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