1 // unittests/ASTMatchers/ASTMatchersInternalTest.cpp - AST matcher unit tests //
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "ASTMatchersTest.h"
10 #include "clang/AST/PrettyPrinter.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Tooling/Tooling.h"
14 #include "llvm/ADT/Triple.h"
15 #include "llvm/Support/Host.h"
16 #include "llvm/Testing/Support/SupportHelpers.h"
17 #include "gtest/gtest.h"
18
19 namespace clang {
20 namespace ast_matchers {
21 using internal::DynTypedMatcher;
22
23 #if GTEST_HAS_DEATH_TEST
TEST(HasNameDeathTest,DiesOnEmptyName)24 TEST(HasNameDeathTest, DiesOnEmptyName) {
25 ASSERT_DEBUG_DEATH({
26 DeclarationMatcher HasEmptyName = recordDecl(hasName(""));
27 EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
28 }, "");
29 }
30
TEST(HasNameDeathTest,DiesOnEmptyPattern)31 TEST(HasNameDeathTest, DiesOnEmptyPattern) {
32 ASSERT_DEBUG_DEATH({
33 DeclarationMatcher HasEmptyName = recordDecl(matchesName(""));
34 EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
35 }, "");
36 }
37 #endif
38
TEST(ConstructVariadic,MismatchedTypes_Regression)39 TEST(ConstructVariadic, MismatchedTypes_Regression) {
40 EXPECT_TRUE(
41 matches("const int a = 0;", internal::DynTypedMatcher::constructVariadic(
42 internal::DynTypedMatcher::VO_AnyOf,
43 ASTNodeKind::getFromNodeKind<QualType>(),
44 {isConstQualified(), arrayType()})
45 .convertTo<QualType>()));
46 }
47
48 // For testing AST_MATCHER_P().
AST_MATCHER_P(Decl,just,internal::Matcher<Decl>,AMatcher)49 AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
50 // Make sure all special variables are used: node, match_finder,
51 // bound_nodes_builder, and the parameter named 'AMatcher'.
52 return AMatcher.matches(Node, Finder, Builder);
53 }
54
TEST(AstMatcherPMacro,Works)55 TEST(AstMatcherPMacro, Works) {
56 DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
57
58 EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
59 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
60
61 EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
62 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
63
64 EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
65 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
66 }
67
AST_POLYMORPHIC_MATCHER_P(polymorphicHas,AST_POLYMORPHIC_SUPPORTED_TYPES (Decl,Stmt),internal::Matcher<Decl>,AMatcher)68 AST_POLYMORPHIC_MATCHER_P(polymorphicHas,
69 AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt),
70 internal::Matcher<Decl>, AMatcher) {
71 return Finder->matchesChildOf(
72 Node, AMatcher, Builder,
73 ASTMatchFinder::BK_First);
74 }
75
TEST(AstPolymorphicMatcherPMacro,Works)76 TEST(AstPolymorphicMatcherPMacro, Works) {
77 DeclarationMatcher HasClassB =
78 polymorphicHas(recordDecl(hasName("B")).bind("b"));
79
80 EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
81 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
82
83 EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
84 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
85
86 EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
87 HasClassB, std::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
88
89 StatementMatcher StatementHasClassB =
90 polymorphicHas(recordDecl(hasName("B")));
91
92 EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
93 }
94
TEST(MatchFinder,CheckProfiling)95 TEST(MatchFinder, CheckProfiling) {
96 MatchFinder::MatchFinderOptions Options;
97 llvm::StringMap<llvm::TimeRecord> Records;
98 Options.CheckProfiling.emplace(Records);
99 MatchFinder Finder(std::move(Options));
100
101 struct NamedCallback : public MatchFinder::MatchCallback {
102 void run(const MatchFinder::MatchResult &Result) override {}
103 StringRef getID() const override { return "MyID"; }
104 } Callback;
105 Finder.addMatcher(decl(), &Callback);
106 std::unique_ptr<FrontendActionFactory> Factory(
107 newFrontendActionFactory(&Finder));
108 ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
109
110 EXPECT_EQ(1u, Records.size());
111 EXPECT_EQ("MyID", Records.begin()->getKey());
112 }
113
114 class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
115 public:
VerifyStartOfTranslationUnit()116 VerifyStartOfTranslationUnit() : Called(false) {}
run(const MatchFinder::MatchResult & Result)117 void run(const MatchFinder::MatchResult &Result) override {
118 EXPECT_TRUE(Called);
119 }
onStartOfTranslationUnit()120 void onStartOfTranslationUnit() override { Called = true; }
121 bool Called;
122 };
123
TEST(MatchFinder,InterceptsStartOfTranslationUnit)124 TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
125 MatchFinder Finder;
126 VerifyStartOfTranslationUnit VerifyCallback;
127 Finder.addMatcher(decl(), &VerifyCallback);
128 std::unique_ptr<FrontendActionFactory> Factory(
129 newFrontendActionFactory(&Finder));
130 ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
131 EXPECT_TRUE(VerifyCallback.Called);
132
133 VerifyCallback.Called = false;
134 std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
135 ASSERT_TRUE(AST.get());
136 Finder.matchAST(AST->getASTContext());
137 EXPECT_TRUE(VerifyCallback.Called);
138 }
139
140 class VerifyEndOfTranslationUnit : public MatchFinder::MatchCallback {
141 public:
VerifyEndOfTranslationUnit()142 VerifyEndOfTranslationUnit() : Called(false) {}
run(const MatchFinder::MatchResult & Result)143 void run(const MatchFinder::MatchResult &Result) override {
144 EXPECT_FALSE(Called);
145 }
onEndOfTranslationUnit()146 void onEndOfTranslationUnit() override { Called = true; }
147 bool Called;
148 };
149
TEST(MatchFinder,InterceptsEndOfTranslationUnit)150 TEST(MatchFinder, InterceptsEndOfTranslationUnit) {
151 MatchFinder Finder;
152 VerifyEndOfTranslationUnit VerifyCallback;
153 Finder.addMatcher(decl(), &VerifyCallback);
154 std::unique_ptr<FrontendActionFactory> Factory(
155 newFrontendActionFactory(&Finder));
156 ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
157 EXPECT_TRUE(VerifyCallback.Called);
158
159 VerifyCallback.Called = false;
160 std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
161 ASSERT_TRUE(AST.get());
162 Finder.matchAST(AST->getASTContext());
163 EXPECT_TRUE(VerifyCallback.Called);
164 }
165
TEST(Matcher,matchOverEntireASTContext)166 TEST(Matcher, matchOverEntireASTContext) {
167 std::unique_ptr<ASTUnit> AST =
168 clang::tooling::buildASTFromCode("struct { int *foo; };");
169 ASSERT_TRUE(AST.get());
170 auto PT = selectFirst<PointerType>(
171 "x", match(pointerType().bind("x"), AST->getASTContext()));
172 EXPECT_NE(nullptr, PT);
173 }
174
TEST(DynTypedMatcherTest,TraversalKindForwardsToImpl)175 TEST(DynTypedMatcherTest, TraversalKindForwardsToImpl) {
176 auto M = DynTypedMatcher(decl());
177 EXPECT_FALSE(M.getTraversalKind().hasValue());
178
179 M = DynTypedMatcher(traverse(TK_AsIs, decl()));
180 EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs));
181 }
182
TEST(DynTypedMatcherTest,ConstructWithTraversalKindSetsTK)183 TEST(DynTypedMatcherTest, ConstructWithTraversalKindSetsTK) {
184 auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs);
185 EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs));
186 }
187
TEST(DynTypedMatcherTest,ConstructWithTraversalKindOverridesNestedTK)188 TEST(DynTypedMatcherTest, ConstructWithTraversalKindOverridesNestedTK) {
189 auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs).withTraversalKind(
190 TK_IgnoreUnlessSpelledInSource);
191 EXPECT_THAT(M.getTraversalKind(),
192 llvm::ValueIs(TK_IgnoreUnlessSpelledInSource));
193 }
194
TEST(IsInlineMatcher,IsInline)195 TEST(IsInlineMatcher, IsInline) {
196 EXPECT_TRUE(matches("void g(); inline void f();",
197 functionDecl(isInline(), hasName("f"))));
198 EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
199 namespaceDecl(isInline(), hasName("m"))));
200 }
201
202 // FIXME: Figure out how to specify paths so the following tests pass on
203 // Windows.
204 #ifndef _WIN32
205
TEST(Matcher,IsExpansionInMainFileMatcher)206 TEST(Matcher, IsExpansionInMainFileMatcher) {
207 EXPECT_TRUE(matches("class X {};",
208 recordDecl(hasName("X"), isExpansionInMainFile())));
209 EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
210 FileContentMappings M;
211 M.push_back(std::make_pair("/other", "class X {};"));
212 EXPECT_TRUE(matchesConditionally("#include <other>\n",
213 recordDecl(isExpansionInMainFile()), false,
214 {"-isystem/"}, M));
215 }
216
TEST(Matcher,IsExpansionInSystemHeader)217 TEST(Matcher, IsExpansionInSystemHeader) {
218 FileContentMappings M;
219 M.push_back(std::make_pair("/other", "class X {};"));
220 EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
221 recordDecl(isExpansionInSystemHeader()),
222 true, {"-isystem/"}, M));
223 EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
224 recordDecl(isExpansionInSystemHeader()),
225 false, {"-I/"}, M));
226 EXPECT_TRUE(notMatches("class X {};",
227 recordDecl(isExpansionInSystemHeader())));
228 EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader())));
229 }
230
TEST(Matcher,IsExpansionInFileMatching)231 TEST(Matcher, IsExpansionInFileMatching) {
232 FileContentMappings M;
233 M.push_back(std::make_pair("/foo", "class A {};"));
234 M.push_back(std::make_pair("/bar", "class B {};"));
235 EXPECT_TRUE(matchesConditionally(
236 "#include <foo>\n"
237 "#include <bar>\n"
238 "class X {};",
239 recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
240 {"-isystem/"}, M));
241 EXPECT_TRUE(matchesConditionally(
242 "#include <foo>\n"
243 "#include <bar>\n"
244 "class X {};",
245 recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false,
246 {"-isystem/"}, M));
247 }
248
249 #endif // _WIN32
250
251 } // end namespace ast_matchers
252 } // end namespace clang
253