[clang] [clang][dataflow] Model the fields that are accessed via inline accessors (PR #66368)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 05:51:02 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang
            
<details>
<summary>Changes</summary>
So that the values that are accessed via such accessors can be analyzed as a limited version of context-sensitive analysis. We can potentially do this only when some option is set, but doing additional modeling like this won't be expensive and intrusive, so we do it by default for now.
--
Full diff: https://github.com/llvm/llvm-project/pull/66368.diff

2 Files Affected:

- (modified) clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (+18) 
- (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+44) 


<pre>
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index e13f880896fc071..713df62e5009336 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -288,6 +288,18 @@ static void insertIfFunction(const Decl &amp;D,
     Funcs.insert(FD);
 }
 
+static Expr *getRetValueFromSingleReturnStmtMethod(const CXXMemberCallExpr &amp;C) {
+  auto *D = cast_or_null&lt;CXXMethodDecl&gt;(C.getMethodDecl()-&gt;getDefinition());
+  if (!D)
+    return nullptr;
+  auto *S = cast&lt;CompoundStmt&gt;(D-&gt;getBody());
+  if (S-&gt;size() != 1)
+    return nullptr;
+  if (auto *RS = dyn_cast&lt;ReturnStmt&gt;(*S-&gt;body_begin()))
+    return RS-&gt;getRetValue()-&gt;IgnoreParenImpCasts();
+  return nullptr;
+}
+
 static void
 getFieldsGlobalsAndFuncs(const Decl &amp;D, FieldSet &amp;Fields,
                          llvm::DenseSet&lt;const VarDecl *&gt; &amp;Vars,
@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt &amp;S, FieldSet &amp;Fields,
   } else if (auto *E = dyn_cast&lt;DeclRefExpr&gt;(&amp;S)) {
     insertIfGlobal(*E-&gt;getDecl(), Vars);
     insertIfFunction(*E-&gt;getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast&lt;CXXMemberCallExpr&gt;(&amp;S)) {
+    // If this is a method that returns a member variable but does nothing else,
+    // model the field of the return value.
+    if (MemberExpr *E = dyn_cast_or_null&lt;MemberExpr&gt;(
+        getRetValueFromSingleReturnStmtMethod(*C)))
+      getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
   } else if (auto *E = dyn_cast&lt;MemberExpr&gt;(&amp;S)) {
     // FIXME: should we be using `E-&gt;getFoundDecl()`?
     const ValueDecl *VD = E-&gt;getMemberDecl();
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 0abd171f1d0b7cb..d52433b14da142a 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1446,6 +1446,50 @@ TEST(TransferTest, BaseClassInitializer) {
       llvm::Succeeded());
 }
 
+TEST(TransferTest, StructModeledFieldsWithConstAccessor) {
+  std::string Code = R&quot;(
+    class S {
+      int *P;
+      int *Q;
+      int X;
+      int Y;
+      int Z;
+    public:
+      int *getPtr() const { return P; }
+      int *getPtrNonConst() { return Q; }
+      int getInt() const { return X; }
+      int getInt(int i) const { return Y; }
+      int getIntNonConst() { return Z; }
+      int getIntNoDefinition() const;
+    };
+
+    void target() {
+      S s;
+      int *p = s.getPtr();
+      int *q = s.getPtrNonConst();
+      int x = s.getInt();
+      int y = s.getIntNonConst();
+      int z = s.getIntNoDefinition();
+      // [[p]]
+    }
+  )&quot;;
+  runDataflow(
+      Code,
+      [](const llvm::StringMap&lt;DataflowAnalysisState&lt;NoopLattice&gt;&gt; &amp;Results,
+         ASTContext &amp;ASTCtx) {
+        const Environment &amp;Env =
+              getEnvironmentAtAnnotation(Results, &quot;p&quot;);
+        auto &amp;SLoc = getLocForDecl&lt;RecordStorageLocation&gt;(ASTCtx, Env, &quot;s&quot;);
+        std::vector&lt;const ValueDecl*&gt; Fields;
+        for (auto [Field, _] : SLoc.children())
+          Fields.push_back(Field);
+        // Only the fields that have corresponding const accessor methods
+        // should be modeled.
+        ASSERT_THAT(Fields, UnorderedElementsAre(
+            findValueDecl(ASTCtx, &quot;P&quot;), findValueDecl(ASTCtx, &quot;X&quot;)));
+      });
+}
+
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = R&quot;(
     struct Base1 {
</pre>
</details>


https://github.com/llvm/llvm-project/pull/66368


More information about the cfe-commits mailing list