[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / TestingSupportTest.cpp
blob5de3dd8dccb68a99d3beb1173dfaa6cfb72721ed
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;
15 namespace {
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;
25 using ::testing::_;
26 using ::testing::IsEmpty;
27 using ::testing::UnorderedElementsAre;
29 template <typename T>
30 const FunctionDecl *findTargetFunc(ASTContext &Context, T FunctionMatcher) {
31 auto TargetMatcher =
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");
35 if (Func == nullptr)
36 continue;
37 if (Func->isTemplated())
38 continue;
39 return Func;
41 return nullptr;
44 void runTest(
45 llvm::StringRef Code, llvm::StringRef TargetName,
46 std::function<void(const llvm::DenseMap<const Stmt *, std::string> &)>
47 RunChecks) {
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) {
63 runTest(R"(
64 int target() {
65 return 42;
66 /*[[ok]]*/
68 )",
69 "target",
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");
74 });
77 void checkDataflow(
78 llvm::StringRef Code,
79 ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcher,
80 std::function<
81 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
82 const AnalysisOutputs &)>
83 Expectations) {
84 ASSERT_THAT_ERROR(checkDataflow<NoopAnalysis>(
85 AnalysisInputs<NoopAnalysis>(
86 Code, std::move(TargetFuncMatcher),
87 [](ASTContext &Context, Environment &) {
88 return NoopAnalysis(
89 Context,
90 // Don't apply builtin transfer function.
91 DataflowAnalysisOptions{std::nullopt});
93 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
94 /*VerifyResults=*/std::move(Expectations)),
95 llvm::Succeeded());
98 TEST(ProgramPointAnnotations, NoAnnotations) {
99 ::testing::MockFunction<void(
100 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
101 const AnalysisOutputs &)>
102 Expectations;
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 &)>
114 Expectations;
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 &)>
126 Expectations;
128 EXPECT_CALL(
129 Expectations,
130 Call(UnorderedElementsAre(IsStringMapEntry("program-point", _)), _))
131 .Times(1);
133 checkDataflow(R"cc(void target() {
134 int n;
135 // [[program-point]]
136 })cc",
137 hasName("target"), Expectations.AsStdFunction());
140 TEST(ProgramPointAnnotations, MultipleProgramPoints) {
141 ::testing::MockFunction<void(
142 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
143 const AnalysisOutputs &)>
144 Expectations;
146 EXPECT_CALL(Expectations,
147 Call(UnorderedElementsAre(IsStringMapEntry("program-point-1", _),
148 IsStringMapEntry("program-point-2", _)),
150 .Times(1);
152 checkDataflow(R"cc(void target(bool b) {
153 if (b) {
154 int n;
155 // [[program-point-1]]
156 } else {
157 int m;
158 // [[program-point-2]]
160 })cc",
161 hasName("target"), Expectations.AsStdFunction());
164 TEST(ProgramPointAnnotations, MultipleFunctionsMultipleProgramPoints) {
165 ::testing::MockFunction<void(
166 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
167 const AnalysisOutputs &)>
168 Expectations;
170 EXPECT_CALL(Expectations, Call(UnorderedElementsAre(
171 IsStringMapEntry("program-point-1a", _),
172 IsStringMapEntry("program-point-1b", _)),
174 .Times(1);
176 EXPECT_CALL(Expectations, Call(UnorderedElementsAre(
177 IsStringMapEntry("program-point-2a", _),
178 IsStringMapEntry("program-point-2b", _)),
180 .Times(1);
182 checkDataflow(
183 R"cc(
184 void target1(bool b) {
185 if (b) {
186 int n;
187 // [[program-point-1a]]
188 } else {
189 int m;
190 // [[program-point-1b]]
194 void target2(bool b) {
195 if (b) {
196 int n;
197 // [[program-point-2a]]
198 } else {
199 int m;
200 // [[program-point-2b]]
203 )cc",
204 functionDecl(hasAnyName("target1", "target2")),
205 Expectations.AsStdFunction());
208 } // namespace