518 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			518 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===-----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "../ASTMatchersTest.h"
 | |
| #include "clang/ASTMatchers/Dynamic/Registry.h"
 | |
| #include "gtest/gtest.h"
 | |
| #include <vector>
 | |
| 
 | |
| namespace clang {
 | |
| namespace ast_matchers {
 | |
| namespace dynamic {
 | |
| namespace {
 | |
| 
 | |
| using ast_matchers::internal::Matcher;
 | |
| 
 | |
| class RegistryTest : public ::testing::Test {
 | |
| public:
 | |
|   std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
 | |
|   std::vector<ParserValue> Args(const VariantValue &Arg1) {
 | |
|     std::vector<ParserValue> Out(1);
 | |
|     Out[0].Value = Arg1;
 | |
|     return Out;
 | |
|   }
 | |
|   std::vector<ParserValue> Args(const VariantValue &Arg1,
 | |
|                                 const VariantValue &Arg2) {
 | |
|     std::vector<ParserValue> Out(2);
 | |
|     Out[0].Value = Arg1;
 | |
|     Out[1].Value = Arg2;
 | |
|     return Out;
 | |
|   }
 | |
| 
 | |
|   llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
 | |
|     return Registry::lookupMatcherCtor(MatcherName);
 | |
|   }
 | |
| 
 | |
|   VariantMatcher constructMatcher(StringRef MatcherName,
 | |
|                                   Diagnostics *Error = nullptr) {
 | |
|     Diagnostics DummyError;
 | |
|     if (!Error) Error = &DummyError;
 | |
|     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
 | |
|     VariantMatcher Out;
 | |
|     if (Ctor)
 | |
|       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
 | |
|     EXPECT_EQ("", DummyError.toStringFull());
 | |
|     return Out;
 | |
|   }
 | |
| 
 | |
|   VariantMatcher constructMatcher(StringRef MatcherName,
 | |
|                                   const VariantValue &Arg1,
 | |
|                                   Diagnostics *Error = nullptr) {
 | |
|     Diagnostics DummyError;
 | |
|     if (!Error) Error = &DummyError;
 | |
|     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
 | |
|     VariantMatcher Out;
 | |
|     if (Ctor)
 | |
|       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
 | |
|     EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
 | |
|     return Out;
 | |
|   }
 | |
| 
 | |
|   VariantMatcher constructMatcher(StringRef MatcherName,
 | |
|                                   const VariantValue &Arg1,
 | |
|                                   const VariantValue &Arg2,
 | |
|                                   Diagnostics *Error = nullptr) {
 | |
|     Diagnostics DummyError;
 | |
|     if (!Error) Error = &DummyError;
 | |
|     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
 | |
|     VariantMatcher Out;
 | |
|     if (Ctor)
 | |
|       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
 | |
|                                        Error);
 | |
|     EXPECT_EQ("", DummyError.toStringFull());
 | |
|     return Out;
 | |
|   }
 | |
| 
 | |
|   typedef std::vector<MatcherCompletion> CompVector;
 | |
| 
 | |
|   CompVector getCompletions() {
 | |
|     std::vector<std::pair<MatcherCtor, unsigned> > Context;
 | |
|     return Registry::getMatcherCompletions(
 | |
|         Registry::getAcceptedCompletionTypes(Context));
 | |
|   }
 | |
| 
 | |
|   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
 | |
|     std::vector<std::pair<MatcherCtor, unsigned> > Context;
 | |
|     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
 | |
|     if (!Ctor)
 | |
|       return CompVector();
 | |
|     Context.push_back(std::make_pair(*Ctor, ArgNo1));
 | |
|     return Registry::getMatcherCompletions(
 | |
|         Registry::getAcceptedCompletionTypes(Context));
 | |
|   }
 | |
| 
 | |
|   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
 | |
|                             StringRef MatcherName2, unsigned ArgNo2) {
 | |
|     std::vector<std::pair<MatcherCtor, unsigned> > Context;
 | |
|     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
 | |
|     if (!Ctor)
 | |
|       return CompVector();
 | |
|     Context.push_back(std::make_pair(*Ctor, ArgNo1));
 | |
|     Ctor = lookupMatcherCtor(MatcherName2);
 | |
|     if (!Ctor)
 | |
|       return CompVector();
 | |
|     Context.push_back(std::make_pair(*Ctor, ArgNo2));
 | |
|     return Registry::getMatcherCompletions(
 | |
|         Registry::getAcceptedCompletionTypes(Context));
 | |
|   }
 | |
| 
 | |
|   bool hasCompletion(const CompVector &Comps, StringRef TypedText,
 | |
|                      StringRef MatcherDecl = StringRef()) {
 | |
|     for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
 | |
|          ++I) {
 | |
|       if (I->TypedText == TypedText &&
 | |
|           (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
| };
 | |
| 
 | |
| TEST_F(RegistryTest, CanConstructNoArgs) {
 | |
|   Matcher<Stmt> IsArrowValue = constructMatcher(
 | |
|       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
 | |
|   Matcher<Stmt> BoolValue =
 | |
|       constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>();
 | |
| 
 | |
|   const std::string ClassSnippet = "struct Foo { int x; };\n"
 | |
|                                    "Foo *foo = new Foo;\n"
 | |
|                                    "int i = foo->x;\n";
 | |
|   const std::string BoolSnippet = "bool Foo = true;\n";
 | |
| 
 | |
|   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
 | |
|   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
 | |
|   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
 | |
|   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, ConstructWithSimpleArgs) {
 | |
|   Matcher<Decl> Value = constructMatcher(
 | |
|       "namedDecl", constructMatcher("hasName", StringRef("X")))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("class X {};", Value));
 | |
|   EXPECT_FALSE(matches("int x;", Value));
 | |
| 
 | |
|   Value = functionDecl(constructMatcher("parameterCountIs", 2)
 | |
|                            .getTypedMatcher<FunctionDecl>());
 | |
|   EXPECT_TRUE(matches("void foo(int,int);", Value));
 | |
|   EXPECT_FALSE(matches("void foo(int);", Value));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, ConstructWithMatcherArgs) {
 | |
|   Matcher<Decl> HasInitializerSimple = constructMatcher(
 | |
|       "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   Matcher<Decl> HasInitializerComplex = constructMatcher(
 | |
|       "varDecl",
 | |
|       constructMatcher("hasInitializer", constructMatcher("callExpr")))
 | |
|       .getTypedMatcher<Decl>();
 | |
| 
 | |
|   std::string code = "int i;";
 | |
|   EXPECT_FALSE(matches(code, HasInitializerSimple));
 | |
|   EXPECT_FALSE(matches(code, HasInitializerComplex));
 | |
| 
 | |
|   code = "int i = 1;";
 | |
|   EXPECT_TRUE(matches(code, HasInitializerSimple));
 | |
|   EXPECT_FALSE(matches(code, HasInitializerComplex));
 | |
| 
 | |
|   code = "int y(); int i = y();";
 | |
|   EXPECT_TRUE(matches(code, HasInitializerSimple));
 | |
|   EXPECT_TRUE(matches(code, HasInitializerComplex));
 | |
| 
 | |
|   Matcher<Decl> HasParameter =
 | |
|       functionDecl(constructMatcher(
 | |
|           "hasParameter", 1, constructMatcher("hasName", StringRef("x")))
 | |
|                        .getTypedMatcher<FunctionDecl>());
 | |
|   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
 | |
|   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, OverloadedMatchers) {
 | |
|   Matcher<Stmt> CallExpr0 = constructMatcher(
 | |
|       "callExpr",
 | |
|       constructMatcher("callee", constructMatcher("memberExpr",
 | |
|                                                   constructMatcher("isArrow"))))
 | |
|       .getTypedMatcher<Stmt>();
 | |
| 
 | |
|   Matcher<Stmt> CallExpr1 = constructMatcher(
 | |
|       "callExpr",
 | |
|       constructMatcher(
 | |
|           "callee",
 | |
|           constructMatcher("cxxMethodDecl",
 | |
|                            constructMatcher("hasName", StringRef("x")))))
 | |
|       .getTypedMatcher<Stmt>();
 | |
| 
 | |
|   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
 | |
|   EXPECT_FALSE(matches(Code, CallExpr0));
 | |
|   EXPECT_TRUE(matches(Code, CallExpr1));
 | |
| 
 | |
|   Code = "class Z { public: void z() { this->z(); } };";
 | |
|   EXPECT_TRUE(matches(Code, CallExpr0));
 | |
|   EXPECT_FALSE(matches(Code, CallExpr1));
 | |
| 
 | |
|   Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
 | |
|       constructMatcher(
 | |
|           "loc", constructMatcher("asString", StringRef("const double *")))
 | |
|           .getTypedMatcher<TypeLoc>()));
 | |
| 
 | |
|   Matcher<NestedNameSpecifierLoc> NNSL =
 | |
|       constructMatcher(
 | |
|           "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
 | |
|                      specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
 | |
|           .getTypedMatcher<NestedNameSpecifierLoc>();
 | |
| 
 | |
|   Code = "const double * x = 0;";
 | |
|   EXPECT_TRUE(matches(Code, DeclDecl));
 | |
|   EXPECT_FALSE(matches(Code, NNSL));
 | |
| 
 | |
|   Code = "struct A { struct B {}; }; A::B a_b;";
 | |
|   EXPECT_FALSE(matches(Code, DeclDecl));
 | |
|   EXPECT_TRUE(matches(Code, NNSL));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, PolymorphicMatchers) {
 | |
|   const VariantMatcher IsDefinition = constructMatcher("isDefinition");
 | |
|   Matcher<Decl> Var =
 | |
|       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
 | |
|   Matcher<Decl> Class =
 | |
|       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
 | |
|   Matcher<Decl> Func =
 | |
|       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("int a;", Var));
 | |
|   EXPECT_FALSE(matches("extern int a;", Var));
 | |
|   EXPECT_TRUE(matches("class A {};", Class));
 | |
|   EXPECT_FALSE(matches("class A;", Class));
 | |
|   EXPECT_TRUE(matches("void f(){};", Func));
 | |
|   EXPECT_FALSE(matches("void f();", Func));
 | |
| 
 | |
|   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
 | |
|   Matcher<Decl> RecordDecl = constructMatcher(
 | |
|       "recordDecl", constructMatcher("hasName", StringRef("Foo")),
 | |
|       VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
 | |
| 
 | |
|   EXPECT_TRUE(matches("int Foo;", Anything));
 | |
|   EXPECT_TRUE(matches("class Foo {};", Anything));
 | |
|   EXPECT_TRUE(matches("void Foo(){};", Anything));
 | |
|   EXPECT_FALSE(matches("int Foo;", RecordDecl));
 | |
|   EXPECT_TRUE(matches("class Foo {};", RecordDecl));
 | |
|   EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
 | |
| 
 | |
|   Matcher<Stmt> ConstructExpr = constructMatcher(
 | |
|       "cxxConstructExpr",
 | |
|       constructMatcher(
 | |
|           "hasDeclaration",
 | |
|           constructMatcher(
 | |
|               "cxxMethodDecl",
 | |
|               constructMatcher(
 | |
|                   "ofClass", constructMatcher("hasName", StringRef("Foo"))))))
 | |
|                                     .getTypedMatcher<Stmt>();
 | |
|   EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
 | |
|   EXPECT_TRUE(
 | |
|       matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, TemplateArgument) {
 | |
|   Matcher<Decl> HasTemplateArgument = constructMatcher(
 | |
|       "classTemplateSpecializationDecl",
 | |
|       constructMatcher(
 | |
|           "hasAnyTemplateArgument",
 | |
|           constructMatcher("refersToType",
 | |
|                            constructMatcher("asString", StringRef("int")))))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
 | |
|                       HasTemplateArgument));
 | |
|   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
 | |
|                        HasTemplateArgument));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, TypeTraversal) {
 | |
|   Matcher<Type> M = constructMatcher(
 | |
|       "pointerType",
 | |
|       constructMatcher("pointee", constructMatcher("isConstQualified"),
 | |
|                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
 | |
|   EXPECT_FALSE(matches("int *a;", M));
 | |
|   EXPECT_TRUE(matches("int const *b;", M));
 | |
| 
 | |
|   M = constructMatcher(
 | |
|       "arrayType",
 | |
|       constructMatcher("hasElementType", constructMatcher("builtinType")))
 | |
|       .getTypedMatcher<Type>();
 | |
|   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
 | |
|   EXPECT_TRUE(matches("int b[7];", M));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, CXXCtorInitializer) {
 | |
|   Matcher<Decl> CtorDecl = constructMatcher(
 | |
|       "cxxConstructorDecl",
 | |
|       constructMatcher(
 | |
|           "hasAnyConstructorInitializer",
 | |
|           constructMatcher("forField",
 | |
|                            constructMatcher("hasName", StringRef("foo")))))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
 | |
|   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
 | |
|   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, Adaptative) {
 | |
|   Matcher<Decl> D = constructMatcher(
 | |
|       "recordDecl",
 | |
|       constructMatcher(
 | |
|           "has",
 | |
|           constructMatcher("recordDecl",
 | |
|                            constructMatcher("hasName", StringRef("X")))))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("class X {};", D));
 | |
|   EXPECT_TRUE(matches("class Y { class X {}; };", D));
 | |
|   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
 | |
| 
 | |
|   Matcher<Stmt> S = constructMatcher(
 | |
|       "forStmt",
 | |
|       constructMatcher(
 | |
|           "hasDescendant",
 | |
|           constructMatcher("varDecl",
 | |
|                            constructMatcher("hasName", StringRef("X")))))
 | |
|       .getTypedMatcher<Stmt>();
 | |
|   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
 | |
|   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
 | |
|   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
 | |
|   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
 | |
| 
 | |
|   S = constructMatcher(
 | |
|       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
 | |
|       .getTypedMatcher<Stmt>();
 | |
|   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
 | |
|   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, VariadicOp) {
 | |
|   Matcher<Decl> D = constructMatcher(
 | |
|       "anyOf",
 | |
|       constructMatcher("recordDecl",
 | |
|                        constructMatcher("hasName", StringRef("Foo"))),
 | |
|       constructMatcher("functionDecl",
 | |
|                        constructMatcher("hasName", StringRef("foo"))))
 | |
|       .getTypedMatcher<Decl>();
 | |
| 
 | |
|   EXPECT_TRUE(matches("void foo(){}", D));
 | |
|   EXPECT_TRUE(matches("struct Foo{};", D));
 | |
|   EXPECT_FALSE(matches("int i = 0;", D));
 | |
| 
 | |
|   D = constructMatcher(
 | |
|       "allOf", constructMatcher("recordDecl"),
 | |
|       constructMatcher(
 | |
|           "namedDecl",
 | |
|           constructMatcher("anyOf",
 | |
|                            constructMatcher("hasName", StringRef("Foo")),
 | |
|                            constructMatcher("hasName", StringRef("Bar")))))
 | |
|       .getTypedMatcher<Decl>();
 | |
| 
 | |
|   EXPECT_FALSE(matches("void foo(){}", D));
 | |
|   EXPECT_TRUE(matches("struct Foo{};", D));
 | |
|   EXPECT_FALSE(matches("int i = 0;", D));
 | |
|   EXPECT_TRUE(matches("class Bar{};", D));
 | |
|   EXPECT_FALSE(matches("class OtherBar{};", D));
 | |
| 
 | |
|   D = recordDecl(
 | |
|       has(fieldDecl(hasName("Foo"))),
 | |
|       constructMatcher(
 | |
|           "unless",
 | |
|           constructMatcher("namedDecl",
 | |
|                            constructMatcher("hasName", StringRef("Bar"))))
 | |
|           .getTypedMatcher<Decl>());
 | |
| 
 | |
|   EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
 | |
|   EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
 | |
| 
 | |
|   D = constructMatcher(
 | |
|           "namedDecl", constructMatcher("hasName", StringRef("Foo")),
 | |
|           constructMatcher("unless", constructMatcher("recordDecl")))
 | |
|           .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("void Foo(){}", D));
 | |
|   EXPECT_TRUE(notMatches("struct Foo {};", D));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, Errors) {
 | |
|   // Incorrect argument count.
 | |
|   std::unique_ptr<Diagnostics> Error(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
 | |
|             Error->toString());
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
 | |
|             Error->toString());
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
 | |
|             Error->toString());
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(),
 | |
|                                Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
 | |
|             Error->toString());
 | |
| 
 | |
|   // Bad argument type
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
 | |
|             "(Actual = String)",
 | |
|             Error->toString());
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(
 | |
|       constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"),
 | |
|                        constructMatcher("parameterCountIs", 3), Error.get())
 | |
|           .isNull());
 | |
|   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
 | |
|             "(Actual = Matcher<FunctionDecl|FunctionProtoType>)",
 | |
|             Error->toString());
 | |
| 
 | |
|   // Bad argument type with variadic.
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(),
 | |
|                                Error.get()).isNull());
 | |
|   EXPECT_EQ(
 | |
|       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
 | |
|       Error->toString());
 | |
|   Error.reset(new Diagnostics());
 | |
|   EXPECT_TRUE(constructMatcher(
 | |
|       "cxxRecordDecl",
 | |
|       constructMatcher("allOf",
 | |
|                        constructMatcher("isDerivedFrom", StringRef("FOO")),
 | |
|                        constructMatcher("isArrow")),
 | |
|       Error.get()).isNull());
 | |
|   EXPECT_EQ("Incorrect type for arg 1. "
 | |
|             "(Expected = Matcher<CXXRecordDecl>) != "
 | |
|             "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
 | |
|             Error->toString());
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, Completion) {
 | |
|   CompVector Comps = getCompletions();
 | |
|   // Overloaded
 | |
|   EXPECT_TRUE(hasCompletion(
 | |
|       Comps, "hasParent(",
 | |
|       "Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...> "
 | |
|       "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
 | |
|   // Variadic.
 | |
|   EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
 | |
|                             "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
 | |
|   // Polymorphic.
 | |
|   EXPECT_TRUE(hasCompletion(
 | |
|       Comps, "hasDescendant(",
 | |
|       "Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> "
 | |
|       "hasDescendant(Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...>)"));
 | |
| 
 | |
|   CompVector WhileComps = getCompletions("whileStmt", 0);
 | |
| 
 | |
|   EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
 | |
|                             "Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
 | |
|   EXPECT_TRUE(hasCompletion(
 | |
|       WhileComps, "hasParent(",
 | |
|       "Matcher<Stmt> "
 | |
|       "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
 | |
|   EXPECT_TRUE(
 | |
|       hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
 | |
| 
 | |
|   EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
 | |
|   EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
 | |
| 
 | |
|   CompVector AllOfWhileComps =
 | |
|       getCompletions("allOf", 0, "whileStmt", 0);
 | |
|   ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
 | |
|   EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
 | |
|                          AllOfWhileComps.begin()));
 | |
| 
 | |
|   CompVector DeclWhileComps =
 | |
|       getCompletions("decl", 0, "whileStmt", 0);
 | |
|   EXPECT_EQ(0u, DeclWhileComps.size());
 | |
| 
 | |
|   CompVector NamedDeclComps = getCompletions("namedDecl", 0);
 | |
|   EXPECT_TRUE(
 | |
|       hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
 | |
|   EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
 | |
|                             "Matcher<NamedDecl> hasName(string)"));
 | |
| 
 | |
|   // Heterogeneous overloads.
 | |
|   Comps = getCompletions("classTemplateSpecializationDecl", 0);
 | |
|   EXPECT_TRUE(hasCompletion(
 | |
|       Comps, "isSameOrDerivedFrom(",
 | |
|       "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, HasArgs) {
 | |
|   Matcher<Decl> Value = constructMatcher(
 | |
|       "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused")))
 | |
|       .getTypedMatcher<Decl>();
 | |
|   EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
 | |
|   EXPECT_FALSE(matches("struct X {};", Value));
 | |
| }
 | |
| 
 | |
| TEST_F(RegistryTest, ParenExpr) {
 | |
|   Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>();
 | |
|   EXPECT_TRUE(matches("int i = (1);", Value));
 | |
|   EXPECT_FALSE(matches("int i = 1;", Value));
 | |
| }
 | |
| 
 | |
| } // end anonymous namespace
 | |
| } // end namespace dynamic
 | |
| } // end namespace ast_matchers
 | |
| } // end namespace clang
 |