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 23 TEST(HasNameDeathTest, DiesOnEmptyName) { 24 ASSERT_DEBUG_DEATH({ 25 DeclarationMatcher HasEmptyName = recordDecl(hasName("")); 26 EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); 27 }, ""); 28 } 29 30 TEST(HasNameDeathTest, DiesOnEmptyPattern) { 31 ASSERT_DEBUG_DEATH({ 32 DeclarationMatcher HasEmptyName = recordDecl(matchesName("")); 33 EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); 34 }, ""); 35 } 36 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 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(). 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 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 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 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 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: 124 VerifyStartOfTranslationUnit() : Called(false) {} 125 void run(const MatchFinder::MatchResult &Result) override { 126 EXPECT_TRUE(Called); 127 } 128 void onStartOfTranslationUnit() override { Called = true; } 129 bool Called; 130 }; 131 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: 150 VerifyEndOfTranslationUnit() : Called(false) {} 151 void run(const MatchFinder::MatchResult &Result) override { 152 EXPECT_FALSE(Called); 153 } 154 void onEndOfTranslationUnit() override { Called = true; } 155 bool Called; 156 }; 157 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 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 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 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 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 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