blob: ffe1f22db55d347f4d16798631c491f2b157f5ae [file] [log] [blame]
Sam McCalledd7d332023-04-17 04:47:58 -07001// 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
Googler7f19b2b2023-05-01 09:44:57 -07005#include "nullability/pointer_nullability.h"
Sam McCalledd7d332023-04-17 04:47:58 -07006
Dmitri Gribenko61645e12023-07-17 04:46:21 -07007#include <memory>
8
Sam McCalla8680262023-09-21 05:55:27 -07009#include "nullability/type_nullability.h"
Dmitri Gribenko61645e12023-07-17 04:46:21 -070010#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 McCalle37df982023-05-02 05:46:44 -070014#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
Googlere1504a62023-07-18 14:03:23 -070015#include "clang/Basic/Specifiers.h"
Sam McCalledd7d332023-04-17 04:47:58 -070016#include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h"
17
18namespace clang::tidy::nullability {
19namespace {
Sam McCalledd7d332023-04-17 04:47:58 -070020
Googlere1504a62023-07-18 14:03:23 -070021class NullabilityPropertiesTest : public ::testing::Test {
22 protected:
Sam McCalla8680262023-09-21 05:55:27 -070023 dataflow::PointerValue &makePointer(PointerTypeNullability N) {
Sam McCalle37df982023-05-02 05:46:44 -070024 auto &P = Env.create<dataflow::PointerValue>(
25 DACtx.createStorageLocation(QualType()));
Sam McCalla8680262023-09-21 05:55:27 -070026 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 McCalle37df982023-05-02 05:46:44 -070034 return P;
Googlere1504a62023-07-18 14:03:23 -070035 }
36
37 dataflow::DataflowAnalysisContext DACtx = dataflow::DataflowAnalysisContext(
38 std::make_unique<dataflow::WatchedLiteralsSolver>());
39 dataflow::Environment Env = dataflow::Environment(DACtx);
40};
41
42TEST_F(NullabilityPropertiesTest, Test) {
Sam McCalla8680262023-09-21 05:55:27 -070043 auto &A = DACtx.arena();
Sam McCalle37df982023-05-02 05:46:44 -070044
Sam McCalla8680262023-09-21 05:55:27 -070045 EXPECT_TRUE(isNullable(makeNullPointer(), Env));
Sam McCalle37df982023-05-02 05:46:44 -070046
Martin Brænne45c22732023-10-16 05:36:34 -070047 {
48 auto &NullableButNotNull = makePointer(NullabilityKind::Nullable);
49 EXPECT_TRUE(isNullable(NullableButNotNull, Env));
Martin Brænne3e1cd482023-10-26 06:51:31 -070050 auto *IsNull = getPointerNullState(NullableButNotNull).IsNull;
51 ASSERT_NE(IsNull, nullptr);
Martin Brænnef5e6f8f2023-10-26 23:50:30 -070052 Env.assume(A.makeNot(*IsNull));
Martin Brænne45c22732023-10-16 05:36:34 -070053 EXPECT_FALSE(isNullable(NullableButNotNull, Env));
54 }
Sam McCalla8680262023-09-21 05:55:27 -070055
Martin Brænne45c22732023-10-16 05:36:34 -070056 {
57 auto &NullableAndNull = makePointer(NullabilityKind::Nullable);
Martin Brænne3e1cd482023-10-26 06:51:31 -070058 auto *IsNull = getPointerNullState(NullableAndNull).IsNull;
59 ASSERT_NE(IsNull, nullptr);
Martin Brænnef5e6f8f2023-10-26 23:50:30 -070060 Env.assume(*IsNull);
Martin Brænne45c22732023-10-16 05:36:34 -070061 EXPECT_TRUE(isNullable(NullableAndNull, Env));
62 }
Sam McCalla8680262023-09-21 05:55:27 -070063
Martin Brænne45c22732023-10-16 05:36:34 -070064 {
65 auto &NonnullAndNotNull = makePointer(NullabilityKind::NonNull);
66 EXPECT_FALSE(isNullable(NonnullAndNotNull, Env));
Martin Brænne3e1cd482023-10-26 06:51:31 -070067 auto *IsNull = getPointerNullState(NonnullAndNotNull).IsNull;
68 ASSERT_NE(IsNull, nullptr);
Martin Brænnef5e6f8f2023-10-26 23:50:30 -070069 Env.assume(A.makeNot(*IsNull));
Martin Brænne45c22732023-10-16 05:36:34 -070070 EXPECT_FALSE(isNullable(NonnullAndNotNull, Env));
71 }
Sam McCalla8680262023-09-21 05:55:27 -070072
Martin Brænne45c22732023-10-16 05:36:34 -070073 {
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ænne3e1cd482023-10-26 06:51:31 -070078 auto *IsNull = getPointerNullState(NonnullAndNull).IsNull;
79 ASSERT_NE(IsNull, nullptr);
Martin Brænnef5e6f8f2023-10-26 23:50:30 -070080 Env.assume(*IsNull);
Martin Brænne45c22732023-10-16 05:36:34 -070081 EXPECT_FALSE(isNullable(NonnullAndNull, Env));
82 }
Googlere1504a62023-07-18 14:03:23 -070083}
84
85TEST_F(NullabilityPropertiesTest, IsNullableAdditionalConstraints) {
Sam McCalla8680262023-09-21 05:55:27 -070086 auto &P = makePointer(NullabilityKind::Nullable);
87 EXPECT_TRUE(isNullable(P, Env));
Martin Brænne3e1cd482023-10-26 06:51:31 -070088 auto *IsNull = getPointerNullState(P).IsNull;
89 ASSERT_NE(IsNull, nullptr);
90 auto *NotNull = &DACtx.arena().makeNot(*IsNull);
Sam McCalla8680262023-09-21 05:55:27 -070091 EXPECT_FALSE(isNullable(P, Env, NotNull));
Googlere1504a62023-07-18 14:03:23 -070092}
93
94TEST_F(NullabilityPropertiesTest, GetNullabilityAdditionalConstraints) {
Sam McCalla8680262023-09-21 05:55:27 -070095 auto &P = makePointer(NullabilityKind::Nullable);
96 EXPECT_EQ(getNullability(P, Env), NullabilityKind::Nullable);
Martin Brænne3e1cd482023-10-26 06:51:31 -070097 auto *IsNull = getPointerNullState(P).IsNull;
98 ASSERT_NE(IsNull, nullptr);
99 auto *NotNull = &DACtx.arena().makeNot(*IsNull);
Sam McCalla8680262023-09-21 05:55:27 -0700100 EXPECT_EQ(getNullability(P, Env, NotNull), NullabilityKind::NonNull);
Sam McCalle37df982023-05-02 05:46:44 -0700101}
102
Martin Brænne3e1cd482023-10-26 06:51:31 -0700103TEST_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 McCalledd7d332023-04-17 04:47:58 -0700118} // namespace
119} // namespace clang::tidy::nullability