diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl index 735f11303..4c23144a1 100644 --- a/bazel/llvm.bzl +++ b/bazel/llvm.bzl @@ -53,7 +53,7 @@ def _llvm_loader_repository(repository_ctx): executable = False, ) -LLVM_COMMIT_SHA = "f5dab90875c4435890a19410fcb4bcd8a96357b2" +LLVM_COMMIT_SHA = "125948a058dcd89b7fe377872a5fc1a7f9d34e70" def llvm_loader_repository_dependencies(): # This *declares* the dependency, but it won't actually be *downloaded* unless it's used. diff --git a/nullability/test/BUILD b/nullability/test/BUILD index f36361ed9..dc8153dd9 100644 --- a/nullability/test/BUILD +++ b/nullability/test/BUILD @@ -79,19 +79,31 @@ sh_test( data = [":nullability_test"], ) -cc_test( - name = "arrays", - srcs = ["arrays.cc"], - deps = [ - ":check_diagnostics", - "@llvm-project//third-party/unittest:gtest", - "@llvm-project//third-party/unittest:gtest_main", +cc_embed_data( + name = "test_headers", + srcs = [ + "nullability_annotations.h", + "nullability_test.h", + "check.h", + "check_diagnostics_preamble.h", + "new", + "memory", + "optional", + "type_traits", + "utility", ], + outs = [ + "test_headers.cc", + "test_headers.h", + "test_headers.o", + ], + embedopts = ["--namespace=clang::tidy::nullability"], + visibility = ["//nullability:__subpackages__"], ) cc_test( - name = "aliases", - srcs = ["aliases.cc"], + name = "arrays", + srcs = ["arrays.cc"], deps = [ ":check_diagnostics", "@llvm-project//third-party/unittest:gtest", @@ -142,6 +154,16 @@ nullability_test( srcs = ["comparisons.cc"], ) +cc_test( + name = "consistent_annotations", + srcs = ["consistent_annotations.cc"], + deps = [ + ":check_diagnostics", + "@llvm-project//third-party/unittest:gtest", + "@llvm-project//third-party/unittest:gtest_main", + ], +) + cc_test( name = "constructors", srcs = ["constructors.cc"], @@ -253,16 +275,6 @@ nullability_test( srcs = ["initialization.cc"], ) -cc_test( - name = "initialization_diagnosis", - srcs = ["initialization_diagnosis.cc"], - deps = [ - ":check_diagnostics", - "@llvm-project//third-party/unittest:gtest", - "@llvm-project//third-party/unittest:gtest_main", - ], -) - nullability_test( name = "join", srcs = ["join.cc"], @@ -279,6 +291,16 @@ cc_test( ], ) +cc_test( + name = "nested", + srcs = ["nested.cc"], + deps = [ + ":check_diagnostics", + "@llvm-project//clang:basic", + "@llvm-project//third-party/unittest:gtest", + ], +) + cc_test( name = "operator_new", srcs = ["operator_new.cc"], @@ -324,6 +346,26 @@ cc_test( ], ) +nullability_test( + name = "pragma", + srcs = [ + "pragma.cc", + "pragma_none.h", + "pragma_nonnull.h", + "pragma_support.h", + ], +) + +cc_test( + name = "pragma_diagnosis", + srcs = ["pragma_diagnosis.cc"], + deps = [ + ":check_diagnostics", + "@llvm-project//third-party/unittest:gtest", + "@llvm-project//third-party/unittest:gtest_main", + ], +) + nullability_test( name = "resugaring", srcs = ["resugaring.cc"], @@ -354,6 +396,16 @@ cc_test( ], ) +cc_test( + name = "struct_initialization", + srcs = ["struct_initialization.cc"], + deps = [ + ":check_diagnostics", + "@llvm-project//third-party/unittest:gtest", + "@llvm-project//third-party/unittest:gtest_main", + ], +) + nullability_test( name = "symbolic_nullability", srcs = ["symbolic_nullability.cc"], @@ -389,14 +441,9 @@ cc_test( ], ) -nullability_test( - name = "types", - srcs = ["types.cc"], -) - cc_test( - name = "variance", - srcs = ["variance.cc"], + name = "type_aliases", + srcs = ["type_aliases.cc"], deps = [ ":check_diagnostics", "@llvm-project//third-party/unittest:gtest", @@ -405,18 +452,13 @@ cc_test( ) nullability_test( - name = "pragma", - srcs = [ - "pragma.cc", - "pragma_none.h", - "pragma_nonnull.h", - "pragma_support.h", - ], + name = "types", + srcs = ["types.cc"], ) cc_test( - name = "pragma_diagnosis", - srcs = ["pragma_diagnosis.cc"], + name = "variable_aliasing", + srcs = ["variable_aliasing.cc"], deps = [ ":check_diagnostics", "@llvm-project//third-party/unittest:gtest", @@ -424,44 +466,12 @@ cc_test( ], ) -cc_embed_data( - name = "test_headers", - srcs = [ - "nullability_annotations.h", - "nullability_test.h", - "check.h", - "check_diagnostics_preamble.h", - "new", - "memory", - "optional", - "type_traits", - "utility", - ], - outs = [ - "test_headers.cc", - "test_headers.h", - "test_headers.o", - ], - embedopts = ["--namespace=clang::tidy::nullability"], - visibility = ["//nullability:__subpackages__"], -) - cc_test( - name = "consistent_annotations", - srcs = ["consistent_annotations.cc"], + name = "variance", + srcs = ["variance.cc"], deps = [ ":check_diagnostics", "@llvm-project//third-party/unittest:gtest", "@llvm-project//third-party/unittest:gtest_main", ], ) - -cc_test( - name = "nested", - srcs = ["nested.cc"], - deps = [ - ":check_diagnostics", - "@llvm-project//clang:basic", - "@llvm-project//third-party/unittest:gtest", - ], -) diff --git a/nullability/test/initialization_diagnosis.cc b/nullability/test/initialization_diagnosis.cc deleted file mode 100644 index 2a5e9ad81..000000000 --- a/nullability/test/initialization_diagnosis.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Part of the Crubit project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// Tests that check nullability is transferred correctly across initializers. - -#include "nullability/test/check_diagnostics.h" -#include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" - -namespace clang::tidy::nullability { -namespace { - -TEST(PointerNullabilityTest, TransitiveNullCheck) { - EXPECT_TRUE(checkDiagnostics(R"cc( - void target(int *_Nullable x) { - int *y = x; - *x; // [[unsafe]] - if (y) { - *x; - } else { - *x; // [[unsafe]] - } - *x; // [[unsafe]] - } - )cc")); - - EXPECT_TRUE(checkDiagnostics(R"cc( - void target(int *_Nullable x) { - int *y = x; - *y; // [[unsafe]] - if (x) { - *y; - } else { - *y; // [[unsafe]] - } - *y; // [[unsafe]] - } - )cc")); -} - -TEST(PointerNullabilityTest, InitializerList) { - EXPECT_TRUE(checkDiagnostics(R"cc( - struct S { - int* _Nonnull p; - }; - - void target() { - S{nullptr}; // [[unsafe]] - S{.p = nullptr}; // [[unsafe]] - - S{new int}; - S{.p = new int}; - } - )cc")); -} - -TEST(PointerNullabilityTest, InitializerListFewerInitsThanMembersValueInit) { - EXPECT_TRUE(checkDiagnostics(R"cc( - struct S { - int* _Nullable NullableMember; - int* _Nonnull NonnullMember; - }; - - void target() { - S s1{nullptr, new int}; - S s2{nullptr}; // [[unsafe]] - S s3{}; // [[unsafe]] - - S s4{.NonnullMember = new int, .NullableMember = nullptr}; - S s5{.NullableMember = nullptr}; // [[unsafe]] - } - )cc")); -} - -TEST(PointerNullabilityTest, InitListWithDefaultInit) { - EXPECT_TRUE(checkDiagnostics(R"cc( - struct S { - int X = 1; - int* _Nonnull NonnullMemberWithNull = nullptr; - int* _Nonnull NonnullMemberWithNonnull = &X; - }; - - void target() { - S{2, new int, new int}; - // test when we have fewer initializers than members - S{2, new int}; - S{2}; // [[unsafe]] - S{}; // [[unsafe]] - - // test when we override the default - S{2, new int, nullptr}; // [[unsafe]] - S{.NonnullMemberWithNull = new int}; - S{.NonnullMemberWithNull = new int, - .NonnullMemberWithNonnull = nullptr}; // [[unsafe]] - } - )cc")); -} - -TEST(PointerNullabilityTest, SmartPointerInitializerList) { - EXPECT_TRUE(checkDiagnostics(R"cc( -#include - struct S { - _Nonnull std::unique_ptr NonnullMember; - _Nullable std::unique_ptr NullableMember; - std::unique_ptr UnannotatedMember; - }; - - void target() { - S{nullptr, // [[unsafe]] - nullptr, nullptr}; - S{.NonnullMember = nullptr, // [[unsafe]] - .NullableMember = nullptr, - .UnannotatedMember = nullptr}; - - // test when we have fewer initializers than members - S{new int}; - S{}; // [[unsafe]] - } - )cc")); -} - -} // namespace -} // namespace clang::tidy::nullability diff --git a/nullability/test/struct_initialization.cc b/nullability/test/struct_initialization.cc new file mode 100644 index 000000000..521103992 --- /dev/null +++ b/nullability/test/struct_initialization.cc @@ -0,0 +1,236 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Tests that check nullability is transferred correctly across initializers. + +#include "nullability/test/check_diagnostics.h" +#include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" + +namespace clang::tidy::nullability { +namespace { + +TEST(PointerNullabilityTest, InitializerListExpressions) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nonnull p; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S{}; // [[unsafe]] + S{nullptr}; // [[unsafe]] + S{q}; // [[unsafe]] + S{new int}; + S{&x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, DesignatedInitializerListExpressions) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nonnull p; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S{.p = nullptr}; // [[unsafe]] + S{.p = q}; // [[unsafe]] + S{.p = new int}; + S{.p = &x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, InitializerListDeclarations) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nonnull p; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S s1{}; // [[unsafe]] + S s2{nullptr}; // [[unsafe]] + S s3{q}; // [[unsafe]] + S s4{new int}; + S s5{&x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, DesignatedInitializerListDeclarations) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nonnull p; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S s1{.p = nullptr}; // [[unsafe]] + S s2{.p = q}; // [[unsafe]] + S s3{.p = new int}; + S s4{.p = &x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, InitializerListDeclarationsWithAssignmentSyntax) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nonnull p; + }; + + void target() { + S s1 = {}; // [[unsafe]] + S s2 = {nullptr}; // [[unsafe]] + S s3 = {.p = nullptr}; // [[unsafe]] + + int* _Nullable q = nullptr; + S s4 = {q}; // [[unsafe]] + S s5 = {.p = q}; // [[unsafe]] + + S s6 = {new int}; + S s7 = {.p = new int}; + + int x = 1; + S s8 = {&x}; + S s9 = {.p = &x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, InitializerListDeclarationsWithTwoMembers) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nullable NullableMember; + int* _Nonnull NonnullMember; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S s1{}; // [[unsafe]] + S s2{nullptr}; // [[unsafe]] + S s3{new int}; // [[unsafe]] + S s4{nullptr, nullptr}; // [[unsafe]] + S s5{new int, nullptr}; // [[unsafe]] + S s6{nullptr, q}; // [[unsafe]] + S s7{nullptr, new int}; + S s8{nullptr, &x}; + } + )cc")); +} + +TEST(PointerNullabilityTest, + DesignatedInitializerListDeclarationsWithTwoMembers) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nullable NullableMember; + int* _Nonnull NonnullMember; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S s1{.NullableMember = nullptr}; // [[unsafe]] + S s2{.NullableMember = new int}; // [[unsafe]] + + S s3{.NonnullMember = nullptr}; // [[unsafe]] + S s4{.NonnullMember = q}; // [[unsafe]] + S s5{.NonnullMember = new int}; + S s6{.NonnullMember = &x}; + + S s7{.NullableMember = nullptr, .NonnullMember = nullptr}; // [[unsafe]] + S s8{.NullableMember = new int, .NonnullMember = nullptr}; // [[unsafe]] + S s9{.NullableMember = nullptr, .NonnullMember = q}; // [[unsafe]] + S s10{.NullableMember = nullptr, .NonnullMember = new int}; + S s11{.NullableMember = nullptr, .NonnullMember = &x}; + } + )cc")); +} + +// Designated initializers with members out of order are not allowed by default, +// but test them in case the warning is disabled. +// https://clang.llvm.org/docs/DiagnosticsReference.html#wreorder-init-list +TEST(PointerNullabilityTest, + DesignatedInitializerListDeclarationsWithTwoMembersOutOfOrder) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int* _Nullable NullableMember; + int* _Nonnull NonnullMember; + }; + + void target() { + int* _Nullable q = nullptr; + int x = 1; + + S s1{.NonnullMember = nullptr, .NullableMember = nullptr}; // [[unsafe]] + S s2{.NonnullMember = nullptr, .NullableMember = new int}; // [[unsafe]] + S s3{.NonnullMember = q, .NullableMember = nullptr}; // [[unsafe]] + S s4{.NonnullMember = new int, .NullableMember = nullptr}; + S s5{.NonnullMember = &x, .NullableMember = nullptr}; + } + )cc")); +} + +TEST(PointerNullabilityTest, InitListWithDefaultInit) { + EXPECT_TRUE(checkDiagnostics(R"cc( + struct S { + int X = 1; + int* _Nonnull NonnullMemberWithNull = nullptr; + int* _Nonnull NonnullMemberWithNonnull = &X; + }; + + void target() { + S{2, new int, new int}; + // test when we have fewer initializers than members + S{2, new int}; + S{2}; // [[unsafe]] + S{}; // [[unsafe]] + + // test when we override the default + S{2, new int, nullptr}; // [[unsafe]] + S{.NonnullMemberWithNull = new int}; + S{.NonnullMemberWithNull = new int, + .NonnullMemberWithNonnull = nullptr}; // [[unsafe]] + } + )cc")); +} + +TEST(PointerNullabilityTest, SmartPointerInitializerList) { + EXPECT_TRUE(checkDiagnostics(R"cc( +#include + struct S { + _Nonnull std::unique_ptr NonnullMember; + _Nullable std::unique_ptr NullableMember; + std::unique_ptr UnannotatedMember; + }; + + void target() { + S{nullptr, // [[unsafe]] + nullptr, nullptr}; + S{.NonnullMember = nullptr, // [[unsafe]] + .NullableMember = nullptr, + .UnannotatedMember = nullptr}; + + // test when we have fewer initializers than members + S{new int}; + S{}; // [[unsafe]] + } + )cc")); +} + +} // namespace +} // namespace clang::tidy::nullability diff --git a/nullability/test/aliases.cc b/nullability/test/type_aliases.cc similarity index 100% rename from nullability/test/aliases.cc rename to nullability/test/type_aliases.cc diff --git a/nullability/test/variable_aliasing.cc b/nullability/test/variable_aliasing.cc new file mode 100644 index 000000000..4696b5fa2 --- /dev/null +++ b/nullability/test/variable_aliasing.cc @@ -0,0 +1,44 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Tests for nullability with variable aliasing. + +#include "nullability/test/check_diagnostics.h" +#include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" + +namespace clang::tidy::nullability { +namespace { + +TEST(PointerNullabilityTest, NullCheckAliasDereferenceOriginal) { + EXPECT_TRUE(checkDiagnostics(R"cc( + void target(int* _Nullable x) { + int* y = x; + *x; // [[unsafe]] + if (y) { + *x; + } else { + *x; // [[unsafe]] + } + *x; // [[unsafe]] + } + )cc")); +} + +TEST(PointerNullabilityTest, NullCheckOriginalDereferenceAlias) { + EXPECT_TRUE(checkDiagnostics(R"cc( + void target(int* _Nullable x) { + int* y = x; + *y; // [[unsafe]] + if (x) { + *y; + } else { + *y; // [[unsafe]] + } + *y; // [[unsafe]] + } + )cc")); +} + +} // namespace +} // namespace clang::tidy::nullability