Home | History | Annotate | Download | only in ASTMatchers
      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