| // 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 pointers-to-pointers. |
| |
| #include "nullability/test/check_diagnostics.h" |
| #include "clang/Basic/LLVM.h" |
| #include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" |
| |
| namespace clang::tidy::nullability { |
| namespace { |
| |
| TEST(PointerNullabilityTest, DoubleDereference) { |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **p) { |
| *p; |
| **p; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nonnull p) { |
| *p; |
| **p; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *p) { |
| *p; |
| **p; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nonnull p) { |
| *p; |
| **p; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nullable p) { |
| *p; // [[unsafe]] |
| **p; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *p) { |
| *p; |
| **p; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nullable p) { |
| *p; // [[unsafe]] |
| **p; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nonnull p) { |
| *p; |
| **p; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nullable p) { |
| *p; // [[unsafe]] |
| **p; // [[unsafe]] |
| } |
| )cc")); |
| } |
| |
| TEST(PointerNullabilityTest, AssignmentsFromNullptr) { |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **p) { |
| *p = nullptr; |
| p = nullptr; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nonnull p) { |
| *p = nullptr; |
| p = nullptr; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *p) { |
| *p = nullptr; // [[unsafe]] |
| p = nullptr; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nonnull p) { |
| *p = nullptr; // [[unsafe]] |
| p = nullptr; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nullable p) { |
| if (p) { |
| *p = nullptr; |
| } |
| p = nullptr; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *p) { |
| *p = nullptr; |
| p = nullptr; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nullable p) { |
| if (p) { |
| *p = nullptr; |
| } |
| p = nullptr; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nonnull p) { |
| *p = nullptr; |
| p = nullptr; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nullable p) { |
| if (p) { |
| *p = nullptr; // [[unsafe]] |
| } |
| p = nullptr; |
| } |
| )cc")); |
| } |
| |
| TEST(PointerNullabilityTest, AssignmentFromMutableVariables) { |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **p, int *_Nonnull nonnull, int *_Nullable nullable, |
| int **unknown_unknown, int **_Nonnull unknown_nonnull, |
| int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; |
| *p = nullable; |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; |
| p = nullable_unknown; |
| p = nullable_nullable; |
| p = nullable_nonnull; |
| p = nonnull_nullable; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nonnull p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; |
| *p = nullable; |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; // [[unsafe]] |
| p = nullable_unknown; |
| p = nullable_nullable; // [[unsafe]] |
| p = nullable_nonnull; |
| p = nonnull_nullable; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; |
| *p = nullable; // [[unsafe]] |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; |
| p = nullable_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nullable_nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nullable_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nullable; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nonnull p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; |
| *p = nullable; // [[unsafe]] |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; // [[unsafe]] |
| p = nullable_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nullable_nullable; // [[unsafe]] |
| p = nullable_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nullable; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int **_Nullable p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| if (p) { |
| *p = nonnull; |
| *p = nullable; |
| } |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; |
| p = nullable_unknown; |
| p = nullable_nullable; |
| p = nullable_nonnull; |
| p = nonnull_nullable; |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| *p = nullable; |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = unknown_nullable; |
| p = nullable_unknown; |
| p = nullable_nullable; |
| p = nullable_nonnull; |
| p = nonnull_nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nullable p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| if (p) { |
| *p = nonnull; |
| *p = nullable; |
| } |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = unknown_nullable; |
| p = nullable_unknown; |
| p = nullable_nullable; |
| p = nullable_nonnull; |
| p = nonnull_nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable *_Nonnull p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| *p = nonnull; |
| *p = nullable; |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = unknown_nullable; // [[unsafe]] |
| p = nullable_unknown; |
| p = nullable_nullable; // [[unsafe]] |
| p = nullable_nonnull; |
| p = nonnull_nullable; // [[unsafe]] |
| } |
| )cc")); |
| |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nonnull *_Nullable p, int *_Nonnull nonnull, |
| int *_Nullable nullable, int **unknown_unknown, |
| int **_Nonnull unknown_nonnull, int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| if (p) { |
| *p = nonnull; |
| *p = nullable; // [[unsafe]] |
| } |
| p = unknown_unknown; |
| p = unknown_nonnull; |
| p = nonnull_unknown; |
| p = nonnull_nonnull; |
| p = unknown_nullable; |
| p = nullable_unknown; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nullable_nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nullable_nonnull; // TODO: b/343960612 - FALSE NEGATIVE |
| p = nonnull_nullable; |
| } |
| )cc")); |
| } |
| |
| TEST(PointerNullabilityTest, AssignmentFromVariablesInnerConst) { |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target(int *_Nullable const *_Nullable inner_const_nullable, |
| int *_Nonnull const *_Nullable inner_const_nonnull, |
| int *_Nonnull nonnull, int *_Nullable nullable, |
| int **unknown_unknown, int **_Nonnull unknown_nonnull, |
| int *_Nonnull *nonnull_unknown, |
| int *_Nonnull *_Nonnull nonnull_nonnull, |
| int **_Nullable unknown_nullable, |
| int *_Nullable *nullable_unknown, |
| int *_Nullable *_Nullable nullable_nullable, |
| int *_Nullable *_Nonnull nullable_nonnull, |
| int *_Nonnull *_Nullable nonnull_nullable) { |
| inner_const_nullable = unknown_unknown; |
| inner_const_nullable = unknown_nonnull; |
| inner_const_nullable = nonnull_unknown; |
| inner_const_nullable = nonnull_nonnull; |
| inner_const_nullable = unknown_nullable; |
| inner_const_nullable = nullable_unknown; |
| inner_const_nullable = nullable_nullable; |
| inner_const_nullable = nullable_nonnull; |
| inner_const_nullable = nonnull_nullable; |
| inner_const_nonnull = unknown_unknown; |
| inner_const_nonnull = unknown_nonnull; |
| inner_const_nonnull = nonnull_unknown; |
| inner_const_nonnull = nonnull_nonnull; |
| inner_const_nonnull = unknown_nullable; |
| inner_const_nonnull = nullable_unknown; // TODO: b/343960612 - FALSE |
| // NEGATIVE |
| inner_const_nonnull = |
| nullable_nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| inner_const_nonnull = nullable_nonnull; // TODO: b/343960612 - FALSE |
| // NEGATIVE |
| inner_const_nonnull = nonnull_nullable; |
| } |
| )cc")); |
| } |
| |
| TEST(PointerNullabilityTest, Initialization) { |
| EXPECT_TRUE(checkDiagnostics(R"cc( |
| void target() { |
| int **_Nonnull a = nullptr; // [[unsafe]] |
| int **_Nullable b = nullptr; |
| |
| int integer; |
| int *_Nonnull nonnull = &integer; |
| int *_Nullable nullable = &integer; |
| |
| int **_Nonnull c = &nonnull; |
| int **_Nullable d = &nonnull; |
| |
| int **_Nonnull e = &nullable; |
| int **_Nullable f = &nullable; |
| |
| int *_Nonnull *g = &nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| int *_Nullable *h = &nullable; |
| nullable = nullptr; |
| int *_Nonnull *i = &nullable; // TODO: b/343960612 - FALSE NEGATIVE |
| int *_Nullable *j = &nullable; |
| } |
| )cc")); |
| } |
| } // namespace |
| } // namespace clang::tidy::nullability |