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