ymandel created this revision.
ymandel added reviewers: xazax.hun, gribozavr2.
Herald added subscribers: martong, rnkovacs.
Herald added a reviewer: NoQ.
Herald added a project: All.
ymandel requested review of this revision.
Herald added a project: clang.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140501

Files:
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ 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 @@
 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 @@
 
   // 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 @@
   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
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -233,6 +233,15 @@
       }
     }
   }
+
+  // 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,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D140501: [clang... Yitzhak Mandelbaum via Phabricator via cfe-commits

Reply via email to