[clang] [clang][dataflow] Model the fields that are accessed via inline accessors (PR #66368)
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)
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)
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)
@@ -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)
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)
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)
@@ -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)
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)
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)
@@ -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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
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)
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)
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)
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)
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)
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)
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