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