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