xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp (revision d1f59544cf31488d84a2daff0020af2f8e366ed8)
1ae60884dSStanislav Gatev //===- unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp -------===//
2ae60884dSStanislav Gatev //
3ae60884dSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ae60884dSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
5ae60884dSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ae60884dSStanislav Gatev //
7ae60884dSStanislav Gatev //===----------------------------------------------------------------------===//
8ae60884dSStanislav Gatev 
9ae60884dSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
102902ea3dSMartin Braenne #include "TestingSupport.h"
11f3700bdbSYitzhak Mandelbaum #include "clang/AST/DeclCXX.h"
1273c98831SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchFinder.h"
13f3700bdbSYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h"
14ae60884dSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
1573c98831SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/StorageLocation.h"
1618c84e2dSYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/Value.h"
17ae60884dSStanislav Gatev #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
1873c98831SYitzhak Mandelbaum #include "clang/Tooling/Tooling.h"
19ae60884dSStanislav Gatev #include "gmock/gmock.h"
20ae60884dSStanislav Gatev #include "gtest/gtest.h"
21ae60884dSStanislav Gatev #include <memory>
22ae60884dSStanislav Gatev 
23ae60884dSStanislav Gatev namespace {
24ae60884dSStanislav Gatev 
25ae60884dSStanislav Gatev using namespace clang;
26ae60884dSStanislav Gatev using namespace dataflow;
272902ea3dSMartin Braenne using ::clang::dataflow::test::getFieldValue;
280f6cf555SMartin Braenne using ::testing::IsNull;
29f3700bdbSYitzhak Mandelbaum using ::testing::NotNull;
30ae60884dSStanislav Gatev 
31ae60884dSStanislav Gatev class EnvironmentTest : public ::testing::Test {
32ae60884dSStanislav Gatev protected:
33f3700bdbSYitzhak Mandelbaum   EnvironmentTest() : DAContext(std::make_unique<WatchedLiteralsSolver>()) {}
34ae60884dSStanislav Gatev 
35f3700bdbSYitzhak Mandelbaum   DataflowAnalysisContext DAContext;
36ae60884dSStanislav Gatev };
37ae60884dSStanislav Gatev 
38ae60884dSStanislav Gatev TEST_F(EnvironmentTest, FlowCondition) {
39f3700bdbSYitzhak Mandelbaum   Environment Env(DAContext);
406272226bSSam McCall   auto &A = Env.arena();
41f3700bdbSYitzhak Mandelbaum 
42*d1f59544Smartinboehme   EXPECT_TRUE(Env.proves(A.makeLiteral(true)));
43*d1f59544Smartinboehme   EXPECT_TRUE(Env.allows(A.makeLiteral(true)));
44*d1f59544Smartinboehme   EXPECT_FALSE(Env.proves(A.makeLiteral(false)));
45*d1f59544Smartinboehme   EXPECT_FALSE(Env.allows(A.makeLiteral(false)));
46ae60884dSStanislav Gatev 
476272226bSSam McCall   auto &X = A.makeAtomRef(A.makeAtom());
48*d1f59544Smartinboehme   EXPECT_FALSE(Env.proves(X));
49*d1f59544Smartinboehme   EXPECT_TRUE(Env.allows(X));
50ae60884dSStanislav Gatev 
51*d1f59544Smartinboehme   Env.assume(X);
52*d1f59544Smartinboehme   EXPECT_TRUE(Env.proves(X));
53*d1f59544Smartinboehme   EXPECT_TRUE(Env.allows(X));
54ae60884dSStanislav Gatev 
556272226bSSam McCall   auto &NotX = A.makeNot(X);
56*d1f59544Smartinboehme   EXPECT_FALSE(Env.proves(NotX));
57*d1f59544Smartinboehme   EXPECT_FALSE(Env.allows(NotX));
58ae60884dSStanislav Gatev }
59ae60884dSStanislav Gatev 
6018c84e2dSYitzhak Mandelbaum TEST_F(EnvironmentTest, CreateValueRecursiveType) {
6118c84e2dSYitzhak Mandelbaum   using namespace ast_matchers;
6218c84e2dSYitzhak Mandelbaum 
6318c84e2dSYitzhak Mandelbaum   std::string Code = R"cc(
6418c84e2dSYitzhak Mandelbaum     struct Recursive {
6518c84e2dSYitzhak Mandelbaum       bool X;
6618c84e2dSYitzhak Mandelbaum       Recursive *R;
6718c84e2dSYitzhak Mandelbaum     };
6801ccf7b3SYitzhak Mandelbaum     // Use both fields to force them to be created with `createValue`.
6901ccf7b3SYitzhak Mandelbaum     void Usage(Recursive R) { (void)R.X; (void)R.R; }
7018c84e2dSYitzhak Mandelbaum   )cc";
7118c84e2dSYitzhak Mandelbaum 
7218c84e2dSYitzhak Mandelbaum   auto Unit =
7318c84e2dSYitzhak Mandelbaum       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
7418c84e2dSYitzhak Mandelbaum   auto &Context = Unit->getASTContext();
7518c84e2dSYitzhak Mandelbaum 
7618c84e2dSYitzhak Mandelbaum   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
7718c84e2dSYitzhak Mandelbaum 
7818c84e2dSYitzhak Mandelbaum   auto Results =
7918c84e2dSYitzhak Mandelbaum       match(qualType(hasDeclaration(recordDecl(
8018c84e2dSYitzhak Mandelbaum                          hasName("Recursive"),
8118c84e2dSYitzhak Mandelbaum                          has(fieldDecl(hasName("R")).bind("field-r")))))
8218c84e2dSYitzhak Mandelbaum                 .bind("target"),
8318c84e2dSYitzhak Mandelbaum             Context);
8401ccf7b3SYitzhak Mandelbaum   const QualType *TyPtr = selectFirst<QualType>("target", Results);
8501ccf7b3SYitzhak Mandelbaum   ASSERT_THAT(TyPtr, NotNull());
8601ccf7b3SYitzhak Mandelbaum   QualType Ty = *TyPtr;
8701ccf7b3SYitzhak Mandelbaum   ASSERT_FALSE(Ty.isNull());
8801ccf7b3SYitzhak Mandelbaum 
8918c84e2dSYitzhak Mandelbaum   const FieldDecl *R = selectFirst<FieldDecl>("field-r", Results);
9001ccf7b3SYitzhak Mandelbaum   ASSERT_THAT(R, NotNull());
9101ccf7b3SYitzhak Mandelbaum 
9201ccf7b3SYitzhak Mandelbaum   Results = match(functionDecl(hasName("Usage")).bind("fun"), Context);
9301ccf7b3SYitzhak Mandelbaum   const auto *Fun = selectFirst<FunctionDecl>("fun", Results);
9401ccf7b3SYitzhak Mandelbaum   ASSERT_THAT(Fun, NotNull());
9518c84e2dSYitzhak Mandelbaum 
9618c84e2dSYitzhak Mandelbaum   // Verify that the struct and the field (`R`) with first appearance of the
9718c84e2dSYitzhak Mandelbaum   // type is created successfully.
9801ccf7b3SYitzhak Mandelbaum   Environment Env(DAContext, *Fun);
997cf20f15Smartinboehme   auto &SLoc = cast<RecordStorageLocation>(Env.createObject(Ty));
1007cf20f15Smartinboehme   PointerValue *PV = cast_or_null<PointerValue>(getFieldValue(&SLoc, *R, Env));
1012902ea3dSMartin Braenne   EXPECT_THAT(PV, NotNull());
10218c84e2dSYitzhak Mandelbaum }
10318c84e2dSYitzhak Mandelbaum 
1047f66cc7dSmartinboehme TEST_F(EnvironmentTest, JoinRecords) {
1057f66cc7dSmartinboehme   using namespace ast_matchers;
1067f66cc7dSmartinboehme 
1077f66cc7dSmartinboehme   std::string Code = R"cc(
1087f66cc7dSmartinboehme     struct S {};
1097f66cc7dSmartinboehme     // Need to use the type somewhere so that the `QualType` gets created;
1107f66cc7dSmartinboehme     S s;
1117f66cc7dSmartinboehme   )cc";
1127f66cc7dSmartinboehme 
1137f66cc7dSmartinboehme   auto Unit =
1147f66cc7dSmartinboehme       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
1157f66cc7dSmartinboehme   auto &Context = Unit->getASTContext();
1167f66cc7dSmartinboehme 
1177f66cc7dSmartinboehme   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
1187f66cc7dSmartinboehme 
1197f66cc7dSmartinboehme   auto Results =
1207f66cc7dSmartinboehme       match(qualType(hasDeclaration(recordDecl(hasName("S")))).bind("SType"),
1217f66cc7dSmartinboehme             Context);
1227f66cc7dSmartinboehme   const QualType *TyPtr = selectFirst<QualType>("SType", Results);
1237f66cc7dSmartinboehme   ASSERT_THAT(TyPtr, NotNull());
1247f66cc7dSmartinboehme   QualType Ty = *TyPtr;
1257f66cc7dSmartinboehme   ASSERT_FALSE(Ty.isNull());
1267f66cc7dSmartinboehme 
1277f66cc7dSmartinboehme   auto *ConstructExpr = CXXConstructExpr::CreateEmpty(Context, 0);
1287f66cc7dSmartinboehme   ConstructExpr->setType(Ty);
1297f66cc7dSmartinboehme   ConstructExpr->setValueKind(VK_PRValue);
1307f66cc7dSmartinboehme 
1317f66cc7dSmartinboehme   // Two different `RecordValue`s with the same location are joined into a
1327f66cc7dSmartinboehme   // third `RecordValue` with that same location.
1337f66cc7dSmartinboehme   {
1347f66cc7dSmartinboehme     Environment Env1(DAContext);
1357f66cc7dSmartinboehme     auto &Val1 = *cast<RecordValue>(Env1.createValue(Ty));
1367f66cc7dSmartinboehme     RecordStorageLocation &Loc = Val1.getLoc();
1377f66cc7dSmartinboehme     Env1.setValue(*ConstructExpr, Val1);
1387f66cc7dSmartinboehme 
1397f66cc7dSmartinboehme     Environment Env2(DAContext);
1407f66cc7dSmartinboehme     auto &Val2 = Env2.create<RecordValue>(Loc);
1417f66cc7dSmartinboehme     Env2.setValue(Loc, Val2);
1427f66cc7dSmartinboehme     Env2.setValue(*ConstructExpr, Val2);
1437f66cc7dSmartinboehme 
1447f66cc7dSmartinboehme     Environment::ValueModel Model;
1457f66cc7dSmartinboehme     Environment EnvJoined = Environment::join(Env1, Env2, Model);
1467f66cc7dSmartinboehme     auto *JoinedVal = cast<RecordValue>(EnvJoined.getValue(*ConstructExpr));
1477f66cc7dSmartinboehme     EXPECT_NE(JoinedVal, &Val1);
1487f66cc7dSmartinboehme     EXPECT_NE(JoinedVal, &Val2);
1497f66cc7dSmartinboehme     EXPECT_EQ(&JoinedVal->getLoc(), &Loc);
1507f66cc7dSmartinboehme   }
1517f66cc7dSmartinboehme 
1527f66cc7dSmartinboehme   // Two different `RecordValue`s with different locations are joined into a
1537f66cc7dSmartinboehme   // third `RecordValue` with a location different from the other two.
1547f66cc7dSmartinboehme   {
1557f66cc7dSmartinboehme     Environment Env1(DAContext);
1567f66cc7dSmartinboehme     auto &Val1 = *cast<RecordValue>(Env1.createValue(Ty));
1577f66cc7dSmartinboehme     Env1.setValue(*ConstructExpr, Val1);
1587f66cc7dSmartinboehme 
1597f66cc7dSmartinboehme     Environment Env2(DAContext);
1607f66cc7dSmartinboehme     auto &Val2 = *cast<RecordValue>(Env2.createValue(Ty));
1617f66cc7dSmartinboehme     Env2.setValue(*ConstructExpr, Val2);
1627f66cc7dSmartinboehme 
1637f66cc7dSmartinboehme     Environment::ValueModel Model;
1647f66cc7dSmartinboehme     Environment EnvJoined = Environment::join(Env1, Env2, Model);
1657f66cc7dSmartinboehme     auto *JoinedVal = cast<RecordValue>(EnvJoined.getValue(*ConstructExpr));
1667f66cc7dSmartinboehme     EXPECT_NE(JoinedVal, &Val1);
1677f66cc7dSmartinboehme     EXPECT_NE(JoinedVal, &Val2);
1687f66cc7dSmartinboehme     EXPECT_NE(&JoinedVal->getLoc(), &Val1.getLoc());
1697f66cc7dSmartinboehme     EXPECT_NE(&JoinedVal->getLoc(), &Val2.getLoc());
1707f66cc7dSmartinboehme   }
1717f66cc7dSmartinboehme }
1727f66cc7dSmartinboehme 
173f3700bdbSYitzhak Mandelbaum TEST_F(EnvironmentTest, InitGlobalVarsFun) {
174f3700bdbSYitzhak Mandelbaum   using namespace ast_matchers;
175f3700bdbSYitzhak Mandelbaum 
176f3700bdbSYitzhak Mandelbaum   std::string Code = R"cc(
177f3700bdbSYitzhak Mandelbaum      int Global = 0;
178f3700bdbSYitzhak Mandelbaum      int Target () { return Global; }
179f3700bdbSYitzhak Mandelbaum   )cc";
180f3700bdbSYitzhak Mandelbaum 
181f3700bdbSYitzhak Mandelbaum   auto Unit =
182f3700bdbSYitzhak Mandelbaum       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
183f3700bdbSYitzhak Mandelbaum   auto &Context = Unit->getASTContext();
184f3700bdbSYitzhak Mandelbaum 
185f3700bdbSYitzhak Mandelbaum   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
186f3700bdbSYitzhak Mandelbaum 
187f3700bdbSYitzhak Mandelbaum   auto Results =
188f3700bdbSYitzhak Mandelbaum       match(decl(anyOf(varDecl(hasName("Global")).bind("global"),
189f3700bdbSYitzhak Mandelbaum                        functionDecl(hasName("Target")).bind("target"))),
190f3700bdbSYitzhak Mandelbaum             Context);
191f3700bdbSYitzhak Mandelbaum   const auto *Fun = selectFirst<FunctionDecl>("target", Results);
192f3700bdbSYitzhak Mandelbaum   const auto *Var = selectFirst<VarDecl>("global", Results);
1933ce03c42SYitzhak Mandelbaum   ASSERT_THAT(Fun, NotNull());
194f3700bdbSYitzhak Mandelbaum   ASSERT_THAT(Var, NotNull());
195f3700bdbSYitzhak Mandelbaum 
196f3700bdbSYitzhak Mandelbaum   // Verify the global variable is populated when we analyze `Target`.
197f3700bdbSYitzhak Mandelbaum   Environment Env(DAContext, *Fun);
1980c852dc8SMartin Braenne   EXPECT_THAT(Env.getValue(*Var), NotNull());
199f3700bdbSYitzhak Mandelbaum }
200f3700bdbSYitzhak Mandelbaum 
20173c98831SYitzhak Mandelbaum // Tests that fields mentioned only in default member initializers are included
20273c98831SYitzhak Mandelbaum // in the set of tracked fields.
20373c98831SYitzhak Mandelbaum TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) {
20473c98831SYitzhak Mandelbaum   using namespace ast_matchers;
20573c98831SYitzhak Mandelbaum 
20673c98831SYitzhak Mandelbaum   std::string Code = R"cc(
20773c98831SYitzhak Mandelbaum      struct S {
20873c98831SYitzhak Mandelbaum        S() {}
20973c98831SYitzhak Mandelbaum        int X = 3;
21073c98831SYitzhak Mandelbaum        int Y = X;
21173c98831SYitzhak Mandelbaum      };
21273c98831SYitzhak Mandelbaum      S foo();
21373c98831SYitzhak Mandelbaum   )cc";
21473c98831SYitzhak Mandelbaum 
21573c98831SYitzhak Mandelbaum   auto Unit =
21673c98831SYitzhak Mandelbaum       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
21773c98831SYitzhak Mandelbaum   auto &Context = Unit->getASTContext();
21873c98831SYitzhak Mandelbaum 
21973c98831SYitzhak Mandelbaum   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
22073c98831SYitzhak Mandelbaum 
22173c98831SYitzhak Mandelbaum   auto Results = match(
22273c98831SYitzhak Mandelbaum       qualType(hasDeclaration(
22373c98831SYitzhak Mandelbaum                    cxxRecordDecl(hasName("S"),
22473c98831SYitzhak Mandelbaum                                  hasMethod(cxxConstructorDecl().bind("target")))
22573c98831SYitzhak Mandelbaum                        .bind("struct")))
22673c98831SYitzhak Mandelbaum           .bind("ty"),
22773c98831SYitzhak Mandelbaum       Context);
22873c98831SYitzhak Mandelbaum   const auto *Constructor = selectFirst<FunctionDecl>("target", Results);
22973c98831SYitzhak Mandelbaum   const auto *Rec = selectFirst<RecordDecl>("struct", Results);
23073c98831SYitzhak Mandelbaum   const auto QTy = *selectFirst<QualType>("ty", Results);
23173c98831SYitzhak Mandelbaum   ASSERT_THAT(Constructor, NotNull());
23273c98831SYitzhak Mandelbaum   ASSERT_THAT(Rec, NotNull());
23373c98831SYitzhak Mandelbaum   ASSERT_FALSE(QTy.isNull());
23473c98831SYitzhak Mandelbaum 
23573c98831SYitzhak Mandelbaum   auto Fields = Rec->fields();
23673c98831SYitzhak Mandelbaum   FieldDecl *XDecl = nullptr;
23773c98831SYitzhak Mandelbaum   for (FieldDecl *Field : Fields) {
23873c98831SYitzhak Mandelbaum     if (Field->getNameAsString() == "X") {
23973c98831SYitzhak Mandelbaum       XDecl = Field;
24073c98831SYitzhak Mandelbaum       break;
24173c98831SYitzhak Mandelbaum     }
24273c98831SYitzhak Mandelbaum   }
24373c98831SYitzhak Mandelbaum   ASSERT_THAT(XDecl, NotNull());
24473c98831SYitzhak Mandelbaum 
24573c98831SYitzhak Mandelbaum   // Verify that the `X` field of `S` is populated when analyzing the
24673c98831SYitzhak Mandelbaum   // constructor, even though it is not referenced directly in the constructor.
24773c98831SYitzhak Mandelbaum   Environment Env(DAContext, *Constructor);
2487cf20f15Smartinboehme   auto &Loc = cast<RecordStorageLocation>(Env.createObject(QTy));
2497cf20f15Smartinboehme   EXPECT_THAT(getFieldValue(&Loc, *XDecl, Env), NotNull());
25073c98831SYitzhak Mandelbaum }
25173c98831SYitzhak Mandelbaum 
2523ce03c42SYitzhak Mandelbaum TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) {
2533ce03c42SYitzhak Mandelbaum   using namespace ast_matchers;
2543ce03c42SYitzhak Mandelbaum 
2553ce03c42SYitzhak Mandelbaum   std::string Code = R"cc(
2563ce03c42SYitzhak Mandelbaum      struct S { int Bar; };
2573ce03c42SYitzhak Mandelbaum      S Global = {0};
2583ce03c42SYitzhak Mandelbaum      int Target () { return Global.Bar; }
2593ce03c42SYitzhak Mandelbaum   )cc";
2603ce03c42SYitzhak Mandelbaum 
2613ce03c42SYitzhak Mandelbaum   auto Unit =
2623ce03c42SYitzhak Mandelbaum       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
2633ce03c42SYitzhak Mandelbaum   auto &Context = Unit->getASTContext();
2643ce03c42SYitzhak Mandelbaum 
2653ce03c42SYitzhak Mandelbaum   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
2663ce03c42SYitzhak Mandelbaum 
2673ce03c42SYitzhak Mandelbaum   auto Results =
2683ce03c42SYitzhak Mandelbaum       match(decl(anyOf(varDecl(hasName("Global")).bind("global"),
2693ce03c42SYitzhak Mandelbaum                        functionDecl(hasName("Target")).bind("target"))),
2703ce03c42SYitzhak Mandelbaum             Context);
2713ce03c42SYitzhak Mandelbaum   const auto *Fun = selectFirst<FunctionDecl>("target", Results);
2723ce03c42SYitzhak Mandelbaum   const auto *GlobalDecl = selectFirst<VarDecl>("global", Results);
2733ce03c42SYitzhak Mandelbaum   ASSERT_THAT(Fun, NotNull());
2743ce03c42SYitzhak Mandelbaum   ASSERT_THAT(GlobalDecl, NotNull());
2753ce03c42SYitzhak Mandelbaum 
2763ce03c42SYitzhak Mandelbaum   ASSERT_TRUE(GlobalDecl->getType()->isStructureType());
2773ce03c42SYitzhak Mandelbaum   auto GlobalFields = GlobalDecl->getType()->getAsRecordDecl()->fields();
2783ce03c42SYitzhak Mandelbaum 
2793ce03c42SYitzhak Mandelbaum   FieldDecl *BarDecl = nullptr;
2803ce03c42SYitzhak Mandelbaum   for (FieldDecl *Field : GlobalFields) {
2813ce03c42SYitzhak Mandelbaum     if (Field->getNameAsString() == "Bar") {
2823ce03c42SYitzhak Mandelbaum       BarDecl = Field;
2833ce03c42SYitzhak Mandelbaum       break;
2843ce03c42SYitzhak Mandelbaum     }
2853ce03c42SYitzhak Mandelbaum     FAIL() << "Unexpected field: " << Field->getNameAsString();
2863ce03c42SYitzhak Mandelbaum   }
2873ce03c42SYitzhak Mandelbaum   ASSERT_THAT(BarDecl, NotNull());
2883ce03c42SYitzhak Mandelbaum 
2893ce03c42SYitzhak Mandelbaum   // Verify the global variable is populated when we analyze `Target`.
2903ce03c42SYitzhak Mandelbaum   Environment Env(DAContext, *Fun);
2919940fac7SMartin Braenne   const auto *GlobalLoc =
2929ecdbe38SMartin Braenne       cast<RecordStorageLocation>(Env.getStorageLocation(*GlobalDecl));
2937cf20f15Smartinboehme   auto *BarVal = getFieldValue(GlobalLoc, *BarDecl, Env);
2943ce03c42SYitzhak Mandelbaum   EXPECT_TRUE(isa<IntegerValue>(BarVal));
2953ce03c42SYitzhak Mandelbaum }
2963ce03c42SYitzhak Mandelbaum 
297f3700bdbSYitzhak Mandelbaum TEST_F(EnvironmentTest, InitGlobalVarsConstructor) {
298f3700bdbSYitzhak Mandelbaum   using namespace ast_matchers;
299f3700bdbSYitzhak Mandelbaum 
300f3700bdbSYitzhak Mandelbaum   std::string Code = R"cc(
301f3700bdbSYitzhak Mandelbaum      int Global = 0;
302f3700bdbSYitzhak Mandelbaum      struct Target {
303f3700bdbSYitzhak Mandelbaum        Target() : Field(Global) {}
304f3700bdbSYitzhak Mandelbaum        int Field;
305f3700bdbSYitzhak Mandelbaum      };
306f3700bdbSYitzhak Mandelbaum   )cc";
307f3700bdbSYitzhak Mandelbaum 
308f3700bdbSYitzhak Mandelbaum   auto Unit =
309f3700bdbSYitzhak Mandelbaum       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
310f3700bdbSYitzhak Mandelbaum   auto &Context = Unit->getASTContext();
311f3700bdbSYitzhak Mandelbaum 
312f3700bdbSYitzhak Mandelbaum   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
313f3700bdbSYitzhak Mandelbaum 
314f3700bdbSYitzhak Mandelbaum   auto Results =
315f3700bdbSYitzhak Mandelbaum       match(decl(anyOf(
316f3700bdbSYitzhak Mandelbaum                 varDecl(hasName("Global")).bind("global"),
317f3700bdbSYitzhak Mandelbaum                 cxxConstructorDecl(ofClass(hasName("Target"))).bind("target"))),
318f3700bdbSYitzhak Mandelbaum             Context);
319f3700bdbSYitzhak Mandelbaum   const auto *Ctor = selectFirst<CXXConstructorDecl>("target", Results);
320f3700bdbSYitzhak Mandelbaum   const auto *Var = selectFirst<VarDecl>("global", Results);
321f3700bdbSYitzhak Mandelbaum   ASSERT_TRUE(Ctor != nullptr);
322f3700bdbSYitzhak Mandelbaum   ASSERT_THAT(Var, NotNull());
323f3700bdbSYitzhak Mandelbaum 
324f3700bdbSYitzhak Mandelbaum   // Verify the global variable is populated when we analyze `Target`.
325f3700bdbSYitzhak Mandelbaum   Environment Env(DAContext, *Ctor);
3260c852dc8SMartin Braenne   EXPECT_THAT(Env.getValue(*Var), NotNull());
327f3700bdbSYitzhak Mandelbaum }
328f3700bdbSYitzhak Mandelbaum 
3299ecdbe38SMartin Braenne TEST_F(EnvironmentTest, RefreshRecordValue) {
3300f6cf555SMartin Braenne   using namespace ast_matchers;
3310f6cf555SMartin Braenne 
3320f6cf555SMartin Braenne   std::string Code = R"cc(
3330f6cf555SMartin Braenne      struct S {};
3340f6cf555SMartin Braenne      void target () {
3350f6cf555SMartin Braenne        S s;
3360f6cf555SMartin Braenne        s;
3370f6cf555SMartin Braenne      }
3380f6cf555SMartin Braenne   )cc";
3390f6cf555SMartin Braenne 
3400f6cf555SMartin Braenne   auto Unit =
3410f6cf555SMartin Braenne       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
3420f6cf555SMartin Braenne   auto &Context = Unit->getASTContext();
3430f6cf555SMartin Braenne 
3440f6cf555SMartin Braenne   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
3450f6cf555SMartin Braenne 
3460f6cf555SMartin Braenne   auto Results = match(functionDecl(hasName("target")).bind("target"), Context);
3470f6cf555SMartin Braenne   const auto *Target = selectFirst<FunctionDecl>("target", Results);
3480f6cf555SMartin Braenne   ASSERT_THAT(Target, NotNull());
3490f6cf555SMartin Braenne 
3500f6cf555SMartin Braenne   Results = match(declRefExpr(to(varDecl(hasName("s")))).bind("s"), Context);
3510f6cf555SMartin Braenne   const auto *DRE = selectFirst<DeclRefExpr>("s", Results);
3520f6cf555SMartin Braenne   ASSERT_THAT(DRE, NotNull());
3530f6cf555SMartin Braenne 
3540f6cf555SMartin Braenne   Environment Env(DAContext, *Target);
355b244b6aeSMartin Braenne   EXPECT_THAT(Env.getStorageLocation(*DRE), IsNull());
3569ecdbe38SMartin Braenne   refreshRecordValue(*DRE, Env);
357b244b6aeSMartin Braenne   EXPECT_THAT(Env.getStorageLocation(*DRE), NotNull());
3580f6cf555SMartin Braenne }
3590f6cf555SMartin Braenne 
360ae60884dSStanislav Gatev } // namespace
361