aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests
diff options
context:
space:
mode:
authorSam Estep <sam@samestep.com>2022-07-26 17:26:58 +0000
committerSam Estep <sam@samestep.com>2022-07-26 17:27:19 +0000
commitfa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317 (patch)
treeded5126349d832870c5d92d097b9d626d2f6f858 /clang/unittests
parentf106525de2bb1be9cd055c45de6d9cf1b46b3c45 (diff)
downloadllvm-fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317.zip
llvm-fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317.tar.gz
llvm-fa2b83d07ecab3b24b4c5ee2e7dc4b6bbc895317.tar.bz2
[clang][dataflow] Analyze calls to in-TU functions
Depends On D130305 This patch adds initial support for context-sensitive analysis of simple functions whose definition is available in the translation unit, guarded by the `ContextSensitive` flag in the new `TransferOptions` struct. When this option is true, the `VisitCallExpr` case in the builtin transfer function has a fallthrough case which checks for a direct callee with a body. In that case, it constructs a CFG from that callee body, uses the new `pushCall` method on the `Environment` to make an environment to analyze the callee, and then calls `runDataflowAnalysis` with a `NoopAnalysis` (disabling context-sensitive analysis on that sub-analysis, to avoid problems with recursion). After the sub-analysis completes, the `Environment` from its exit block is simply assigned back to the environment at the callsite. The `pushCall` method (which currently only supports non-method functions with some restrictions) first calls `initGlobalVars`, then maps the `SourceLocation`s for all the parameters to the existing source locations for the corresponding arguments from the callsite. This patch adds a few tests to check that this context-sensitive analysis works on simple functions. More sophisticated functionality will be added later; the most important next step is to explicitly model context in some fields of the `DataflowAnalysisContext` class, as mentioned in a `TODO` comment in the `pushCall` implementation. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D130306
Diffstat (limited to 'clang/unittests')
-rw-r--r--clang/unittests/Analysis/FlowSensitive/TransferTest.cpp114
1 files changed, 106 insertions, 8 deletions
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index bf3aab1..41e4252 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -39,14 +39,14 @@ using ::testing::SizeIs;
template <typename Matcher>
void runDataflow(llvm::StringRef Code, Matcher Match,
- LangStandard::Kind Std = LangStandard::lang_cxx17,
- bool ApplyBuiltinTransfer = true,
- llvm::StringRef TargetFun = "target") {
+ DataflowAnalysisOptions Options,
+ LangStandard::Kind Std = LangStandard::lang_cxx17,
+ llvm::StringRef TargetFun = "target") {
ASSERT_THAT_ERROR(
test::checkDataflow<NoopAnalysis>(
Code, TargetFun,
- [ApplyBuiltinTransfer](ASTContext &C, Environment &) {
- return NoopAnalysis(C, ApplyBuiltinTransfer);
+ [Options](ASTContext &C, Environment &) {
+ return NoopAnalysis(C, Options);
},
[&Match](
llvm::ArrayRef<
@@ -54,12 +54,19 @@ void runDataflow(llvm::StringRef Code, Matcher Match,
Results,
ASTContext &ASTCtx) { Match(Results, ASTCtx); },
{"-fsyntax-only", "-fno-delayed-template-parsing",
- "-std=" +
- std::string(
- LangStandard::getLangStandardForKind(Std).getName())}),
+ "-std=" + std::string(
+ LangStandard::getLangStandardForKind(Std).getName())}),
llvm::Succeeded());
}
+template <typename Matcher>
+void runDataflow(llvm::StringRef Code, Matcher Match,
+ LangStandard::Kind Std = LangStandard::lang_cxx17,
+ bool ApplyBuiltinTransfer = true,
+ llvm::StringRef TargetFun = "target") {
+ runDataflow(Code, Match, {ApplyBuiltinTransfer, {}}, Std, TargetFun);
+}
+
TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
std::string Code = R"(
void target() {
@@ -3862,4 +3869,95 @@ TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
});
}
+TEST(TransferTest, ContextSensitiveOptionDisabled) {
+ std::string Code = R"(
+ bool GiveBool();
+ void SetBool(bool &Var) { Var = true; }
+
+ void target() {
+ bool Foo = GiveBool();
+ SetBool(Foo);
+ // [[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_FALSE(Env.flowConditionImplies(FooVal));
+ EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal)));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/false}});
+}
+
+TEST(TransferTest, ContextSensitiveSetTrue) {
+ std::string Code = R"(
+ bool GiveBool();
+ void SetBool(bool &Var) { Var = true; }
+
+ void target() {
+ bool Foo = GiveBool();
+ SetBool(Foo);
+ // [[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, ContextSensitiveSetFalse) {
+ std::string Code = R"(
+ bool GiveBool();
+ void SetBool(bool &Var) { Var = false; }
+
+ void target() {
+ bool Foo = GiveBool();
+ SetBool(Foo);
+ // [[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(Env.makeNot(FooVal)));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
} // namespace