samestep created this revision.
Herald added subscribers: martong, xazax.hun.
Herald added a reviewer: NoQ.
Herald added a project: All.
samestep requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D131170
Files:
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -4229,4 +4229,143 @@
/*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
}
+TEST(TransferTest, ContextSensitiveMethodLiteral) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ bool giveBool() { return true; }
+ };
+
+ void target() {
+ MyClass MyObj;
+ bool Foo = MyObj.giveBool();
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(FooVal));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
+TEST(TransferTest, ContextSensitiveMethodGetter) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ bool getField() { return Field; }
+
+ bool Field;
+ };
+
+ void target() {
+ MyClass MyObj;
+ MyObj.Field = true;
+ bool Foo = MyObj.getField();
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(FooVal));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
+TEST(TransferTest, ContextSensitiveMethodSetter) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ bool setField(bool Val) { Field = Val; }
+
+ bool Field;
+ };
+
+ void target() {
+ MyClass MyObj;
+ MyObj.setField(true);
+ bool Foo = MyObj.Field;
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(FooVal));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
+TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ bool getField() { return Field; }
+ bool setField(bool Val) { Field = Val; }
+
+ private:
+ bool Field;
+ };
+
+ void target() {
+ MyClass MyObj;
+ MyObj.setField(true);
+ bool Foo = MyObj.getField();
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(FooVal));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
} // namespace
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -155,8 +155,9 @@
Environment::Environment(const Environment &Other)
: DACtx(Other.DACtx), ReturnLoc(Other.ReturnLoc),
- DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc),
- LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct),
+ ThisPointeeLoc(Other.ThisPointeeLoc), DeclToLoc(Other.DeclToLoc),
+ ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal),
+ MemberLocToStruct(Other.MemberLocToStruct),
FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) {
}
@@ -194,10 +195,9 @@
QualType ThisPointeeType = MethodDecl->getThisObjectType();
// FIXME: Add support for union types.
if (!ThisPointeeType->isUnionType()) {
- auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
- DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
+ ThisPointeeLoc = &createStorageLocation(ThisPointeeType);
if (Value *ThisPointeeVal = createValue(ThisPointeeType))
- setValue(ThisPointeeLoc, *ThisPointeeVal);
+ setValue(*ThisPointeeLoc, *ThisPointeeVal);
}
}
}
@@ -212,6 +212,11 @@
// FIXME: In order to allow the callee to reference globals, we probably need
// to call `initGlobalVars` here in some way.
+ if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
+ const Expr *Arg = MethodCall->getImplicitObjectArgument();
+ Env.ThisPointeeLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
+ }
+
auto ParamIt = FuncDecl->param_begin();
auto ArgIt = Call->arg_begin();
auto ArgEnd = Call->arg_end();
@@ -245,12 +250,12 @@
void Environment::popCall(const Environment &CalleeEnv) {
// We ignore `DACtx` because it's already the same in both. We don't want the
- // callee's `ReturnLoc`. We don't bring back `DeclToLoc` and `ExprToLoc`
- // because we want to be able to later analyze the same callee in a different
- // context, and `setStorageLocation` requires there to not already be a
- // storage location assigned. Conceptually, these maps capture information
- // from the local scope, so when popping that scope, we do not propagate the
- // maps.
+ // callee's `ReturnLoc` or `ThisPointeeLoc`. We don't bring back `DeclToLoc`
+ // and `ExprToLoc` because we want to be able to later analyze the same callee
+ // in a different context, and `setStorageLocation` requires there to not
+ // already be a storage location assigned. Conceptually, these maps capture
+ // information from the local scope, so when popping that scope, we do not
+ // propagate the maps.
this->LocToVal = std::move(CalleeEnv.LocToVal);
this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
@@ -263,6 +268,9 @@
if (ReturnLoc != Other.ReturnLoc)
return false;
+ if (ThisPointeeLoc != Other.ThisPointeeLoc)
+ return false;
+
if (DeclToLoc != Other.DeclToLoc)
return false;
@@ -293,12 +301,14 @@
Environment::ValueModel &Model) {
assert(DACtx == Other.DACtx);
assert(ReturnLoc == Other.ReturnLoc);
+ assert(ThisPointeeLoc == Other.ThisPointeeLoc);
auto Effect = LatticeJoinEffect::Unchanged;
Environment JoinedEnv(*DACtx);
JoinedEnv.ReturnLoc = ReturnLoc;
+ JoinedEnv.ThisPointeeLoc = ThisPointeeLoc;
JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
@@ -389,7 +399,7 @@
}
StorageLocation *Environment::getThisPointeeStorageLocation() const {
- return DACtx->getThisPointeeStorageLocation();
+ return ThisPointeeLoc;
}
StorageLocation *Environment::getReturnStorageLocation() const {
Index: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
===================================================================
--- clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -380,7 +380,7 @@
// In a properly initialized `Environment`, `ReturnLoc` should only be null if
// its `DeclContext` could not be cast to a `FunctionDecl`.
StorageLocation *ReturnLoc = nullptr;
- // FIXME: Move `ThisPointeeLoc` here from `DataflowAnalysisContext`.
+ StorageLocation *ThisPointeeLoc = nullptr;
// Maps from program declarations and statements to storage locations that are
// assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
Index: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
===================================================================
--- clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -139,22 +139,6 @@
return It == ExprToLoc.end() ? nullptr : It->second;
}
- /// Assigns `Loc` as the storage location of the `this` pointee.
- ///
- /// Requirements:
- ///
- /// The `this` pointee must not be assigned a storage location.
- void setThisPointeeStorageLocation(StorageLocation &Loc) {
- assert(ThisPointeeLoc == nullptr);
- ThisPointeeLoc = &Loc;
- }
-
- /// Returns the storage location assigned to the `this` pointee or null if the
- /// `this` pointee has no assigned storage location.
- StorageLocation *getThisPointeeStorageLocation() const {
- return ThisPointeeLoc;
- }
-
/// Returns a pointer value that represents a null pointer. Calls with
/// `PointeeType` that are canonically equivalent will return the same result.
/// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
@@ -324,9 +308,6 @@
llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
- // FIXME: Move this into `Environment`.
- StorageLocation *ThisPointeeLoc = nullptr;
-
// Null pointer values, keyed by the canonical pointee type.
//
// FIXME: The pointer values are indexed by the pointee types which are
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits