forked from OSchip/llvm-project
[clang][dataflow] Add support for nested method calls.
Extend the context-sensitive analysis to handle a call to a method (of the same class) from within a method. That, is a member-call expression through `this`. Differential Revision: https://reviews.llvm.org/D134432
This commit is contained in:
parent
d0aeb74e88
commit
0b12efc7a4
|
@ -216,7 +216,10 @@ Environment Environment::pushCall(const CallExpr *Call) const {
|
|||
|
||||
if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
|
||||
if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
|
||||
Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
|
||||
if (!isa<CXXThisExpr>(Arg))
|
||||
Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
|
||||
// Otherwise (when the argument is `this`), retain the current
|
||||
// environment's `ThisPointeeLoc`.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4359,7 +4359,7 @@ TEST(TransferTest, ContextSensitiveMethodSetter) {
|
|||
std::string Code = R"(
|
||||
class MyClass {
|
||||
public:
|
||||
bool setField(bool Val) { Field = Val; }
|
||||
void setField(bool Val) { Field = Val; }
|
||||
|
||||
bool Field;
|
||||
};
|
||||
|
@ -4392,7 +4392,7 @@ TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
|
|||
class MyClass {
|
||||
public:
|
||||
bool getField() { return Field; }
|
||||
bool setField(bool Val) { Field = Val; }
|
||||
void setField(bool Val) { Field = Val; }
|
||||
|
||||
private:
|
||||
bool Field;
|
||||
|
@ -4421,6 +4421,73 @@ TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
|
|||
{TransferOptions{ContextSensitiveOptions{}}});
|
||||
}
|
||||
|
||||
|
||||
TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {
|
||||
std::string Code = R"(
|
||||
class MyClass {
|
||||
public:
|
||||
void Inner() { MyField = true; }
|
||||
void Outer() { Inner(); }
|
||||
|
||||
bool MyField;
|
||||
};
|
||||
|
||||
void target() {
|
||||
MyClass MyObj;
|
||||
MyObj.Outer();
|
||||
bool Foo = MyObj.MyField;
|
||||
// [[p]]
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));;
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
|
||||
ASSERT_THAT(FooDecl, NotNull());
|
||||
|
||||
auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
|
||||
EXPECT_TRUE(Env.flowConditionImplies(FooVal));
|
||||
},
|
||||
{TransferOptions{ContextSensitiveOptions{}}});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {
|
||||
std::string Code = R"(
|
||||
class MyClass {
|
||||
public:
|
||||
bool Inner() { return MyField; }
|
||||
bool Outer() { return Inner(); }
|
||||
|
||||
bool MyField;
|
||||
};
|
||||
|
||||
void target() {
|
||||
MyClass MyObj;
|
||||
MyObj.MyField = true;
|
||||
bool Foo = MyObj.Outer();
|
||||
// [[p]]
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
Code,
|
||||
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));;
|
||||
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
|
||||
|
||||
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
|
||||
ASSERT_THAT(FooDecl, NotNull());
|
||||
|
||||
auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
|
||||
EXPECT_TRUE(Env.flowConditionImplies(FooVal));
|
||||
},
|
||||
{TransferOptions{ContextSensitiveOptions{}}});
|
||||
}
|
||||
|
||||
TEST(TransferTest, ContextSensitiveConstructorBody) {
|
||||
std::string Code = R"(
|
||||
class MyClass {
|
||||
|
|
Loading…
Reference in New Issue