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

2023-09-18 Thread via cfe-commits

https://github.com/martinboehme closed 
https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

kinu wrote:

Thanks! Addressed comments.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

https://github.com/kinu resolved https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits


@@ -288,6 +288,18 @@ static void insertIfFunction(const Decl ,
 Funcs.insert(FD);
 }
 
+static Expr *getRetValueFromSingleReturnStmtMethod(const CXXMemberCallExpr ) 
{
+  auto *D = cast_or_null(C.getMethodDecl()->getDefinition());
+  if (!D)
+return nullptr;
+  auto *S = cast(D->getBody());
+  if (S->size() != 1)
+return nullptr;
+  if (auto *RS = dyn_cast(*S->body_begin()))
+return RS->getRetValue()->IgnoreParenImpCasts();
+  return nullptr;

kinu wrote:

Applied with slight modifications

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

https://github.com/kinu resolved https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

https://github.com/kinu resolved https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits


@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt , FieldSet ,
   } else if (auto *E = dyn_cast()) {
 insertIfGlobal(*E->getDecl(), Vars);
 insertIfFunction(*E->getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast()) {
+// 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(
+getRetValueFromSingleReturnStmtMethod(*C)))
+  getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);

kinu wrote:

Totally, done.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

https://github.com/kinu resolved https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

https://github.com/kinu resolved https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits


@@ -1446,6 +1446,51 @@ TEST(TransferTest, BaseClassInitializer) {
   llvm::Succeeded());
 }
 
+TEST(TransferTest, StructModeledFieldsWithAccessor) {
+  std::string Code = R"(
+class S {
+  int *P;
+  int *Q;
+  int X;
+  int Y;
+  int Z;
+public:
+  int *getPtr() const { return P; }
+  int *getPtrNonConst() { return Q; }
+  int getInt(int i) const { return X; }

kinu wrote:

Done.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread Kinuko Yasuda via cfe-commits

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

>From d311f12fe3ca0d30a40e659236ba7eaccda24a8b Mon Sep 17 00:00:00 2001
From: Kinuko Yasuda 
Date: Thu, 14 Sep 2023 12:45:04 +
Subject: [PATCH 1/4] [clang][dataflow] Model the fields that are accessed via
 inline accessors

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.
---
 .../FlowSensitive/DataflowEnvironment.cpp | 18 
 .../Analysis/FlowSensitive/TransferTest.cpp   | 44 +++
 2 files changed, 62 insertions(+)

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 ,
 Funcs.insert(FD);
 }
 
+static Expr *getRetValueFromSingleReturnStmtMethod(const CXXMemberCallExpr ) 
{
+  auto *D = cast_or_null(C.getMethodDecl()->getDefinition());
+  if (!D)
+return nullptr;
+  auto *S = cast(D->getBody());
+  if (S->size() != 1)
+return nullptr;
+  if (auto *RS = dyn_cast(*S->body_begin()))
+return RS->getRetValue()->IgnoreParenImpCasts();
+  return nullptr;
+}
+
 static void
 getFieldsGlobalsAndFuncs(const Decl , FieldSet ,
  llvm::DenseSet ,
@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt , FieldSet ,
   } else if (auto *E = dyn_cast()) {
 insertIfGlobal(*E->getDecl(), Vars);
 insertIfFunction(*E->getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast()) {
+// 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(
+getRetValueFromSingleReturnStmtMethod(*C)))
+  getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
   } else if (auto *E = dyn_cast()) {
 // FIXME: should we be using `E->getFoundDecl()`?
 const ValueDecl *VD = E->getMemberDecl();
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index cdb1bc3cd16ac7b..355d18bc1fe55a6 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"(
+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]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> ,
+ ASTContext ) {
+const Environment  =
+  getEnvironmentAtAnnotation(Results, "p");
+auto  = getLocForDecl(ASTCtx, Env, "s");
+std::vector 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, "P"), findValueDecl(ASTCtx, "X")));
+  });
+}
+
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = R"(
 struct Base1 {

>From ec7e051b7b0901b5776fe0c0fe751b3a1d2f995d Mon Sep 17 00:00:00 2001
From: Kinuko Yasuda 
Date: Thu, 14 Sep 2023 15:09:29 +
Subject: [PATCH 2/4] Update the broken test

---
 .../Analysis/FlowSensitive/TransferTest.cpp   | 25 +++
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 355d18bc1fe55a6..bf3d002567cc06a 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1446,7 +1446,7 @@ TEST(TransferTest, BaseClassInitializer) {
   llvm::Succeeded());
 }
 
-TEST(TransferTest, StructModeledFieldsWithConstAccessor) {
+TEST(TransferTest, StructModeledFieldsWithAccessor) {
   std::string Code = R"(
 class S {
   int *P;
@@ -1457,9 +1457,9 @@ TEST(TransferTest, 

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

2023-09-15 Thread via cfe-commits


@@ -1446,6 +1446,51 @@ TEST(TransferTest, BaseClassInitializer) {
   llvm::Succeeded());
 }
 
+TEST(TransferTest, StructModeledFieldsWithAccessor) {
+  std::string Code = R"(
+class S {
+  int *P;
+  int *Q;
+  int X;
+  int Y;
+  int Z;

martinboehme wrote:

Rename these to match the methods that return them (e.g. `Ptr`, `PtrNonConst` 
etc.)? This would make it easier to read the assertion below.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits


@@ -288,6 +288,18 @@ static void insertIfFunction(const Decl ,
 Funcs.insert(FD);
 }
 
+static Expr *getRetValueFromSingleReturnStmtMethod(const CXXMemberCallExpr ) 
{
+  auto *D = cast_or_null(C.getMethodDecl()->getDefinition());
+  if (!D)
+return nullptr;
+  auto *S = cast(D->getBody());
+  if (S->size() != 1)
+return nullptr;
+  if (auto *RS = dyn_cast(*S->body_begin()))
+return RS->getRetValue()->IgnoreParenImpCasts();
+  return nullptr;

martinboehme wrote:

```suggestion
  auto *Body = dyn_cast(C.getBody());
  if (!Body || Body->size() != 1)
return nullptr;
  if (auto *RS = dyn_cast(*Body->body_begin()))
return RS->getRetValue()->IgnoreParenImpCasts();
  return nullptr;
```

- `getBody()` can be called on any declaration, not just the definition
- Suggest renaming `S` to `Body` for clarity
- The fact that `getBody()` returns just a `Stmt *` makes me wary that casting 
unconditionally to `CompoundStmt` may not be safe, so suggest using `dyn_cast` 
instead.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits


@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt , FieldSet ,
   } else if (auto *E = dyn_cast()) {
 insertIfGlobal(*E->getDecl(), Vars);
 insertIfFunction(*E->getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast()) {
+// 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(
+getRetValueFromSingleReturnStmtMethod(*C)))
+  getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);

martinboehme wrote:

```suggestion
  if (const auto *FD = dyn_cast(E->getMemberDecl()))
Fields.insert(FD);
```

This is all of the logic that you really need from the recursive 
`getFieldsGlobalsAndFuncs()` call. I would suggest simply repeating these two 
lines here:

- The intent is clearer
- You save quite a few unnecessary `dyn_cast`s

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits


@@ -1446,6 +1446,51 @@ TEST(TransferTest, BaseClassInitializer) {
   llvm::Succeeded());
 }
 
+TEST(TransferTest, StructModeledFieldsWithAccessor) {
+  std::string Code = R"(
+class S {
+  int *P;
+  int *Q;
+  int X;
+  int Y;
+  int Z;
+public:
+  int *getPtr() const { return P; }
+  int *getPtrNonConst() { return Q; }
+  int getInt(int i) const { return X; }

martinboehme wrote:

Can you add a case that returns a reference? This produces a slightly different 
shape of AST (without an `LValueToRValue` cast).

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits


@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt , FieldSet ,
   } else if (auto *E = dyn_cast()) {
 insertIfGlobal(*E->getDecl(), Vars);
 insertIfFunction(*E->getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast()) {
+// 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(

martinboehme wrote:

Maybe include the cast to `MemberExpr` in 
`getRetValueFromSingleReturnStmtMethod()`?

This would put all of the checking in a single function and make the callsite 
here cleaner. The function should then be renamed to something like 
`getMemberForAccessor()`.

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits

https://github.com/martinboehme approved this pull request.


https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-15 Thread via cfe-commits

https://github.com/martinboehme edited 
https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang


Changes
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) 



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_nulllt;CXXMethodDeclgt;(C.getMethodDecl()-gt;getDefinition());
+  if (!D)
+return nullptr;
+  auto *S = castlt;CompoundStmtgt;(D-gt;getBody());
+  if (S-gt;size() != 1)
+return nullptr;
+  if (auto *RS = dyn_castlt;ReturnStmtgt;(*S-gt;body_begin()))
+return RS-gt;getRetValue()-gt;IgnoreParenImpCasts();
+  return nullptr;
+}
+
 static void
 getFieldsGlobalsAndFuncs(const Decl amp;D, FieldSet amp;Fields,
  llvm::DenseSetlt;const VarDecl *gt; 
amp;Vars,
@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt amp;S, FieldSet 
amp;Fields,
   } else if (auto *E = dyn_castlt;DeclRefExprgt;(amp;S)) {
 insertIfGlobal(*E-gt;getDecl(), Vars);
 insertIfFunction(*E-gt;getDecl(), Funcs);
+  } else if (const auto *C = 
dyn_castlt;CXXMemberCallExprgt;(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_nulllt;MemberExprgt;(
+getRetValueFromSingleReturnStmtMethod(*C)))
+  getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
   } else if (auto *E = dyn_castlt;MemberExprgt;(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 = Rquot;(
+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::StringMaplt;DataflowAnalysisStatelt;NoopLatticegt;gt; 
amp;Results,
+ ASTContext amp;ASTCtx) {
+const Environment amp;Env =
+  getEnvironmentAtAnnotation(Results, quot;pquot;);
+auto amp;SLoc = 
getLocForDecllt;RecordStorageLocationgt;(ASTCtx, Env, 
quot;squot;);
+std::vectorlt;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;Pquot;), 
findValueDecl(ASTCtx, quot;Xquot;)));
+  });
+}
+
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = Rquot;(
 struct Base1 {




https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread Kinuko Yasuda via cfe-commits

kinu wrote:

/cc @martinboehme @ymand 

https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread via cfe-commits

https://github.com/llvmbot labeled 
https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread via cfe-commits

https://github.com/llvmbot labeled 
https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread via cfe-commits

https://github.com/llvmbot labeled 
https://github.com/llvm/llvm-project/pull/66368
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2023-09-14 Thread Kinuko Yasuda via cfe-commits

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

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.

>From d3f686a9f342d3cf38ed0cf742fd0377bb998891 Mon Sep 17 00:00:00 2001
From: Kinuko Yasuda 
Date: Thu, 14 Sep 2023 12:45:04 +
Subject: [PATCH] [clang][dataflow] Model the fields that are accessed via
 inline accessors

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.
---
 .../FlowSensitive/DataflowEnvironment.cpp | 18 
 .../Analysis/FlowSensitive/TransferTest.cpp   | 44 +++
 2 files changed, 62 insertions(+)

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 ,
 Funcs.insert(FD);
 }
 
+static Expr *getRetValueFromSingleReturnStmtMethod(const CXXMemberCallExpr ) 
{
+  auto *D = cast_or_null(C.getMethodDecl()->getDefinition());
+  if (!D)
+return nullptr;
+  auto *S = cast(D->getBody());
+  if (S->size() != 1)
+return nullptr;
+  if (auto *RS = dyn_cast(*S->body_begin()))
+return RS->getRetValue()->IgnoreParenImpCasts();
+  return nullptr;
+}
+
 static void
 getFieldsGlobalsAndFuncs(const Decl , FieldSet ,
  llvm::DenseSet ,
@@ -324,6 +336,12 @@ getFieldsGlobalsAndFuncs(const Stmt , FieldSet ,
   } else if (auto *E = dyn_cast()) {
 insertIfGlobal(*E->getDecl(), Vars);
 insertIfFunction(*E->getDecl(), Funcs);
+  } else if (const auto *C = dyn_cast()) {
+// 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(
+getRetValueFromSingleReturnStmtMethod(*C)))
+  getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
   } else if (auto *E = dyn_cast()) {
 // FIXME: should we be using `E->getFoundDecl()`?
 const ValueDecl *VD = E->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"(
+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]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> ,
+ ASTContext ) {
+const Environment  =
+  getEnvironmentAtAnnotation(Results, "p");
+auto  = getLocForDecl(ASTCtx, Env, "s");
+std::vector 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, "P"), findValueDecl(ASTCtx, "X")));
+  });
+}
+
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = R"(
 struct Base1 {

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits