Home | History | Annotate | Download | only in Dynamic
      1 //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry 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/ASTMatchers/Dynamic/Registry.h"
     12 #include "gtest/gtest.h"
     13 #include <vector>
     14 
     15 namespace clang {
     16 namespace ast_matchers {
     17 namespace dynamic {
     18 namespace {
     19 
     20 using ast_matchers::internal::Matcher;
     21 
     22 class RegistryTest : public ::testing::Test {
     23 public:
     24   std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
     25   std::vector<ParserValue> Args(const VariantValue &Arg1) {
     26     std::vector<ParserValue> Out(1);
     27     Out[0].Value = Arg1;
     28     return Out;
     29   }
     30   std::vector<ParserValue> Args(const VariantValue &Arg1,
     31                                 const VariantValue &Arg2) {
     32     std::vector<ParserValue> Out(2);
     33     Out[0].Value = Arg1;
     34     Out[1].Value = Arg2;
     35     return Out;
     36   }
     37 
     38   llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
     39     return Registry::lookupMatcherCtor(MatcherName);
     40   }
     41 
     42   VariantMatcher constructMatcher(StringRef MatcherName,
     43                                   Diagnostics *Error = nullptr) {
     44     Diagnostics DummyError;
     45     if (!Error) Error = &DummyError;
     46     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     47     VariantMatcher Out;
     48     if (Ctor)
     49       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
     50     EXPECT_EQ("", DummyError.toStringFull());
     51     return Out;
     52   }
     53 
     54   VariantMatcher constructMatcher(StringRef MatcherName,
     55                                   const VariantValue &Arg1,
     56                                   Diagnostics *Error = nullptr) {
     57     Diagnostics DummyError;
     58     if (!Error) Error = &DummyError;
     59     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     60     VariantMatcher Out;
     61     if (Ctor)
     62       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
     63     EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
     64     return Out;
     65   }
     66 
     67   VariantMatcher constructMatcher(StringRef MatcherName,
     68                                   const VariantValue &Arg1,
     69                                   const VariantValue &Arg2,
     70                                   Diagnostics *Error = nullptr) {
     71     Diagnostics DummyError;
     72     if (!Error) Error = &DummyError;
     73     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     74     VariantMatcher Out;
     75     if (Ctor)
     76       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
     77                                        Error);
     78     EXPECT_EQ("", DummyError.toStringFull());
     79     return Out;
     80   }
     81 
     82   typedef std::vector<MatcherCompletion> CompVector;
     83 
     84   CompVector getCompletions() {
     85     std::vector<std::pair<MatcherCtor, unsigned> > Context;
     86     return Registry::getMatcherCompletions(
     87         Registry::getAcceptedCompletionTypes(Context));
     88   }
     89 
     90   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
     91     std::vector<std::pair<MatcherCtor, unsigned> > Context;
     92     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
     93     if (!Ctor)
     94       return CompVector();
     95     Context.push_back(std::make_pair(*Ctor, ArgNo1));
     96     return Registry::getMatcherCompletions(
     97         Registry::getAcceptedCompletionTypes(Context));
     98   }
     99 
    100   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
    101                             StringRef MatcherName2, unsigned ArgNo2) {
    102     std::vector<std::pair<MatcherCtor, unsigned> > Context;
    103     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
    104     if (!Ctor)
    105       return CompVector();
    106     Context.push_back(std::make_pair(*Ctor, ArgNo1));
    107     Ctor = lookupMatcherCtor(MatcherName2);
    108     if (!Ctor)
    109       return CompVector();
    110     Context.push_back(std::make_pair(*Ctor, ArgNo2));
    111     return Registry::getMatcherCompletions(
    112         Registry::getAcceptedCompletionTypes(Context));
    113   }
    114 
    115   bool hasCompletion(const CompVector &Comps, StringRef TypedText,
    116                      StringRef MatcherDecl = StringRef()) {
    117     for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
    118          ++I) {
    119       if (I->TypedText == TypedText &&
    120           (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
    121         return true;
    122       }
    123     }
    124     return false;
    125   }
    126 };
    127 
    128 TEST_F(RegistryTest, CanConstructNoArgs) {
    129   Matcher<Stmt> IsArrowValue = constructMatcher(
    130       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
    131   Matcher<Stmt> BoolValue =
    132       constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>();
    133 
    134   const std::string ClassSnippet = "struct Foo { int x; };\n"
    135                                    "Foo *foo = new Foo;\n"
    136                                    "int i = foo->x;\n";
    137   const std::string BoolSnippet = "bool Foo = true;\n";
    138 
    139   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
    140   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
    141   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
    142   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
    143 }
    144 
    145 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
    146   Matcher<Decl> Value = constructMatcher(
    147       "namedDecl", constructMatcher("hasName", StringRef("X")))
    148       .getTypedMatcher<Decl>();
    149   EXPECT_TRUE(matches("class X {};", Value));
    150   EXPECT_FALSE(matches("int x;", Value));
    151 
    152   Value = functionDecl(constructMatcher("parameterCountIs", 2)
    153                            .getTypedMatcher<FunctionDecl>());
    154   EXPECT_TRUE(matches("void foo(int,int);", Value));
    155   EXPECT_FALSE(matches("void foo(int);", Value));
    156 }
    157 
    158 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
    159   Matcher<Decl> HasInitializerSimple = constructMatcher(
    160       "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
    161       .getTypedMatcher<Decl>();
    162   Matcher<Decl> HasInitializerComplex = constructMatcher(
    163       "varDecl",
    164       constructMatcher("hasInitializer", constructMatcher("callExpr")))
    165       .getTypedMatcher<Decl>();
    166 
    167   std::string code = "int i;";
    168   EXPECT_FALSE(matches(code, HasInitializerSimple));
    169   EXPECT_FALSE(matches(code, HasInitializerComplex));
    170 
    171   code = "int i = 1;";
    172   EXPECT_TRUE(matches(code, HasInitializerSimple));
    173   EXPECT_FALSE(matches(code, HasInitializerComplex));
    174 
    175   code = "int y(); int i = y();";
    176   EXPECT_TRUE(matches(code, HasInitializerSimple));
    177   EXPECT_TRUE(matches(code, HasInitializerComplex));
    178 
    179   Matcher<Decl> HasParameter =
    180       functionDecl(constructMatcher(
    181           "hasParameter", 1, constructMatcher("hasName", StringRef("x")))
    182                        .getTypedMatcher<FunctionDecl>());
    183   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
    184   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
    185 }
    186 
    187 TEST_F(RegistryTest, OverloadedMatchers) {
    188   Matcher<Stmt> CallExpr0 = constructMatcher(
    189       "callExpr",
    190       constructMatcher("callee", constructMatcher("memberExpr",
    191                                                   constructMatcher("isArrow"))))
    192       .getTypedMatcher<Stmt>();
    193 
    194   Matcher<Stmt> CallExpr1 = constructMatcher(
    195       "callExpr",
    196       constructMatcher(
    197           "callee",
    198           constructMatcher("cxxMethodDecl",
    199                            constructMatcher("hasName", StringRef("x")))))
    200       .getTypedMatcher<Stmt>();
    201 
    202   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
    203   EXPECT_FALSE(matches(Code, CallExpr0));
    204   EXPECT_TRUE(matches(Code, CallExpr1));
    205 
    206   Code = "class Z { public: void z() { this->z(); } };";
    207   EXPECT_TRUE(matches(Code, CallExpr0));
    208   EXPECT_FALSE(matches(Code, CallExpr1));
    209 
    210   Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
    211       constructMatcher(
    212           "loc", constructMatcher("asString", StringRef("const double *")))
    213           .getTypedMatcher<TypeLoc>()));
    214 
    215   Matcher<NestedNameSpecifierLoc> NNSL =
    216       constructMatcher(
    217           "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
    218                      specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
    219           .getTypedMatcher<NestedNameSpecifierLoc>();
    220 
    221   Code = "const double * x = 0;";
    222   EXPECT_TRUE(matches(Code, DeclDecl));
    223   EXPECT_FALSE(matches(Code, NNSL));
    224 
    225   Code = "struct A { struct B {}; }; A::B a_b;";
    226   EXPECT_FALSE(matches(Code, DeclDecl));
    227   EXPECT_TRUE(matches(Code, NNSL));
    228 }
    229 
    230 TEST_F(RegistryTest, PolymorphicMatchers) {
    231   const VariantMatcher IsDefinition = constructMatcher("isDefinition");
    232   Matcher<Decl> Var =
    233       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
    234   Matcher<Decl> Class =
    235       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
    236   Matcher<Decl> Func =
    237       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
    238   EXPECT_TRUE(matches("int a;", Var));
    239   EXPECT_FALSE(matches("extern int a;", Var));
    240   EXPECT_TRUE(matches("class A {};", Class));
    241   EXPECT_FALSE(matches("class A;", Class));
    242   EXPECT_TRUE(matches("void f(){};", Func));
    243   EXPECT_FALSE(matches("void f();", Func));
    244 
    245   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
    246   Matcher<Decl> RecordDecl = constructMatcher(
    247       "recordDecl", constructMatcher("hasName", StringRef("Foo")),
    248       VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
    249 
    250   EXPECT_TRUE(matches("int Foo;", Anything));
    251   EXPECT_TRUE(matches("class Foo {};", Anything));
    252   EXPECT_TRUE(matches("void Foo(){};", Anything));
    253   EXPECT_FALSE(matches("int Foo;", RecordDecl));
    254   EXPECT_TRUE(matches("class Foo {};", RecordDecl));
    255   EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
    256 
    257   Matcher<Stmt> ConstructExpr = constructMatcher(
    258       "cxxConstructExpr",
    259       constructMatcher(
    260           "hasDeclaration",
    261           constructMatcher(
    262               "cxxMethodDecl",
    263               constructMatcher(
    264                   "ofClass", constructMatcher("hasName", StringRef("Foo"))))))
    265                                     .getTypedMatcher<Stmt>();
    266   EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
    267   EXPECT_TRUE(
    268       matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
    269 }
    270 
    271 TEST_F(RegistryTest, TemplateArgument) {
    272   Matcher<Decl> HasTemplateArgument = constructMatcher(
    273       "classTemplateSpecializationDecl",
    274       constructMatcher(
    275           "hasAnyTemplateArgument",
    276           constructMatcher("refersToType",
    277                            constructMatcher("asString", StringRef("int")))))
    278       .getTypedMatcher<Decl>();
    279   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
    280                       HasTemplateArgument));
    281   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
    282                        HasTemplateArgument));
    283 }
    284 
    285 TEST_F(RegistryTest, TypeTraversal) {
    286   Matcher<Type> M = constructMatcher(
    287       "pointerType",
    288       constructMatcher("pointee", constructMatcher("isConstQualified"),
    289                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
    290   EXPECT_FALSE(matches("int *a;", M));
    291   EXPECT_TRUE(matches("int const *b;", M));
    292 
    293   M = constructMatcher(
    294       "arrayType",
    295       constructMatcher("hasElementType", constructMatcher("builtinType")))
    296       .getTypedMatcher<Type>();
    297   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
    298   EXPECT_TRUE(matches("int b[7];", M));
    299 }
    300 
    301 TEST_F(RegistryTest, CXXCtorInitializer) {
    302   Matcher<Decl> CtorDecl = constructMatcher(
    303       "cxxConstructorDecl",
    304       constructMatcher(
    305           "hasAnyConstructorInitializer",
    306           constructMatcher("forField",
    307                            constructMatcher("hasName", StringRef("foo")))))
    308       .getTypedMatcher<Decl>();
    309   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
    310   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
    311   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
    312 }
    313 
    314 TEST_F(RegistryTest, Adaptative) {
    315   Matcher<Decl> D = constructMatcher(
    316       "recordDecl",
    317       constructMatcher(
    318           "has",
    319           constructMatcher("recordDecl",
    320                            constructMatcher("hasName", StringRef("X")))))
    321       .getTypedMatcher<Decl>();
    322   EXPECT_TRUE(matches("class X {};", D));
    323   EXPECT_TRUE(matches("class Y { class X {}; };", D));
    324   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
    325 
    326   Matcher<Stmt> S = constructMatcher(
    327       "forStmt",
    328       constructMatcher(
    329           "hasDescendant",
    330           constructMatcher("varDecl",
    331                            constructMatcher("hasName", StringRef("X")))))
    332       .getTypedMatcher<Stmt>();
    333   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
    334   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
    335   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
    336   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
    337 
    338   S = constructMatcher(
    339       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
    340       .getTypedMatcher<Stmt>();
    341   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
    342   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
    343 }
    344 
    345 TEST_F(RegistryTest, VariadicOp) {
    346   Matcher<Decl> D = constructMatcher(
    347       "anyOf",
    348       constructMatcher("recordDecl",
    349                        constructMatcher("hasName", StringRef("Foo"))),
    350       constructMatcher("functionDecl",
    351                        constructMatcher("hasName", StringRef("foo"))))
    352       .getTypedMatcher<Decl>();
    353 
    354   EXPECT_TRUE(matches("void foo(){}", D));
    355   EXPECT_TRUE(matches("struct Foo{};", D));
    356   EXPECT_FALSE(matches("int i = 0;", D));
    357 
    358   D = constructMatcher(
    359       "allOf", constructMatcher("recordDecl"),
    360       constructMatcher(
    361           "namedDecl",
    362           constructMatcher("anyOf",
    363                            constructMatcher("hasName", StringRef("Foo")),
    364                            constructMatcher("hasName", StringRef("Bar")))))
    365       .getTypedMatcher<Decl>();
    366 
    367   EXPECT_FALSE(matches("void foo(){}", D));
    368   EXPECT_TRUE(matches("struct Foo{};", D));
    369   EXPECT_FALSE(matches("int i = 0;", D));
    370   EXPECT_TRUE(matches("class Bar{};", D));
    371   EXPECT_FALSE(matches("class OtherBar{};", D));
    372 
    373   D = recordDecl(
    374       has(fieldDecl(hasName("Foo"))),
    375       constructMatcher(
    376           "unless",
    377           constructMatcher("namedDecl",
    378                            constructMatcher("hasName", StringRef("Bar"))))
    379           .getTypedMatcher<Decl>());
    380 
    381   EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
    382   EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
    383 
    384   D = constructMatcher(
    385           "namedDecl", constructMatcher("hasName", StringRef("Foo")),
    386           constructMatcher("unless", constructMatcher("recordDecl")))
    387           .getTypedMatcher<Decl>();
    388   EXPECT_TRUE(matches("void Foo(){}", D));
    389   EXPECT_TRUE(notMatches("struct Foo {};", D));
    390 }
    391 
    392 TEST_F(RegistryTest, Errors) {
    393   // Incorrect argument count.
    394   std::unique_ptr<Diagnostics> Error(new Diagnostics());
    395   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
    396   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
    397             Error->toString());
    398   Error.reset(new Diagnostics());
    399   EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull());
    400   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
    401             Error->toString());
    402   Error.reset(new Diagnostics());
    403   EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
    404   EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
    405             Error->toString());
    406   Error.reset(new Diagnostics());
    407   EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(),
    408                                Error.get()).isNull());
    409   EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
    410             Error->toString());
    411 
    412   // Bad argument type
    413   Error.reset(new Diagnostics());
    414   EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull());
    415   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
    416             "(Actual = String)",
    417             Error->toString());
    418   Error.reset(new Diagnostics());
    419   EXPECT_TRUE(
    420       constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"),
    421                        constructMatcher("parameterCountIs", 3), Error.get())
    422           .isNull());
    423   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
    424             "(Actual = Matcher<FunctionDecl|FunctionProtoType>)",
    425             Error->toString());
    426 
    427   // Bad argument type with variadic.
    428   Error.reset(new Diagnostics());
    429   EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(),
    430                                Error.get()).isNull());
    431   EXPECT_EQ(
    432       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
    433       Error->toString());
    434   Error.reset(new Diagnostics());
    435   EXPECT_TRUE(constructMatcher(
    436       "cxxRecordDecl",
    437       constructMatcher("allOf",
    438                        constructMatcher("isDerivedFrom", StringRef("FOO")),
    439                        constructMatcher("isArrow")),
    440       Error.get()).isNull());
    441   EXPECT_EQ("Incorrect type for arg 1. "
    442             "(Expected = Matcher<CXXRecordDecl>) != "
    443             "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
    444             Error->toString());
    445 }
    446 
    447 TEST_F(RegistryTest, Completion) {
    448   CompVector Comps = getCompletions();
    449   // Overloaded
    450   EXPECT_TRUE(hasCompletion(
    451       Comps, "hasParent(",
    452       "Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...> "
    453       "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
    454   // Variadic.
    455   EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
    456                             "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
    457   // Polymorphic.
    458   EXPECT_TRUE(hasCompletion(
    459       Comps, "hasDescendant(",
    460       "Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> "
    461       "hasDescendant(Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...>)"));
    462 
    463   CompVector WhileComps = getCompletions("whileStmt", 0);
    464 
    465   EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
    466                             "Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
    467   EXPECT_TRUE(hasCompletion(
    468       WhileComps, "hasParent(",
    469       "Matcher<Stmt> "
    470       "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
    471   EXPECT_TRUE(
    472       hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
    473 
    474   EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
    475   EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
    476 
    477   CompVector AllOfWhileComps =
    478       getCompletions("allOf", 0, "whileStmt", 0);
    479   ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
    480   EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
    481                          AllOfWhileComps.begin()));
    482 
    483   CompVector DeclWhileComps =
    484       getCompletions("decl", 0, "whileStmt", 0);
    485   EXPECT_EQ(0u, DeclWhileComps.size());
    486 
    487   CompVector NamedDeclComps = getCompletions("namedDecl", 0);
    488   EXPECT_TRUE(
    489       hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
    490   EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
    491                             "Matcher<NamedDecl> hasName(string)"));
    492 
    493   // Heterogeneous overloads.
    494   Comps = getCompletions("classTemplateSpecializationDecl", 0);
    495   EXPECT_TRUE(hasCompletion(
    496       Comps, "isSameOrDerivedFrom(",
    497       "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
    498 }
    499 
    500 TEST_F(RegistryTest, HasArgs) {
    501   Matcher<Decl> Value = constructMatcher(
    502       "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused")))
    503       .getTypedMatcher<Decl>();
    504   EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
    505   EXPECT_FALSE(matches("struct X {};", Value));
    506 }
    507 
    508 TEST_F(RegistryTest, ParenExpr) {
    509   Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>();
    510   EXPECT_TRUE(matches("int i = (1);", Value));
    511   EXPECT_FALSE(matches("int i = 1;", Value));
    512 }
    513 
    514 } // end anonymous namespace
    515 } // end namespace dynamic
    516 } // end namespace ast_matchers
    517 } // end namespace clang
    518