samestep updated this revision to Diff 450951.
samestep added a comment.
Fix bug
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D131438/new/
https://reviews.llvm.org/D131438
Files:
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.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
@@ -4368,4 +4368,72 @@
/*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
}
+TEST(TransferTest, ContextSensitiveConstructorBody) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ MyClass() { MyField = true; }
+
+ bool MyField;
+ };
+
+ void target() {
+ MyClass MyObj;
+ bool Foo = MyObj.MyField;
+ // [[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, ContextSensitiveConstructorInitializer) {
+ std::string Code = R"(
+ class MyClass {
+ public:
+ MyClass() : MyField(true) {}
+
+ bool MyField;
+ };
+
+ void target() {
+ MyClass MyObj;
+ bool Foo = MyObj.MyField;
+ // [[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/Transfer.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -444,6 +444,8 @@
Env.setStorageLocation(*S, Loc);
if (Value *Val = Env.createValue(S->getType()))
Env.setValue(Loc, *Val);
+
+ transferInlineCall(S, ConstructorDecl);
}
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
@@ -526,45 +528,7 @@
return;
Env.setStorageLocation(*S, *ArgLoc);
} else if (const FunctionDecl *F = S->getDirectCallee()) {
- // This case is for context-sensitive analysis.
- if (!Options.ContextSensitive)
- return;
-
- const ControlFlowContext *CFCtx = Env.getControlFlowContext(F);
- if (!CFCtx)
- return;
-
- // FIXME: We don't support context-sensitive analysis of recursion, so
- // we should return early here if `F` is the same as the `FunctionDecl`
- // holding `S` itself.
-
- auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
-
- // Note that it is important for the storage location of `S` to be set
- // before `pushCall`, because the latter uses it to set the storage
- // location for `return`.
- auto &ReturnLoc = Env.createStorageLocation(*S);
- Env.setStorageLocation(*S, ReturnLoc);
- auto CalleeEnv = Env.pushCall(S);
-
- // FIXME: Use the same analysis as the caller for the callee. Note,
- // though, that doing so would require support for changing the analysis's
- // ASTContext.
- assert(
- CFCtx->getDecl() != nullptr &&
- "ControlFlowContexts in the environment should always carry a decl");
- auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
- DataflowAnalysisOptions());
-
- auto BlockToOutputState =
- dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
- assert(BlockToOutputState);
- assert(ExitBlock < BlockToOutputState->size());
-
- auto ExitState = (*BlockToOutputState)[ExitBlock];
- assert(ExitState);
-
- Env.popCall(ExitState->Env);
+ transferInlineCall(S, F);
}
}
@@ -693,6 +657,52 @@
return Env.makeAtomicBoolValue();
}
+ // If context sensitivity is enabled, try to analyze the body of the callee
+ // `F` of `S`. `S` itself must be either a `CallExpr` or a
+ // `CXXConstructExpr`.
+ void transferInlineCall(const Expr *S, const FunctionDecl *F) {
+ if (!Options.ContextSensitive)
+ return;
+
+ const ControlFlowContext *CFCtx = Env.getControlFlowContext(F);
+
+ if (!CFCtx)
+ return;
+
+ // FIXME: We don't support context-sensitive analysis of recursion, so
+ // we should return early here if `F` is the same as the `FunctionDecl`
+ // holding `S` itself.
+
+ auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
+
+ if (const auto *NonConstructExpr = dyn_cast<CallExpr>(S)) {
+ // Note that it is important for the storage location of `S` to be set
+ // before `pushCall`, because the latter uses it to set the storage
+ // location for `return`.
+ auto &ReturnLoc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, ReturnLoc);
+ }
+ auto CalleeEnv = Env.pushCall(S);
+
+ // FIXME: Use the same analysis as the caller for the callee. Note,
+ // though, that doing so would require support for changing the analysis's
+ // ASTContext.
+ assert(CFCtx->getDecl() != nullptr &&
+ "ControlFlowContexts in the environment should always carry a decl");
+ auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
+ DataflowAnalysisOptions());
+
+ auto BlockToOutputState =
+ dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
+ assert(BlockToOutputState);
+ assert(ExitBlock < BlockToOutputState->size());
+
+ auto ExitState = (*BlockToOutputState)[ExitBlock];
+ assert(ExitState);
+
+ Env.popCall(ExitState->Env);
+ }
+
const StmtToEnvMap &StmtToEnv;
Environment &Env;
TransferOptions Options;
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -203,13 +203,11 @@
}
}
-Environment Environment::pushCall(const CallExpr *Call) const {
+Environment Environment::pushCall(const Expr *Call) const {
Environment Env(*this);
// FIXME: Support references here.
Env.ReturnLoc = Env.getStorageLocation(*Call, SkipPast::Reference);
- const auto *FuncDecl = Call->getDirectCallee();
- assert(FuncDecl != nullptr);
// FIXME: In order to allow the callee to reference globals, we probably need
// to call `initGlobalVars` here in some way.
@@ -219,16 +217,37 @@
}
}
+ const FunctionDecl *FuncDecl;
+ unsigned NumArgs;
+ if (const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(Call)) {
+ Env.ThisPointeeLoc = Env.ReturnLoc;
+
+ FuncDecl = ConstructExpr->getConstructor();
+ NumArgs = ConstructExpr->getNumArgs();
+ } else if (const auto *NonConstructExpr = dyn_cast<CallExpr>(Call)) {
+ FuncDecl = NonConstructExpr->getDirectCallee();
+ NumArgs = NonConstructExpr->getNumArgs();
+ } else {
+ // This case is disallowed by the precondition from the method docstring.
+ assert(false);
+ }
auto ParamIt = FuncDecl->param_begin();
- auto ArgIt = Call->arg_begin();
- auto ArgEnd = Call->arg_end();
// FIXME: Parameters don't always map to arguments 1:1; examples include
// overloaded operators implemented as member functions, and parameter packs.
- for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
+ for (unsigned ArgIndex = 0; ArgIndex < NumArgs; ++ParamIt, ++ArgIndex) {
assert(ParamIt != FuncDecl->param_end());
- const Expr *Arg = *ArgIt;
+ const Expr *Arg;
+ if (const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(Call)) {
+ Arg = ConstructExpr->getArg(ArgIndex);
+ } else if (const auto *NonConstructExpr = dyn_cast<CallExpr>(Call)) {
+ Arg = NonConstructExpr->getArg(ArgIndex);
+ } else {
+ // This case is disallowed by the precondition from the method docstring.
+ assert(false);
+ }
+
auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
assert(ArgLoc != nullptr);
Index: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
===================================================================
--- clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -135,6 +135,8 @@
///
/// Requirements:
///
+ /// `Call` must be either a `CallExpr` or a `CXXConstructExpr`.
+ ///
/// The callee of `Call` must be a `FunctionDecl` with a body.
///
/// The body of the callee must not reference globals.
@@ -142,7 +144,7 @@
/// The arguments of `Call` must map 1:1 to the callee's parameters.
///
/// Each argument of `Call` must already have a `StorageLocation`.
- Environment pushCall(const CallExpr *Call) const;
+ Environment pushCall(const Expr *Call) const;
/// Moves gathered information back into `this` from a `CalleeEnv` created via
/// `pushCall`.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits