[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / DataflowEnvironmentTest.cpp
blob751e86770d5e6dc8511ed0a1425167b5ce468e09
1 //===- unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
10 #include "TestingSupport.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
15 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
16 #include "clang/Analysis/FlowSensitive/Value.h"
17 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include <memory>
23 namespace {
25 using namespace clang;
26 using namespace dataflow;
27 using ::clang::dataflow::test::getFieldValue;
28 using ::testing::IsNull;
29 using ::testing::NotNull;
31 class EnvironmentTest : public ::testing::Test {
32 protected:
33 EnvironmentTest() : DAContext(std::make_unique<WatchedLiteralsSolver>()) {}
35 DataflowAnalysisContext DAContext;
38 TEST_F(EnvironmentTest, FlowCondition) {
39 Environment Env(DAContext);
40 auto &A = Env.arena();
42 EXPECT_TRUE(Env.proves(A.makeLiteral(true)));
43 EXPECT_TRUE(Env.allows(A.makeLiteral(true)));
44 EXPECT_FALSE(Env.proves(A.makeLiteral(false)));
45 EXPECT_FALSE(Env.allows(A.makeLiteral(false)));
47 auto &X = A.makeAtomRef(A.makeAtom());
48 EXPECT_FALSE(Env.proves(X));
49 EXPECT_TRUE(Env.allows(X));
51 Env.assume(X);
52 EXPECT_TRUE(Env.proves(X));
53 EXPECT_TRUE(Env.allows(X));
55 auto &NotX = A.makeNot(X);
56 EXPECT_FALSE(Env.proves(NotX));
57 EXPECT_FALSE(Env.allows(NotX));
60 TEST_F(EnvironmentTest, CreateValueRecursiveType) {
61 using namespace ast_matchers;
63 std::string Code = R"cc(
64 struct Recursive {
65 bool X;
66 Recursive *R;
68 // Use both fields to force them to be created with `createValue`.
69 void Usage(Recursive R) { (void)R.X; (void)R.R; }
70 )cc";
72 auto Unit =
73 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
74 auto &Context = Unit->getASTContext();
76 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
78 auto Results =
79 match(qualType(hasDeclaration(recordDecl(
80 hasName("Recursive"),
81 has(fieldDecl(hasName("R")).bind("field-r")))))
82 .bind("target"),
83 Context);
84 const QualType *TyPtr = selectFirst<QualType>("target", Results);
85 ASSERT_THAT(TyPtr, NotNull());
86 QualType Ty = *TyPtr;
87 ASSERT_FALSE(Ty.isNull());
89 const FieldDecl *R = selectFirst<FieldDecl>("field-r", Results);
90 ASSERT_THAT(R, NotNull());
92 Results = match(functionDecl(hasName("Usage")).bind("fun"), Context);
93 const auto *Fun = selectFirst<FunctionDecl>("fun", Results);
94 ASSERT_THAT(Fun, NotNull());
96 // Verify that the struct and the field (`R`) with first appearance of the
97 // type is created successfully.
98 Environment Env(DAContext, *Fun);
99 auto &SLoc = cast<RecordStorageLocation>(Env.createObject(Ty));
100 PointerValue *PV = cast_or_null<PointerValue>(getFieldValue(&SLoc, *R, Env));
101 EXPECT_THAT(PV, NotNull());
104 TEST_F(EnvironmentTest, JoinRecords) {
105 using namespace ast_matchers;
107 std::string Code = R"cc(
108 struct S {};
109 // Need to use the type somewhere so that the `QualType` gets created;
110 S s;
111 )cc";
113 auto Unit =
114 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
115 auto &Context = Unit->getASTContext();
117 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
119 auto Results =
120 match(qualType(hasDeclaration(recordDecl(hasName("S")))).bind("SType"),
121 Context);
122 const QualType *TyPtr = selectFirst<QualType>("SType", Results);
123 ASSERT_THAT(TyPtr, NotNull());
124 QualType Ty = *TyPtr;
125 ASSERT_FALSE(Ty.isNull());
127 auto *ConstructExpr = CXXConstructExpr::CreateEmpty(Context, 0);
128 ConstructExpr->setType(Ty);
129 ConstructExpr->setValueKind(VK_PRValue);
131 // Two different `RecordValue`s with the same location are joined into a
132 // third `RecordValue` with that same location.
134 Environment Env1(DAContext);
135 auto &Val1 = *cast<RecordValue>(Env1.createValue(Ty));
136 RecordStorageLocation &Loc = Val1.getLoc();
137 Env1.setValue(*ConstructExpr, Val1);
139 Environment Env2(DAContext);
140 auto &Val2 = Env2.create<RecordValue>(Loc);
141 Env2.setValue(Loc, Val2);
142 Env2.setValue(*ConstructExpr, Val2);
144 Environment::ValueModel Model;
145 Environment EnvJoined = Environment::join(Env1, Env2, Model);
146 auto *JoinedVal = cast<RecordValue>(EnvJoined.getValue(*ConstructExpr));
147 EXPECT_NE(JoinedVal, &Val1);
148 EXPECT_NE(JoinedVal, &Val2);
149 EXPECT_EQ(&JoinedVal->getLoc(), &Loc);
152 // Two different `RecordValue`s with different locations are joined into a
153 // third `RecordValue` with a location different from the other two.
155 Environment Env1(DAContext);
156 auto &Val1 = *cast<RecordValue>(Env1.createValue(Ty));
157 Env1.setValue(*ConstructExpr, Val1);
159 Environment Env2(DAContext);
160 auto &Val2 = *cast<RecordValue>(Env2.createValue(Ty));
161 Env2.setValue(*ConstructExpr, Val2);
163 Environment::ValueModel Model;
164 Environment EnvJoined = Environment::join(Env1, Env2, Model);
165 auto *JoinedVal = cast<RecordValue>(EnvJoined.getValue(*ConstructExpr));
166 EXPECT_NE(JoinedVal, &Val1);
167 EXPECT_NE(JoinedVal, &Val2);
168 EXPECT_NE(&JoinedVal->getLoc(), &Val1.getLoc());
169 EXPECT_NE(&JoinedVal->getLoc(), &Val2.getLoc());
173 TEST_F(EnvironmentTest, InitGlobalVarsFun) {
174 using namespace ast_matchers;
176 std::string Code = R"cc(
177 int Global = 0;
178 int Target () { return Global; }
179 )cc";
181 auto Unit =
182 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
183 auto &Context = Unit->getASTContext();
185 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
187 auto Results =
188 match(decl(anyOf(varDecl(hasName("Global")).bind("global"),
189 functionDecl(hasName("Target")).bind("target"))),
190 Context);
191 const auto *Fun = selectFirst<FunctionDecl>("target", Results);
192 const auto *Var = selectFirst<VarDecl>("global", Results);
193 ASSERT_THAT(Fun, NotNull());
194 ASSERT_THAT(Var, NotNull());
196 // Verify the global variable is populated when we analyze `Target`.
197 Environment Env(DAContext, *Fun);
198 EXPECT_THAT(Env.getValue(*Var), NotNull());
201 // Tests that fields mentioned only in default member initializers are included
202 // in the set of tracked fields.
203 TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) {
204 using namespace ast_matchers;
206 std::string Code = R"cc(
207 struct S {
208 S() {}
209 int X = 3;
210 int Y = X;
212 S foo();
213 )cc";
215 auto Unit =
216 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
217 auto &Context = Unit->getASTContext();
219 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
221 auto Results = match(
222 qualType(hasDeclaration(
223 cxxRecordDecl(hasName("S"),
224 hasMethod(cxxConstructorDecl().bind("target")))
225 .bind("struct")))
226 .bind("ty"),
227 Context);
228 const auto *Constructor = selectFirst<FunctionDecl>("target", Results);
229 const auto *Rec = selectFirst<RecordDecl>("struct", Results);
230 const auto QTy = *selectFirst<QualType>("ty", Results);
231 ASSERT_THAT(Constructor, NotNull());
232 ASSERT_THAT(Rec, NotNull());
233 ASSERT_FALSE(QTy.isNull());
235 auto Fields = Rec->fields();
236 FieldDecl *XDecl = nullptr;
237 for (FieldDecl *Field : Fields) {
238 if (Field->getNameAsString() == "X") {
239 XDecl = Field;
240 break;
243 ASSERT_THAT(XDecl, NotNull());
245 // Verify that the `X` field of `S` is populated when analyzing the
246 // constructor, even though it is not referenced directly in the constructor.
247 Environment Env(DAContext, *Constructor);
248 auto &Loc = cast<RecordStorageLocation>(Env.createObject(QTy));
249 EXPECT_THAT(getFieldValue(&Loc, *XDecl, Env), NotNull());
252 TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) {
253 using namespace ast_matchers;
255 std::string Code = R"cc(
256 struct S { int Bar; };
257 S Global = {0};
258 int Target () { return Global.Bar; }
259 )cc";
261 auto Unit =
262 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
263 auto &Context = Unit->getASTContext();
265 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
267 auto Results =
268 match(decl(anyOf(varDecl(hasName("Global")).bind("global"),
269 functionDecl(hasName("Target")).bind("target"))),
270 Context);
271 const auto *Fun = selectFirst<FunctionDecl>("target", Results);
272 const auto *GlobalDecl = selectFirst<VarDecl>("global", Results);
273 ASSERT_THAT(Fun, NotNull());
274 ASSERT_THAT(GlobalDecl, NotNull());
276 ASSERT_TRUE(GlobalDecl->getType()->isStructureType());
277 auto GlobalFields = GlobalDecl->getType()->getAsRecordDecl()->fields();
279 FieldDecl *BarDecl = nullptr;
280 for (FieldDecl *Field : GlobalFields) {
281 if (Field->getNameAsString() == "Bar") {
282 BarDecl = Field;
283 break;
285 FAIL() << "Unexpected field: " << Field->getNameAsString();
287 ASSERT_THAT(BarDecl, NotNull());
289 // Verify the global variable is populated when we analyze `Target`.
290 Environment Env(DAContext, *Fun);
291 const auto *GlobalLoc =
292 cast<RecordStorageLocation>(Env.getStorageLocation(*GlobalDecl));
293 auto *BarVal = getFieldValue(GlobalLoc, *BarDecl, Env);
294 EXPECT_TRUE(isa<IntegerValue>(BarVal));
297 TEST_F(EnvironmentTest, InitGlobalVarsConstructor) {
298 using namespace ast_matchers;
300 std::string Code = R"cc(
301 int Global = 0;
302 struct Target {
303 Target() : Field(Global) {}
304 int Field;
306 )cc";
308 auto Unit =
309 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
310 auto &Context = Unit->getASTContext();
312 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
314 auto Results =
315 match(decl(anyOf(
316 varDecl(hasName("Global")).bind("global"),
317 cxxConstructorDecl(ofClass(hasName("Target"))).bind("target"))),
318 Context);
319 const auto *Ctor = selectFirst<CXXConstructorDecl>("target", Results);
320 const auto *Var = selectFirst<VarDecl>("global", Results);
321 ASSERT_TRUE(Ctor != nullptr);
322 ASSERT_THAT(Var, NotNull());
324 // Verify the global variable is populated when we analyze `Target`.
325 Environment Env(DAContext, *Ctor);
326 EXPECT_THAT(Env.getValue(*Var), NotNull());
329 TEST_F(EnvironmentTest, RefreshRecordValue) {
330 using namespace ast_matchers;
332 std::string Code = R"cc(
333 struct S {};
334 void target () {
335 S s;
338 )cc";
340 auto Unit =
341 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
342 auto &Context = Unit->getASTContext();
344 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
346 auto Results = match(functionDecl(hasName("target")).bind("target"), Context);
347 const auto *Target = selectFirst<FunctionDecl>("target", Results);
348 ASSERT_THAT(Target, NotNull());
350 Results = match(declRefExpr(to(varDecl(hasName("s")))).bind("s"), Context);
351 const auto *DRE = selectFirst<DeclRefExpr>("s", Results);
352 ASSERT_THAT(DRE, NotNull());
354 Environment Env(DAContext, *Target);
355 EXPECT_THAT(Env.getStorageLocation(*DRE), IsNull());
356 refreshRecordValue(*DRE, Env);
357 EXPECT_THAT(Env.getStorageLocation(*DRE), NotNull());
360 } // namespace