Sam McCall | edd7d33 | 2023-04-17 04:47:58 -0700 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | |
Googler | 7f19b2b | 2023-05-01 09:44:57 -0700 | [diff] [blame] | 5 | #include "nullability/pointer_nullability.h" |
Sam McCall | edd7d33 | 2023-04-17 04:47:58 -0700 | [diff] [blame] | 6 | |
Dmitri Gribenko | 61645e1 | 2023-07-17 04:46:21 -0700 | [diff] [blame] | 7 | #include <memory> |
| 8 | |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 9 | #include "nullability/type_nullability.h" |
Dmitri Gribenko | 61645e1 | 2023-07-17 04:46:21 -0700 | [diff] [blame] | 10 | #include "clang/AST/Type.h" |
| 11 | #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" |
| 12 | #include "clang/Analysis/FlowSensitive/Formula.h" |
| 13 | #include "clang/Analysis/FlowSensitive/Value.h" |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 14 | #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" |
Googler | e1504a6 | 2023-07-18 14:03:23 -0700 | [diff] [blame] | 15 | #include "clang/Basic/Specifiers.h" |
Sam McCall | edd7d33 | 2023-04-17 04:47:58 -0700 | [diff] [blame] | 16 | #include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" |
| 17 | |
| 18 | namespace clang::tidy::nullability { |
| 19 | namespace { |
Sam McCall | edd7d33 | 2023-04-17 04:47:58 -0700 | [diff] [blame] | 20 | |
Googler | e1504a6 | 2023-07-18 14:03:23 -0700 | [diff] [blame] | 21 | class NullabilityPropertiesTest : public ::testing::Test { |
| 22 | protected: |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 23 | dataflow::PointerValue &makePointer(PointerTypeNullability N) { |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 24 | auto &P = Env.create<dataflow::PointerValue>( |
| 25 | DACtx.createStorageLocation(QualType())); |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 26 | initPointerNullState(P, DACtx, N); |
| 27 | return P; |
| 28 | } |
| 29 | |
| 30 | dataflow::PointerValue &makeNullPointer() { |
| 31 | auto &P = Env.create<dataflow::PointerValue>( |
| 32 | DACtx.createStorageLocation(QualType())); |
| 33 | initNullPointer(P, DACtx); |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 34 | return P; |
Googler | e1504a6 | 2023-07-18 14:03:23 -0700 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | dataflow::DataflowAnalysisContext DACtx = dataflow::DataflowAnalysisContext( |
| 38 | std::make_unique<dataflow::WatchedLiteralsSolver>()); |
| 39 | dataflow::Environment Env = dataflow::Environment(DACtx); |
| 40 | }; |
| 41 | |
| 42 | TEST_F(NullabilityPropertiesTest, Test) { |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 43 | auto &A = DACtx.arena(); |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 44 | |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 45 | EXPECT_TRUE(isNullable(makeNullPointer(), Env)); |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 46 | |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 47 | { |
| 48 | auto &NullableButNotNull = makePointer(NullabilityKind::Nullable); |
| 49 | EXPECT_TRUE(isNullable(NullableButNotNull, Env)); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 50 | auto *IsNull = getPointerNullState(NullableButNotNull).IsNull; |
| 51 | ASSERT_NE(IsNull, nullptr); |
Martin Brænne | f5e6f8f | 2023-10-26 23:50:30 -0700 | [diff] [blame] | 52 | Env.assume(A.makeNot(*IsNull)); |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 53 | EXPECT_FALSE(isNullable(NullableButNotNull, Env)); |
| 54 | } |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 55 | |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 56 | { |
| 57 | auto &NullableAndNull = makePointer(NullabilityKind::Nullable); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 58 | auto *IsNull = getPointerNullState(NullableAndNull).IsNull; |
| 59 | ASSERT_NE(IsNull, nullptr); |
Martin Brænne | f5e6f8f | 2023-10-26 23:50:30 -0700 | [diff] [blame] | 60 | Env.assume(*IsNull); |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 61 | EXPECT_TRUE(isNullable(NullableAndNull, Env)); |
| 62 | } |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 63 | |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 64 | { |
| 65 | auto &NonnullAndNotNull = makePointer(NullabilityKind::NonNull); |
| 66 | EXPECT_FALSE(isNullable(NonnullAndNotNull, Env)); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 67 | auto *IsNull = getPointerNullState(NonnullAndNotNull).IsNull; |
| 68 | ASSERT_NE(IsNull, nullptr); |
Martin Brænne | f5e6f8f | 2023-10-26 23:50:30 -0700 | [diff] [blame] | 69 | Env.assume(A.makeNot(*IsNull)); |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 70 | EXPECT_FALSE(isNullable(NonnullAndNotNull, Env)); |
| 71 | } |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 72 | |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 73 | { |
| 74 | // This is a little surprising: if a pointer comes from a non-null source |
| 75 | // but is dynamically discovered to be definitely null, we still don't |
| 76 | // consider it nullable. |
| 77 | auto &NonnullAndNull = makePointer(NullabilityKind::NonNull); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 78 | auto *IsNull = getPointerNullState(NonnullAndNull).IsNull; |
| 79 | ASSERT_NE(IsNull, nullptr); |
Martin Brænne | f5e6f8f | 2023-10-26 23:50:30 -0700 | [diff] [blame] | 80 | Env.assume(*IsNull); |
Martin Brænne | 45c2273 | 2023-10-16 05:36:34 -0700 | [diff] [blame] | 81 | EXPECT_FALSE(isNullable(NonnullAndNull, Env)); |
| 82 | } |
Googler | e1504a6 | 2023-07-18 14:03:23 -0700 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | TEST_F(NullabilityPropertiesTest, IsNullableAdditionalConstraints) { |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 86 | auto &P = makePointer(NullabilityKind::Nullable); |
| 87 | EXPECT_TRUE(isNullable(P, Env)); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 88 | auto *IsNull = getPointerNullState(P).IsNull; |
| 89 | ASSERT_NE(IsNull, nullptr); |
| 90 | auto *NotNull = &DACtx.arena().makeNot(*IsNull); |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 91 | EXPECT_FALSE(isNullable(P, Env, NotNull)); |
Googler | e1504a6 | 2023-07-18 14:03:23 -0700 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | TEST_F(NullabilityPropertiesTest, GetNullabilityAdditionalConstraints) { |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 95 | auto &P = makePointer(NullabilityKind::Nullable); |
| 96 | EXPECT_EQ(getNullability(P, Env), NullabilityKind::Nullable); |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 97 | auto *IsNull = getPointerNullState(P).IsNull; |
| 98 | ASSERT_NE(IsNull, nullptr); |
| 99 | auto *NotNull = &DACtx.arena().makeNot(*IsNull); |
Sam McCall | a868026 | 2023-09-21 05:55:27 -0700 | [diff] [blame] | 100 | EXPECT_EQ(getNullability(P, Env, NotNull), NullabilityKind::NonNull); |
Sam McCall | e37df98 | 2023-05-02 05:46:44 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Martin Brænne | 3e1cd48 | 2023-10-26 06:51:31 -0700 | [diff] [blame] | 103 | TEST_F(NullabilityPropertiesTest, InitNullabilityPropertiesWithTop) { |
| 104 | auto &P = Env.create<dataflow::PointerValue>( |
| 105 | DACtx.createStorageLocation(QualType())); |
| 106 | |
| 107 | initPointerNullState(P, DACtx); |
| 108 | ASSERT_NE(getPointerNullState(P).FromNullable, nullptr); |
| 109 | ASSERT_NE(getPointerNullState(P).IsNull, nullptr); |
| 110 | |
| 111 | forgetFromNullable(P, DACtx); |
| 112 | ASSERT_EQ(getPointerNullState(P).FromNullable, nullptr); |
| 113 | |
| 114 | forgetIsNull(P, DACtx); |
| 115 | ASSERT_EQ(getPointerNullState(P).IsNull, nullptr); |
| 116 | } |
| 117 | |
Sam McCall | edd7d33 | 2023-04-17 04:47:58 -0700 | [diff] [blame] | 118 | } // namespace |
| 119 | } // namespace clang::tidy::nullability |