Author: Yitzhak Mandelbaum Date: 2022-12-22T14:20:50Z New Revision: f3700bdb7f00d4f2652a7bdc6a99130e8a1b3c59
URL: https://github.com/llvm/llvm-project/commit/f3700bdb7f00d4f2652a7bdc6a99130e8a1b3c59 DIFF: https://github.com/llvm/llvm-project/commit/f3700bdb7f00d4f2652a7bdc6a99130e8a1b3c59.diff LOG: [clang][dataflow] Account for global variables in constructor initializers. Previously, the analysis modeled global variables appearing in the _body_ of any function (including constructors). But, that misses those appearing in constructor _initializers_. This patch adds the initializers to the set of expressions used to determine which globals to model. Differential Revision: https://reviews.llvm.org/D140501 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 70fcb6be787aa..c883f90f5554b 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -233,6 +233,15 @@ Environment::Environment(DataflowAnalysisContext &DACtx, } } } + + // Look for global variable references in the constructor-initializers. + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&DeclCtx)) { + for (const auto *Init : CtorDecl->inits()) { + const Expr *E = Init->getInit(); + assert(E != nullptr); + initGlobalVars(*E, *this); + } + } } bool Environment::canDescend(unsigned MaxDepth, diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index ae70131a60a57..b237f3b83759f 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -8,6 +8,8 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "TestingSupport.h" +#include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" @@ -21,19 +23,19 @@ namespace { using namespace clang; using namespace dataflow; using ::testing::ElementsAre; +using ::testing::NotNull; using ::testing::Pair; class EnvironmentTest : public ::testing::Test { - DataflowAnalysisContext Context; - protected: - EnvironmentTest() - : Context(std::make_unique<WatchedLiteralsSolver>()), Env(Context) {} + EnvironmentTest() : DAContext(std::make_unique<WatchedLiteralsSolver>()) {} - Environment Env; + DataflowAnalysisContext DAContext; }; TEST_F(EnvironmentTest, FlowCondition) { + Environment Env(DAContext); + EXPECT_TRUE(Env.flowConditionImplies(Env.getBoolLiteralValue(true))); EXPECT_FALSE(Env.flowConditionImplies(Env.getBoolLiteralValue(false))); @@ -76,6 +78,7 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) { // Verify that the struct and the field (`R`) with first appearance of the // type is created successfully. + Environment Env(DAContext); Value *Val = Env.createValue(*Ty); ASSERT_NE(Val, nullptr); StructValue *SVal = clang::dyn_cast<StructValue>(Val); @@ -86,4 +89,64 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) { EXPECT_NE(PV, nullptr); } +TEST_F(EnvironmentTest, InitGlobalVarsFun) { + using namespace ast_matchers; + + std::string Code = R"cc( + int Global = 0; + int Target () { return Global; } + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = + match(decl(anyOf(varDecl(hasName("Global")).bind("global"), + functionDecl(hasName("Target")).bind("target"))), + Context); + const auto *Fun = selectFirst<FunctionDecl>("target", Results); + const auto *Var = selectFirst<VarDecl>("global", Results); + ASSERT_TRUE(Fun != nullptr); + ASSERT_THAT(Var, NotNull()); + + // Verify the global variable is populated when we analyze `Target`. + Environment Env(DAContext, *Fun); + EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); +} + +TEST_F(EnvironmentTest, InitGlobalVarsConstructor) { + using namespace ast_matchers; + + std::string Code = R"cc( + int Global = 0; + struct Target { + Target() : Field(Global) {} + int Field; + }; + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = + match(decl(anyOf( + varDecl(hasName("Global")).bind("global"), + cxxConstructorDecl(ofClass(hasName("Target"))).bind("target"))), + Context); + const auto *Ctor = selectFirst<CXXConstructorDecl>("target", Results); + const auto *Var = selectFirst<VarDecl>("global", Results); + ASSERT_TRUE(Ctor != nullptr); + ASSERT_THAT(Var, NotNull()); + + // Verify the global variable is populated when we analyze `Target`. + Environment Env(DAContext, *Ctor); + EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); +} + } // namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits