1 #include "TestingSupport.h"
2 #include "clang/AST/ASTContext.h"
3 #include "clang/ASTMatchers/ASTMatchFinder.h"
4 #include "clang/ASTMatchers/ASTMatchers.h"
5 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
6 #include "clang/Tooling/Tooling.h"
7 #include "llvm/Testing/ADT/StringMapEntry.h"
8 #include "llvm/Testing/Support/Error.h"
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
12 using namespace clang
;
13 using namespace dataflow
;
17 using ::clang::ast_matchers::functionDecl
;
18 using ::clang::ast_matchers::hasAnyName
;
19 using ::clang::ast_matchers::hasName
;
20 using ::clang::ast_matchers::isDefinition
;
21 using ::clang::dataflow::test::AnalysisInputs
;
22 using ::clang::dataflow::test::AnalysisOutputs
;
23 using ::clang::dataflow::test::checkDataflow
;
24 using ::llvm::IsStringMapEntry
;
26 using ::testing::IsEmpty
;
27 using ::testing::UnorderedElementsAre
;
30 const FunctionDecl
*findTargetFunc(ASTContext
&Context
, T FunctionMatcher
) {
32 functionDecl(FunctionMatcher
, isDefinition()).bind("target");
33 for (const auto &Node
: ast_matchers::match(TargetMatcher
, Context
)) {
34 const auto *Func
= Node
.template getNodeAs
<FunctionDecl
>("target");
37 if (Func
->isTemplated())
45 llvm::StringRef Code
, llvm::StringRef TargetName
,
46 std::function
<void(const llvm::DenseMap
<const Stmt
*, std::string
> &)>
48 llvm::Annotations
AnnotatedCode(Code
);
49 auto Unit
= tooling::buildASTFromCodeWithArgs(
50 AnnotatedCode
.code(), {"-fsyntax-only", "-std=c++17"});
51 auto &Context
= Unit
->getASTContext();
52 const FunctionDecl
*Func
= findTargetFunc(Context
, hasName(TargetName
));
53 ASSERT_NE(Func
, nullptr);
55 llvm::Expected
<llvm::DenseMap
<const Stmt
*, std::string
>> Mapping
=
56 test::buildStatementToAnnotationMapping(Func
, AnnotatedCode
);
57 ASSERT_TRUE(static_cast<bool>(Mapping
));
59 RunChecks(Mapping
.get());
62 TEST(BuildStatementToAnnotationMappingTest
, ReturnStmt
) {
70 [](const llvm::DenseMap
<const Stmt
*, std::string
> &Annotations
) {
71 ASSERT_EQ(Annotations
.size(), static_cast<unsigned int>(1));
72 EXPECT_TRUE(isa
<ReturnStmt
>(Annotations
.begin()->first
));
73 EXPECT_EQ(Annotations
.begin()->second
, "ok");
79 ast_matchers::internal::Matcher
<FunctionDecl
> TargetFuncMatcher
,
81 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
82 const AnalysisOutputs
&)>
84 ASSERT_THAT_ERROR(checkDataflow
<NoopAnalysis
>(
85 AnalysisInputs
<NoopAnalysis
>(
86 Code
, std::move(TargetFuncMatcher
),
87 [](ASTContext
&Context
, Environment
&) {
90 // Don't apply builtin transfer function.
91 DataflowAnalysisOptions
{std::nullopt
});
93 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
94 /*VerifyResults=*/std::move(Expectations
)),
98 TEST(ProgramPointAnnotations
, NoAnnotations
) {
99 ::testing::MockFunction
<void(
100 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
101 const AnalysisOutputs
&)>
104 EXPECT_CALL(Expectations
, Call(IsEmpty(), _
)).Times(1);
106 checkDataflow("void target() {}", hasName("target"),
107 Expectations
.AsStdFunction());
110 TEST(ProgramPointAnnotations
, NoAnnotationsDifferentTarget
) {
111 ::testing::MockFunction
<void(
112 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
113 const AnalysisOutputs
&)>
116 EXPECT_CALL(Expectations
, Call(IsEmpty(), _
)).Times(1);
118 checkDataflow("void target() {}", hasName("target"),
119 Expectations
.AsStdFunction());
122 TEST(ProgramPointAnnotations
, WithProgramPoint
) {
123 ::testing::MockFunction
<void(
124 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
125 const AnalysisOutputs
&)>
130 Call(UnorderedElementsAre(IsStringMapEntry("program-point", _
)), _
))
133 checkDataflow(R
"cc(void target() {
137 hasName("target"), Expectations
.AsStdFunction());
140 TEST(ProgramPointAnnotations
, MultipleProgramPoints
) {
141 ::testing::MockFunction
<void(
142 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
143 const AnalysisOutputs
&)>
146 EXPECT_CALL(Expectations
,
147 Call(UnorderedElementsAre(IsStringMapEntry("program-point-1", _
),
148 IsStringMapEntry("program-point-2", _
)),
152 checkDataflow(R
"cc(void target(bool b) {
155 // [[program-point-1]]
158 // [[program-point-2]]
161 hasName("target"), Expectations
.AsStdFunction());
164 TEST(ProgramPointAnnotations
, MultipleFunctionsMultipleProgramPoints
) {
165 ::testing::MockFunction
<void(
166 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
167 const AnalysisOutputs
&)>
170 EXPECT_CALL(Expectations
, Call(UnorderedElementsAre(
171 IsStringMapEntry("program-point-1a", _
),
172 IsStringMapEntry("program-point-1b", _
)),
176 EXPECT_CALL(Expectations
, Call(UnorderedElementsAre(
177 IsStringMapEntry("program-point-2a", _
),
178 IsStringMapEntry("program-point-2b", _
)),
184 void target1(bool b) {
187 // [[program-point-1a]]
190 // [[program-point-1b]]
194 void target2(bool b) {
197 // [[program-point-2a]]
200 // [[program-point-2b]]
204 functionDecl(hasAnyName("target1", "target2")),
205 Expectations
.AsStdFunction());