Skip to content

Commit 03be486

Browse files
authored
[clang][dataflow] Model the fields that are accessed via inline accessors (#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.
1 parent 75b76c4 commit 03be486

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ static void insertIfFunction(const Decl &D,
288288
Funcs.insert(FD);
289289
}
290290

291+
static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
292+
auto *Body = dyn_cast_or_null<CompoundStmt>(C.getMethodDecl()->getBody());
293+
if (!Body || Body->size() != 1)
294+
return nullptr;
295+
if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
296+
return dyn_cast<MemberExpr>(RS->getRetValue()->IgnoreParenImpCasts());
297+
return nullptr;
298+
}
299+
291300
static void
292301
getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
293302
llvm::DenseSet<const VarDecl *> &Vars,
@@ -324,6 +333,12 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
324333
} else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
325334
insertIfGlobal(*E->getDecl(), Vars);
326335
insertIfFunction(*E->getDecl(), Funcs);
336+
} else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
337+
// If this is a method that returns a member variable but does nothing else,
338+
// model the field of the return value.
339+
if (MemberExpr *E = getMemberForAccessor(*C))
340+
if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
341+
Fields.insert(FD);
327342
} else if (auto *E = dyn_cast<MemberExpr>(&S)) {
328343
// FIXME: should we be using `E->getFoundDecl()`?
329344
const ValueDecl *VD = E->getMemberDecl();

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,55 @@ TEST(TransferTest, BaseClassInitializer) {
14461446
llvm::Succeeded());
14471447
}
14481448

1449+
TEST(TransferTest, StructModeledFieldsWithAccessor) {
1450+
std::string Code = R"(
1451+
class S {
1452+
int *Ptr;
1453+
int *PtrNonConst;
1454+
int Int;
1455+
int IntWithInc;
1456+
int IntNotAccessed;
1457+
int IntRef;
1458+
public:
1459+
int *getPtr() const { return Ptr; }
1460+
int *getPtrNonConst() { return PtrNonConst; }
1461+
int getInt(int i) const { return Int; }
1462+
int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1463+
int getIntNotAccessed() const { return IntNotAccessed; }
1464+
int getIntNoDefinition() const;
1465+
int &getIntRef() { return IntRef; }
1466+
};
1467+
1468+
void target() {
1469+
S s;
1470+
int *p1 = s.getPtr();
1471+
int *p2 = s.getPtrNonConst();
1472+
int i1 = s.getInt(1);
1473+
int i2 = s.getWithInc(1);
1474+
int i3 = s.getIntNoDefinition();
1475+
int &iref = s.getIntRef();
1476+
// [[p]]
1477+
}
1478+
)";
1479+
runDataflow(
1480+
Code,
1481+
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1482+
ASTContext &ASTCtx) {
1483+
const Environment &Env =
1484+
getEnvironmentAtAnnotation(Results, "p");
1485+
auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
1486+
std::vector<const ValueDecl*> Fields;
1487+
for (auto [Field, _] : SLoc.children())
1488+
Fields.push_back(Field);
1489+
// Only the fields that have simple accessor methods (that have a
1490+
// single statement body that returns the member variable) should be
1491+
// modeled.
1492+
ASSERT_THAT(Fields, UnorderedElementsAre(
1493+
findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"),
1494+
findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef")));
1495+
});
1496+
}
1497+
14491498
TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
14501499
std::string Code = R"(
14511500
struct Base1 {

0 commit comments

Comments
 (0)