xref: /aosp_15_r20/external/clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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