|  | // unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp - AST matcher 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/AST/PrettyPrinter.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  | #include "clang/ASTMatchers/ASTMatchers.h" | 
|  | #include "clang/Tooling/Tooling.h" | 
|  | #include "llvm/ADT/Triple.h" | 
|  | #include "llvm/Support/Host.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace clang { | 
|  | namespace ast_matchers { | 
|  |  | 
|  |  | 
|  | TEST(AllOf, AllOverloadsWork) { | 
|  | const char Program[] = | 
|  | "struct T { };" | 
|  | "int f(int, T*, int, int);" | 
|  | "void g(int x) { T t; f(x, &t, 3, 4); }"; | 
|  | EXPECT_TRUE(matches(Program, | 
|  | callExpr(allOf(callee(functionDecl(hasName("f"))), | 
|  | hasArgument(0, declRefExpr(to(varDecl()))))))); | 
|  | EXPECT_TRUE(matches(Program, | 
|  | callExpr(allOf(callee(functionDecl(hasName("f"))), | 
|  | hasArgument(0, declRefExpr(to(varDecl()))), | 
|  | hasArgument(1, hasType(pointsTo( | 
|  | recordDecl(hasName("T"))))))))); | 
|  | EXPECT_TRUE(matches(Program, | 
|  | callExpr(allOf(callee(functionDecl(hasName("f"))), | 
|  | hasArgument(0, declRefExpr(to(varDecl()))), | 
|  | hasArgument(1, hasType(pointsTo( | 
|  | recordDecl(hasName("T"))))), | 
|  | hasArgument(2, integerLiteral(equals(3))))))); | 
|  | EXPECT_TRUE(matches(Program, | 
|  | callExpr(allOf(callee(functionDecl(hasName("f"))), | 
|  | hasArgument(0, declRefExpr(to(varDecl()))), | 
|  | hasArgument(1, hasType(pointsTo( | 
|  | recordDecl(hasName("T"))))), | 
|  | hasArgument(2, integerLiteral(equals(3))), | 
|  | hasArgument(3, integerLiteral(equals(4))))))); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, MatchHas) { | 
|  | DeclarationMatcher HasClassX = recordDecl(has(recordDecl(hasName("X")))); | 
|  | EXPECT_TRUE(matches("class Y { class X {}; };", HasClassX)); | 
|  | EXPECT_TRUE(matches("class X {};", HasClassX)); | 
|  |  | 
|  | DeclarationMatcher YHasClassX = | 
|  | recordDecl(hasName("Y"), has(recordDecl(hasName("X")))); | 
|  | EXPECT_TRUE(matches("class Y { class X {}; };", YHasClassX)); | 
|  | EXPECT_TRUE(notMatches("class X {};", YHasClassX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class Y { class Z { class X {}; }; };", YHasClassX)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, MatchHasRecursiveAllOf) { | 
|  | DeclarationMatcher Recursive = | 
|  | recordDecl( | 
|  | has(recordDecl( | 
|  | has(recordDecl(hasName("X"))), | 
|  | has(recordDecl(hasName("Y"))), | 
|  | hasName("Z"))), | 
|  | has(recordDecl( | 
|  | has(recordDecl(hasName("A"))), | 
|  | has(recordDecl(hasName("B"))), | 
|  | hasName("C"))), | 
|  | hasName("F")); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "class F {" | 
|  | "  class Z {" | 
|  | "    class X {};" | 
|  | "    class Y {};" | 
|  | "  };" | 
|  | "  class C {" | 
|  | "    class A {};" | 
|  | "    class B {};" | 
|  | "  };" | 
|  | "};", Recursive)); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "class F {" | 
|  | "  class Z {" | 
|  | "    class A {};" | 
|  | "    class X {};" | 
|  | "    class Y {};" | 
|  | "  };" | 
|  | "  class C {" | 
|  | "    class X {};" | 
|  | "    class A {};" | 
|  | "    class B {};" | 
|  | "  };" | 
|  | "};", Recursive)); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "class O1 {" | 
|  | "  class O2 {" | 
|  | "    class F {" | 
|  | "      class Z {" | 
|  | "        class A {};" | 
|  | "        class X {};" | 
|  | "        class Y {};" | 
|  | "      };" | 
|  | "      class C {" | 
|  | "        class X {};" | 
|  | "        class A {};" | 
|  | "        class B {};" | 
|  | "      };" | 
|  | "    };" | 
|  | "  };" | 
|  | "};", Recursive)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { | 
|  | DeclarationMatcher Recursive = | 
|  | recordDecl( | 
|  | anyOf( | 
|  | has(recordDecl( | 
|  | anyOf( | 
|  | has(recordDecl( | 
|  | hasName("X"))), | 
|  | has(recordDecl( | 
|  | hasName("Y"))), | 
|  | hasName("Z")))), | 
|  | has(recordDecl( | 
|  | anyOf( | 
|  | hasName("C"), | 
|  | has(recordDecl( | 
|  | hasName("A"))), | 
|  | has(recordDecl( | 
|  | hasName("B")))))), | 
|  | hasName("F"))); | 
|  |  | 
|  | EXPECT_TRUE(matches("class F {};", Recursive)); | 
|  | EXPECT_TRUE(matches("class Z {};", Recursive)); | 
|  | EXPECT_TRUE(matches("class C {};", Recursive)); | 
|  | EXPECT_TRUE(matches("class M { class N { class X {}; }; };", Recursive)); | 
|  | EXPECT_TRUE(matches("class M { class N { class B {}; }; };", Recursive)); | 
|  | EXPECT_TRUE( | 
|  | matches("class O1 { class O2 {" | 
|  | "  class M { class N { class B {}; }; }; " | 
|  | "}; };", Recursive)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, MatchNot) { | 
|  | DeclarationMatcher NotClassX = | 
|  | cxxRecordDecl( | 
|  | isDerivedFrom("Y"), | 
|  | unless(hasName("X"))); | 
|  | EXPECT_TRUE(notMatches("", NotClassX)); | 
|  | EXPECT_TRUE(notMatches("class Y {};", NotClassX)); | 
|  | EXPECT_TRUE(matches("class Y {}; class Z : public Y {};", NotClassX)); | 
|  | EXPECT_TRUE(notMatches("class Y {}; class X : public Y {};", NotClassX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class Y {}; class Z {}; class X : public Y {};", | 
|  | NotClassX)); | 
|  |  | 
|  | DeclarationMatcher ClassXHasNotClassY = | 
|  | recordDecl( | 
|  | hasName("X"), | 
|  | has(recordDecl(hasName("Z"))), | 
|  | unless( | 
|  | has(recordDecl(hasName("Y"))))); | 
|  | EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY)); | 
|  | EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };", | 
|  | ClassXHasNotClassY)); | 
|  |  | 
|  | DeclarationMatcher NamedNotRecord = | 
|  | namedDecl(hasName("Foo"), unless(recordDecl())); | 
|  | EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord)); | 
|  | EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord)); | 
|  | } | 
|  |  | 
|  | TEST(CastExpression, HasCastKind) { | 
|  | EXPECT_TRUE(matches("char *p = 0;", | 
|  | castExpr(hasCastKind(CK_NullToPointer)))); | 
|  | EXPECT_TRUE(notMatches("char *p = 0;", | 
|  | castExpr(hasCastKind(CK_DerivedToBase)))); | 
|  | EXPECT_TRUE(matches("char *p = 0;", | 
|  | implicitCastExpr(hasCastKind(CK_NullToPointer)))); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, HasDescendant) { | 
|  | DeclarationMatcher ZDescendantClassX = | 
|  | recordDecl( | 
|  | hasDescendant(recordDecl(hasName("X"))), | 
|  | hasName("Z")); | 
|  | EXPECT_TRUE(matches("class Z { class X {}; };", ZDescendantClassX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Z { class Y { class X {}; }; };", ZDescendantClassX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Z { class A { class Y { class X {}; }; }; };", | 
|  | ZDescendantClassX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Z { class A { class B { class Y { class X {}; }; }; }; };", | 
|  | ZDescendantClassX)); | 
|  | EXPECT_TRUE(notMatches("class Z {};", ZDescendantClassX)); | 
|  |  | 
|  | DeclarationMatcher ZDescendantClassXHasClassY = | 
|  | recordDecl( | 
|  | hasDescendant(recordDecl(has(recordDecl(hasName("Y"))), | 
|  | hasName("X"))), | 
|  | hasName("Z")); | 
|  | EXPECT_TRUE(matches("class Z { class X { class Y {}; }; };", | 
|  | ZDescendantClassXHasClassY)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Z { class A { class B { class X { class Y {}; }; }; }; };", | 
|  | ZDescendantClassXHasClassY)); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class Z {" | 
|  | "  class A {" | 
|  | "    class B {" | 
|  | "      class X {" | 
|  | "        class C {" | 
|  | "          class Y {};" | 
|  | "        };" | 
|  | "      };" | 
|  | "    }; " | 
|  | "  };" | 
|  | "};", ZDescendantClassXHasClassY)); | 
|  |  | 
|  | DeclarationMatcher ZDescendantClassXDescendantClassY = | 
|  | recordDecl( | 
|  | hasDescendant(recordDecl(hasDescendant(recordDecl(hasName("Y"))), | 
|  | hasName("X"))), | 
|  | hasName("Z")); | 
|  | EXPECT_TRUE( | 
|  | matches("class Z { class A { class X { class B { class Y {}; }; }; }; };", | 
|  | ZDescendantClassXDescendantClassY)); | 
|  | EXPECT_TRUE(matches( | 
|  | "class Z {" | 
|  | "  class A {" | 
|  | "    class X {" | 
|  | "      class B {" | 
|  | "        class Y {};" | 
|  | "      };" | 
|  | "      class Y {};" | 
|  | "    };" | 
|  | "  };" | 
|  | "};", ZDescendantClassXDescendantClassY)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, HasDescendantMemoization) { | 
|  | DeclarationMatcher CannotMemoize = | 
|  | decl(hasDescendant(typeLoc().bind("x")), has(decl())); | 
|  | EXPECT_TRUE(matches("void f() { int i; }", CannotMemoize)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, HasDescendantMemoizationUsesRestrictKind) { | 
|  | auto Name = hasName("i"); | 
|  | auto VD = internal::Matcher<VarDecl>(Name).dynCastTo<Decl>(); | 
|  | auto RD = internal::Matcher<RecordDecl>(Name).dynCastTo<Decl>(); | 
|  | // Matching VD first should not make a cache hit for RD. | 
|  | EXPECT_TRUE(notMatches("void f() { int i; }", | 
|  | decl(hasDescendant(VD), hasDescendant(RD)))); | 
|  | EXPECT_TRUE(notMatches("void f() { int i; }", | 
|  | decl(hasDescendant(RD), hasDescendant(VD)))); | 
|  | // Not matching RD first should not make a cache hit for VD either. | 
|  | EXPECT_TRUE(matches("void f() { int i; }", | 
|  | decl(anyOf(hasDescendant(RD), hasDescendant(VD))))); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, HasAncestorMemoization) { | 
|  | // This triggers an hasAncestor with a TemplateArgument in the bound nodes. | 
|  | // That node can't be memoized so we have to check for it before trying to put | 
|  | // it on the cache. | 
|  | DeclarationMatcher CannotMemoize = classTemplateSpecializationDecl( | 
|  | hasAnyTemplateArgument(templateArgument().bind("targ")), | 
|  | forEach(fieldDecl(hasAncestor(forStmt())))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("template <typename T> struct S;" | 
|  | "template <> struct S<int>{ int i; int j; };", | 
|  | CannotMemoize)); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, HasAttr) { | 
|  | EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", | 
|  | decl(hasAttr(clang::attr::WarnUnused)))); | 
|  | EXPECT_FALSE(matches("struct X {};", | 
|  | decl(hasAttr(clang::attr::WarnUnused)))); | 
|  | } | 
|  |  | 
|  |  | 
|  | TEST(DeclarationMatcher, MatchAnyOf) { | 
|  | DeclarationMatcher YOrZDerivedFromX = cxxRecordDecl( | 
|  | anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); | 
|  | EXPECT_TRUE(matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); | 
|  | EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X {}; class W : public X {};", YOrZDerivedFromX)); | 
|  | EXPECT_TRUE(notMatches("class Z {};", YOrZDerivedFromX)); | 
|  |  | 
|  | DeclarationMatcher XOrYOrZOrU = | 
|  | recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"))); | 
|  | EXPECT_TRUE(matches("class X {};", XOrYOrZOrU)); | 
|  | EXPECT_TRUE(notMatches("class V {};", XOrYOrZOrU)); | 
|  |  | 
|  | DeclarationMatcher XOrYOrZOrUOrV = | 
|  | recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"), | 
|  | hasName("V"))); | 
|  | EXPECT_TRUE(matches("class X {};", XOrYOrZOrUOrV)); | 
|  | EXPECT_TRUE(matches("class Y {};", XOrYOrZOrUOrV)); | 
|  | EXPECT_TRUE(matches("class Z {};", XOrYOrZOrUOrV)); | 
|  | EXPECT_TRUE(matches("class U {};", XOrYOrZOrUOrV)); | 
|  | EXPECT_TRUE(matches("class V {};", XOrYOrZOrUOrV)); | 
|  | EXPECT_TRUE(notMatches("class A {};", XOrYOrZOrUOrV)); | 
|  |  | 
|  | StatementMatcher MixedTypes = stmt(anyOf(ifStmt(), binaryOperator())); | 
|  | EXPECT_TRUE(matches("int F() { return 1 + 2; }", MixedTypes)); | 
|  | EXPECT_TRUE(matches("int F() { if (true) return 1; }", MixedTypes)); | 
|  | EXPECT_TRUE(notMatches("int F() { return 1; }", MixedTypes)); | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | matches("void f() try { } catch (int) { } catch (...) { }", | 
|  | cxxCatchStmt(anyOf(hasDescendant(varDecl()), isCatchAll())))); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, ClassIsDerived) { | 
|  | DeclarationMatcher IsDerivedFromX = cxxRecordDecl(isDerivedFrom("X")); | 
|  |  | 
|  | EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX)); | 
|  | EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX)); | 
|  | EXPECT_TRUE(notMatches("class X;", IsDerivedFromX)); | 
|  | EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX)); | 
|  | EXPECT_TRUE(notMatches("", IsDerivedFromX)); | 
|  |  | 
|  | DeclarationMatcher IsAX = cxxRecordDecl(isSameOrDerivedFrom("X")); | 
|  |  | 
|  | EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX)); | 
|  | EXPECT_TRUE(matches("class X {};", IsAX)); | 
|  | EXPECT_TRUE(matches("class X;", IsAX)); | 
|  | EXPECT_TRUE(notMatches("class Y;", IsAX)); | 
|  | EXPECT_TRUE(notMatches("", IsAX)); | 
|  |  | 
|  | DeclarationMatcher ZIsDerivedFromX = | 
|  | cxxRecordDecl(hasName("Z"), isDerivedFrom("X")); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; class Y : public X {}; class Z : public Y {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {};" | 
|  | "template<class T> class Y : public X {};" | 
|  | "class Z : public Y<int> {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE(matches("class X {}; template<class T> class Z : public X {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class T> class X {}; " | 
|  | "template<class T> class Z : public X<T> {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class T, class U=T> class X {}; " | 
|  | "template<class T> class Z : public X<T> {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<class X> class A { class Z : public X {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class X> class A { public: class Z : public X {}; }; " | 
|  | "class X{}; void y() { A<X>::Z z; }", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template <class T> class X {}; " | 
|  | "template<class Y> class A { class Z : public X<Y> {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<template<class T> class X> class A { " | 
|  | "  class Z : public X<int> {}; };", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<template<class T> class X> class A { " | 
|  | "  public: class Z : public X<int> {}; }; " | 
|  | "template<class T> class X {}; void y() { A<X>::Z z; }", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<class X> class A { class Z : public X::D {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class X> class A { public: " | 
|  | "  class Z : public X::D {}; }; " | 
|  | "class Y { public: class X {}; typedef X D; }; " | 
|  | "void y() { A<Y>::Z z; }", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; typedef X Y; class Z : public Y {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class T> class Y { typedef typename T::U X; " | 
|  | "  class Z : public X {}; };", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE(matches("class X {}; class Z : public ::X {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<class T> class X {}; " | 
|  | "template<class T> class A { class Z : public X<T>::D {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class T> class X { public: typedef X<T> D; }; " | 
|  | "template<class T> class A { public: " | 
|  | "  class Z : public X<T>::D {}; }; void y() { A<int>::Z z; }", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<class X> class A { class Z : public X::D::E {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; typedef X V; typedef V W; class Z : public W {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; class Y : public X {}; " | 
|  | "typedef Y V; typedef V W; class Z : public W {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template<class T, class U> class X {}; " | 
|  | "template<class T> class A { class Z : public X<T, int> {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<class X> class D { typedef X A; typedef A B; " | 
|  | "  typedef B C; class Z : public C {}; };", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; typedef X A; typedef A B; " | 
|  | "class Z : public B {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; typedef X A; typedef A B; typedef B C; " | 
|  | "class Z : public C {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class U {}; typedef U X; typedef X V; " | 
|  | "class Z : public V {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Base {}; typedef Base X; " | 
|  | "class Z : public Base {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class Base {}; typedef Base Base2; typedef Base2 X; " | 
|  | "class Z : public Base {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class Base {}; class Base2 {}; typedef Base2 X; " | 
|  | "class Z : public Base {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class A {}; typedef A X; typedef A Y; " | 
|  | "class Z : public Y {};", ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template <typename T> class Z;" | 
|  | "template <> class Z<void> {};" | 
|  | "template <typename T> class Z : public Z<void> {};", | 
|  | IsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | matches("template <typename T> class X;" | 
|  | "template <> class X<void> {};" | 
|  | "template <typename T> class X : public X<void> {};", | 
|  | IsDerivedFromX)); | 
|  | EXPECT_TRUE(matches( | 
|  | "class X {};" | 
|  | "template <typename T> class Z;" | 
|  | "template <> class Z<void> {};" | 
|  | "template <typename T> class Z : public Z<void>, public X {};", | 
|  | ZIsDerivedFromX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<int> struct X;" | 
|  | "template<int i> struct X : public X<i-1> {};", | 
|  | cxxRecordDecl(isDerivedFrom(recordDecl(hasName("Some")))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "struct A {};" | 
|  | "template<int> struct X;" | 
|  | "template<int i> struct X : public X<i-1> {};" | 
|  | "template<> struct X<0> : public A {};" | 
|  | "struct B : public X<42> {};", | 
|  | cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A")))))); | 
|  |  | 
|  | // FIXME: Once we have better matchers for template type matching, | 
|  | // get rid of the Variable(...) matching and match the right template | 
|  | // declarations directly. | 
|  | const char *RecursiveTemplateOneParameter = | 
|  | "class Base1 {}; class Base2 {};" | 
|  | "template <typename T> class Z;" | 
|  | "template <> class Z<void> : public Base1 {};" | 
|  | "template <> class Z<int> : public Base2 {};" | 
|  | "template <> class Z<float> : public Z<void> {};" | 
|  | "template <> class Z<double> : public Z<int> {};" | 
|  | "template <typename T> class Z : public Z<float>, public Z<double> {};" | 
|  | "void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }"; | 
|  | EXPECT_TRUE(matches( | 
|  | RecursiveTemplateOneParameter, | 
|  | varDecl(hasName("z_float"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | RecursiveTemplateOneParameter, | 
|  | varDecl(hasName("z_float"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); | 
|  | EXPECT_TRUE(matches( | 
|  | RecursiveTemplateOneParameter, | 
|  | varDecl(hasName("z_char"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), | 
|  | isDerivedFrom("Base2"))))))); | 
|  |  | 
|  | const char *RecursiveTemplateTwoParameters = | 
|  | "class Base1 {}; class Base2 {};" | 
|  | "template <typename T1, typename T2> class Z;" | 
|  | "template <typename T> class Z<void, T> : public Base1 {};" | 
|  | "template <typename T> class Z<int, T> : public Base2 {};" | 
|  | "template <typename T> class Z<float, T> : public Z<void, T> {};" | 
|  | "template <typename T> class Z<double, T> : public Z<int, T> {};" | 
|  | "template <typename T1, typename T2> class Z : " | 
|  | "    public Z<float, T2>, public Z<double, T2> {};" | 
|  | "void f() { Z<float, void> z_float; Z<double, void> z_double; " | 
|  | "           Z<char, void> z_char; }"; | 
|  | EXPECT_TRUE(matches( | 
|  | RecursiveTemplateTwoParameters, | 
|  | varDecl(hasName("z_float"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | RecursiveTemplateTwoParameters, | 
|  | varDecl(hasName("z_float"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); | 
|  | EXPECT_TRUE(matches( | 
|  | RecursiveTemplateTwoParameters, | 
|  | varDecl(hasName("z_char"), | 
|  | hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), | 
|  | isDerivedFrom("Base2"))))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "namespace ns { class X {}; class Y : public X {}; }", | 
|  | cxxRecordDecl(isDerivedFrom("::ns::X")))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class X {}; class Y : public X {};", | 
|  | cxxRecordDecl(isDerivedFrom("::ns::X")))); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "class X {}; class Y : public X {};", | 
|  | cxxRecordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "template<typename T> class X {};" | 
|  | "template<typename T> using Z = X<T>;" | 
|  | "template <typename T> class Y : Z<T> {};", | 
|  | cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X")))))); | 
|  | } | 
|  |  | 
|  | TEST(DeclarationMatcher, IsLambda) { | 
|  | const auto IsLambda = cxxMethodDecl(ofClass(cxxRecordDecl(isLambda()))); | 
|  | EXPECT_TRUE(matches("auto x = []{};", IsLambda)); | 
|  | EXPECT_TRUE(notMatches("struct S { void operator()() const; };", IsLambda)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, BindMatchedNodes) { | 
|  | DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x")); | 
|  |  | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue("class X {};", | 
|  | ClassX, llvm::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("x"))); | 
|  |  | 
|  | EXPECT_TRUE(matchAndVerifyResultFalse("class X {};", | 
|  | ClassX, llvm::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("other-id"))); | 
|  |  | 
|  | TypeMatcher TypeAHasClassB = hasDeclaration( | 
|  | recordDecl(hasName("A"), has(recordDecl(hasName("B")).bind("b")))); | 
|  |  | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };", | 
|  | TypeAHasClassB, | 
|  | llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b"))); | 
|  |  | 
|  | StatementMatcher MethodX = | 
|  | callExpr(callee(cxxMethodDecl(hasName("x")))).bind("x"); | 
|  |  | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };", | 
|  | MethodX, | 
|  | llvm::make_unique<VerifyIdIsBoundTo<CXXMemberCallExpr>>("x"))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, BindTheSameNameInAlternatives) { | 
|  | StatementMatcher matcher = anyOf( | 
|  | binaryOperator(hasOperatorName("+"), | 
|  | hasLHS(expr().bind("x")), | 
|  | hasRHS(integerLiteral(equals(0)))), | 
|  | binaryOperator(hasOperatorName("+"), | 
|  | hasLHS(integerLiteral(equals(0))), | 
|  | hasRHS(expr().bind("x")))); | 
|  |  | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | // The first branch of the matcher binds x to 0 but then fails. | 
|  | // The second branch binds x to f() and succeeds. | 
|  | "int f() { return 0 + f(); }", | 
|  | matcher, | 
|  | llvm::make_unique<VerifyIdIsBoundTo<CallExpr>>("x"))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, BindsIDForMemoizedResults) { | 
|  | // Using the same matcher in two match expressions will make memoization | 
|  | // kick in. | 
|  | DeclarationMatcher ClassX = recordDecl(hasName("X")).bind("x"); | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "class A { class B { class X {}; }; };", | 
|  | DeclarationMatcher(anyOf( | 
|  | recordDecl(hasName("A"), hasDescendant(ClassX)), | 
|  | recordDecl(hasName("B"), hasDescendant(ClassX)))), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<Decl>>("x", 2))); | 
|  | } | 
|  |  | 
|  | TEST(HasType, MatchesAsString) { | 
|  | EXPECT_TRUE( | 
|  | matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }", | 
|  | cxxMemberCallExpr(on(hasType(asString("class Y *")))))); | 
|  | EXPECT_TRUE( | 
|  | matches("class X { void x(int x) {} };", | 
|  | cxxMethodDecl(hasParameter(0, hasType(asString("int")))))); | 
|  | EXPECT_TRUE(matches("namespace ns { struct A {}; }  struct B { ns::A a; };", | 
|  | fieldDecl(hasType(asString("ns::A"))))); | 
|  | EXPECT_TRUE(matches("namespace { struct A {}; }  struct B { A a; };", | 
|  | fieldDecl(hasType(asString("struct (anonymous namespace)::A"))))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { | 
|  | StatementMatcher OpCallAndAnd = | 
|  | cxxOperatorCallExpr(hasOverloadedOperatorName("&&")); | 
|  | EXPECT_TRUE(matches("class Y { }; " | 
|  | "bool operator&&(Y x, Y y) { return true; }; " | 
|  | "Y a; Y b; bool c = a && b;", OpCallAndAnd)); | 
|  | StatementMatcher OpCallLessLess = | 
|  | cxxOperatorCallExpr(hasOverloadedOperatorName("<<")); | 
|  | EXPECT_TRUE(notMatches("class Y { }; " | 
|  | "bool operator&&(Y x, Y y) { return true; }; " | 
|  | "Y a; Y b; bool c = a && b;", | 
|  | OpCallLessLess)); | 
|  | StatementMatcher OpStarCall = | 
|  | cxxOperatorCallExpr(hasOverloadedOperatorName("*")); | 
|  | EXPECT_TRUE(matches("class Y; int operator*(Y &); void f(Y &y) { *y; }", | 
|  | OpStarCall)); | 
|  | DeclarationMatcher ClassWithOpStar = | 
|  | cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))); | 
|  | EXPECT_TRUE(matches("class Y { int operator*(); };", | 
|  | ClassWithOpStar)); | 
|  | EXPECT_TRUE(notMatches("class Y { void myOperator(); };", | 
|  | ClassWithOpStar)) ; | 
|  | DeclarationMatcher AnyOpStar = functionDecl(hasOverloadedOperatorName("*")); | 
|  | EXPECT_TRUE(matches("class Y; int operator*(Y &);", AnyOpStar)); | 
|  | EXPECT_TRUE(matches("class Y { int operator*(); };", AnyOpStar)); | 
|  | } | 
|  |  | 
|  |  | 
|  | TEST(Matcher, NestedOverloadedOperatorCalls) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "class Y { }; " | 
|  | "Y& operator&&(Y& x, Y& y) { return x; }; " | 
|  | "Y a; Y b; Y c; Y d = a && b && c;", | 
|  | cxxOperatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<CXXOperatorCallExpr>>("x", 2))); | 
|  | EXPECT_TRUE(matches("class Y { }; " | 
|  | "Y& operator&&(Y& x, Y& y) { return x; }; " | 
|  | "Y a; Y b; Y c; Y d = a && b && c;", | 
|  | cxxOperatorCallExpr(hasParent(cxxOperatorCallExpr())))); | 
|  | EXPECT_TRUE( | 
|  | matches("class Y { }; " | 
|  | "Y& operator&&(Y& x, Y& y) { return x; }; " | 
|  | "Y a; Y b; Y c; Y d = a && b && c;", | 
|  | cxxOperatorCallExpr(hasDescendant(cxxOperatorCallExpr())))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, VarDecl_Storage) { | 
|  | auto M = varDecl(hasName("X"), hasLocalStorage()); | 
|  | EXPECT_TRUE(matches("void f() { int X; }", M)); | 
|  | EXPECT_TRUE(notMatches("int X;", M)); | 
|  | EXPECT_TRUE(notMatches("void f() { static int X; }", M)); | 
|  |  | 
|  | M = varDecl(hasName("X"), hasGlobalStorage()); | 
|  | EXPECT_TRUE(notMatches("void f() { int X; }", M)); | 
|  | EXPECT_TRUE(matches("int X;", M)); | 
|  | EXPECT_TRUE(matches("void f() { static int X; }", M)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, VarDecl_StorageDuration) { | 
|  | std::string T = | 
|  | "void f() { int x; static int y; } int a;"; | 
|  |  | 
|  | EXPECT_TRUE(matches(T, varDecl(hasName("x"), hasAutomaticStorageDuration()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches(T, varDecl(hasName("y"), hasAutomaticStorageDuration()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches(T, varDecl(hasName("a"), hasAutomaticStorageDuration()))); | 
|  |  | 
|  | EXPECT_TRUE(matches(T, varDecl(hasName("y"), hasStaticStorageDuration()))); | 
|  | EXPECT_TRUE(matches(T, varDecl(hasName("a"), hasStaticStorageDuration()))); | 
|  | EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasStaticStorageDuration()))); | 
|  |  | 
|  | // FIXME: It is really hard to test with thread_local itself because not all | 
|  | // targets support TLS, which causes this to be an error depending on what | 
|  | // platform the test is being run on. We do not have access to the TargetInfo | 
|  | // object to be able to test whether the platform supports TLS or not. | 
|  | EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasThreadStorageDuration()))); | 
|  | EXPECT_TRUE(notMatches(T, varDecl(hasName("y"), hasThreadStorageDuration()))); | 
|  | EXPECT_TRUE(notMatches(T, varDecl(hasName("a"), hasThreadStorageDuration()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, FindsVarDeclInFunctionParameter) { | 
|  | EXPECT_TRUE(matches( | 
|  | "void f(int i) {}", | 
|  | varDecl(hasName("i")))); | 
|  | } | 
|  |  | 
|  | TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) { | 
|  | EXPECT_TRUE(matches("void x() { int a = sizeof(a); }", sizeOfExpr( | 
|  | hasArgumentOfType(asString("int"))))); | 
|  | EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr( | 
|  | hasArgumentOfType(asString("float"))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "struct A {}; void x() { A a; int b = sizeof(a); }", | 
|  | sizeOfExpr(hasArgumentOfType(hasDeclaration(recordDecl(hasName("A"))))))); | 
|  | EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr( | 
|  | hasArgumentOfType(hasDeclaration(recordDecl(hasName("string"))))))); | 
|  | } | 
|  |  | 
|  | TEST(IsInteger, MatchesIntegers) { | 
|  | EXPECT_TRUE(matches("int i = 0;", varDecl(hasType(isInteger())))); | 
|  | EXPECT_TRUE(matches( | 
|  | "long long i = 0; void f(long long) { }; void g() {f(i);}", | 
|  | callExpr(hasArgument(0, declRefExpr( | 
|  | to(varDecl(hasType(isInteger())))))))); | 
|  | } | 
|  |  | 
|  | TEST(IsInteger, ReportsNoFalsePositives) { | 
|  | EXPECT_TRUE(notMatches("int *i;", varDecl(hasType(isInteger())))); | 
|  | EXPECT_TRUE(notMatches("struct T {}; T t; void f(T *) { }; void g() {f(&t);}", | 
|  | callExpr(hasArgument(0, declRefExpr( | 
|  | to(varDecl(hasType(isInteger())))))))); | 
|  | } | 
|  |  | 
|  | TEST(IsSignedInteger, MatchesSignedIntegers) { | 
|  | EXPECT_TRUE(matches("int i = 0;", varDecl(hasType(isSignedInteger())))); | 
|  | EXPECT_TRUE(notMatches("unsigned i = 0;", | 
|  | varDecl(hasType(isSignedInteger())))); | 
|  | } | 
|  |  | 
|  | TEST(IsUnsignedInteger, MatchesUnsignedIntegers) { | 
|  | EXPECT_TRUE(notMatches("int i = 0;", varDecl(hasType(isUnsignedInteger())))); | 
|  | EXPECT_TRUE(matches("unsigned i = 0;", | 
|  | varDecl(hasType(isUnsignedInteger())))); | 
|  | } | 
|  |  | 
|  | TEST(IsAnyPointer, MatchesPointers) { | 
|  | EXPECT_TRUE(matches("int* i = nullptr;", varDecl(hasType(isAnyPointer())))); | 
|  | } | 
|  |  | 
|  | TEST(IsAnyPointer, MatchesObjcPointer) { | 
|  | EXPECT_TRUE(matchesObjC("@interface Foo @end Foo *f;", | 
|  | varDecl(hasType(isAnyPointer())))); | 
|  | } | 
|  |  | 
|  | TEST(IsAnyPointer, ReportsNoFalsePositives) { | 
|  | EXPECT_TRUE(notMatches("int i = 0;", varDecl(hasType(isAnyPointer())))); | 
|  | } | 
|  |  | 
|  | TEST(IsAnyCharacter, MatchesCharacters) { | 
|  | EXPECT_TRUE(matches("char i = 0;", varDecl(hasType(isAnyCharacter())))); | 
|  | } | 
|  |  | 
|  | TEST(IsAnyCharacter, ReportsNoFalsePositives) { | 
|  | EXPECT_TRUE(notMatches("int i;", varDecl(hasType(isAnyCharacter())))); | 
|  | } | 
|  |  | 
|  | TEST(IsArrow, MatchesMemberVariablesViaArrow) { | 
|  | EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(matches("class Y { void x() { y; } int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | } | 
|  |  | 
|  | TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) { | 
|  | EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } static int y; };", | 
|  | memberExpr(isArrow()))); | 
|  | } | 
|  |  | 
|  | TEST(IsArrow, MatchesMemberCallsViaArrow) { | 
|  | EXPECT_TRUE(matches("class Y { void x() { this->x(); } };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(matches("class Y { void x() { x(); } };", | 
|  | memberExpr(isArrow()))); | 
|  | EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };", | 
|  | memberExpr(isArrow()))); | 
|  | } | 
|  |  | 
|  | TEST(ConversionDeclaration, IsExplicit) { | 
|  | EXPECT_TRUE(matches("struct S { explicit operator int(); };", | 
|  | cxxConversionDecl(isExplicit()))); | 
|  | EXPECT_TRUE(notMatches("struct S { operator int(); };", | 
|  | cxxConversionDecl(isExplicit()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, ArgumentCount) { | 
|  | StatementMatcher Call1Arg = callExpr(argumentCountIs(1)); | 
|  |  | 
|  | EXPECT_TRUE(matches("void x(int) { x(0); }", Call1Arg)); | 
|  | EXPECT_TRUE(matches("class X { void x(int) { x(0); } };", Call1Arg)); | 
|  | EXPECT_TRUE(notMatches("void x(int, int) { x(0, 0); }", Call1Arg)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, ParameterCount) { | 
|  | DeclarationMatcher Function1Arg = functionDecl(parameterCountIs(1)); | 
|  | EXPECT_TRUE(matches("void f(int i) {}", Function1Arg)); | 
|  | EXPECT_TRUE(matches("class X { void f(int i) {} };", Function1Arg)); | 
|  | EXPECT_TRUE(notMatches("void f() {}", Function1Arg)); | 
|  | EXPECT_TRUE(notMatches("void f(int i, int j, int k) {}", Function1Arg)); | 
|  | EXPECT_TRUE(matches("void f(int i, ...) {};", Function1Arg)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, References) { | 
|  | DeclarationMatcher ReferenceClassX = varDecl( | 
|  | hasType(references(recordDecl(hasName("X"))))); | 
|  | EXPECT_TRUE(matches("class X {}; void y(X y) { X &x = y; }", | 
|  | ReferenceClassX)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX)); | 
|  | // The match here is on the implicit copy constructor code for | 
|  | // class X, not on code 'X x = y'. | 
|  | EXPECT_TRUE( | 
|  | matches("class X {}; void y(X y) { X x = y; }", ReferenceClassX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X {}; extern X x;", ReferenceClassX)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX)); | 
|  | } | 
|  |  | 
|  | TEST(QualType, hasLocalQualifiers) { | 
|  | EXPECT_TRUE(notMatches("typedef const int const_int; const_int i = 1;", | 
|  | varDecl(hasType(hasLocalQualifiers())))); | 
|  | EXPECT_TRUE(matches("int *const j = nullptr;", | 
|  | varDecl(hasType(hasLocalQualifiers())))); | 
|  | EXPECT_TRUE(matches("int *volatile k;", | 
|  | varDecl(hasType(hasLocalQualifiers())))); | 
|  | EXPECT_TRUE(notMatches("int m;", | 
|  | varDecl(hasType(hasLocalQualifiers())))); | 
|  | } | 
|  |  | 
|  | TEST(IsExternC, MatchesExternCFunctionDeclarations) { | 
|  | EXPECT_TRUE(matches("extern \"C\" void f() {}", functionDecl(isExternC()))); | 
|  | EXPECT_TRUE(matches("extern \"C\" { void f() {} }", | 
|  | functionDecl(isExternC()))); | 
|  | EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC()))); | 
|  | } | 
|  |  | 
|  | TEST(IsExternC, MatchesExternCVariableDeclarations) { | 
|  | EXPECT_TRUE(matches("extern \"C\" int i;", varDecl(isExternC()))); | 
|  | EXPECT_TRUE(matches("extern \"C\" { int i; }", varDecl(isExternC()))); | 
|  | EXPECT_TRUE(notMatches("int i;", varDecl(isExternC()))); | 
|  | } | 
|  |  | 
|  | TEST(IsDefaulted, MatchesDefaultedFunctionDeclarations) { | 
|  | EXPECT_TRUE(notMatches("class A { ~A(); };", | 
|  | functionDecl(hasName("~A"), isDefaulted()))); | 
|  | EXPECT_TRUE(matches("class B { ~B() = default; };", | 
|  | functionDecl(hasName("~B"), isDefaulted()))); | 
|  | } | 
|  |  | 
|  | TEST(IsDeleted, MatchesDeletedFunctionDeclarations) { | 
|  | EXPECT_TRUE( | 
|  | notMatches("void Func();", functionDecl(hasName("Func"), isDeleted()))); | 
|  | EXPECT_TRUE(matches("void Func() = delete;", | 
|  | functionDecl(hasName("Func"), isDeleted()))); | 
|  | } | 
|  |  | 
|  | TEST(IsNoThrow, MatchesNoThrowFunctionDeclarations) { | 
|  | EXPECT_TRUE(notMatches("void f();", functionDecl(isNoThrow()))); | 
|  | EXPECT_TRUE(notMatches("void f() throw(int);", functionDecl(isNoThrow()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("void f() noexcept(false);", functionDecl(isNoThrow()))); | 
|  | EXPECT_TRUE(matches("void f() throw();", functionDecl(isNoThrow()))); | 
|  | EXPECT_TRUE(matches("void f() noexcept;", functionDecl(isNoThrow()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("void f();", functionProtoType(isNoThrow()))); | 
|  | EXPECT_TRUE(notMatches("void f() throw(int);", functionProtoType(isNoThrow()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("void f() noexcept(false);", functionProtoType(isNoThrow()))); | 
|  | EXPECT_TRUE(matches("void f() throw();", functionProtoType(isNoThrow()))); | 
|  | EXPECT_TRUE(matches("void f() noexcept;", functionProtoType(isNoThrow()))); | 
|  | } | 
|  |  | 
|  | TEST(isConstexpr, MatchesConstexprDeclarations) { | 
|  | EXPECT_TRUE(matches("constexpr int foo = 42;", | 
|  | varDecl(hasName("foo"), isConstexpr()))); | 
|  | EXPECT_TRUE(matches("constexpr int bar();", | 
|  | functionDecl(hasName("bar"), isConstexpr()))); | 
|  | } | 
|  |  | 
|  | TEST(TemplateArgumentCountIs, Matches) { | 
|  | EXPECT_TRUE( | 
|  | matches("template<typename T> struct C {}; C<int> c;", | 
|  | classTemplateSpecializationDecl(templateArgumentCountIs(1)))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<typename T> struct C {}; C<int> c;", | 
|  | classTemplateSpecializationDecl(templateArgumentCountIs(2)))); | 
|  |  | 
|  | EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", | 
|  | templateSpecializationType(templateArgumentCountIs(1)))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("template<typename T> struct C {}; C<int> c;", | 
|  | templateSpecializationType(templateArgumentCountIs(2)))); | 
|  | } | 
|  |  | 
|  | TEST(IsIntegral, Matches) { | 
|  | EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", | 
|  | classTemplateSpecializationDecl( | 
|  | hasAnyTemplateArgument(isIntegral())))); | 
|  | EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;", | 
|  | classTemplateSpecializationDecl(hasAnyTemplateArgument( | 
|  | templateArgument(isIntegral()))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsIntegralValue, Matches) { | 
|  | EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", | 
|  | classTemplateSpecializationDecl( | 
|  | hasAnyTemplateArgument(equalsIntegralValue("42"))))); | 
|  | EXPECT_TRUE(matches("template<int T> struct C {}; C<-42> c;", | 
|  | classTemplateSpecializationDecl( | 
|  | hasAnyTemplateArgument(equalsIntegralValue("-42"))))); | 
|  | EXPECT_TRUE(matches("template<int T> struct C {}; C<-0042> c;", | 
|  | classTemplateSpecializationDecl( | 
|  | hasAnyTemplateArgument(equalsIntegralValue("-34"))))); | 
|  | EXPECT_TRUE(notMatches("template<int T> struct C {}; C<42> c;", | 
|  | classTemplateSpecializationDecl(hasAnyTemplateArgument( | 
|  | equalsIntegralValue("0042"))))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesAccessSpecDecls) { | 
|  | EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl())); | 
|  | EXPECT_TRUE( | 
|  | matches("class C { public: int i; };", accessSpecDecl(isPublic()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class C { public: int i; };", accessSpecDecl(isProtected()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class C { public: int i; };", accessSpecDecl(isPrivate()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("class C { int i; };", accessSpecDecl())); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesFinal) { | 
|  | EXPECT_TRUE(matches("class X final {};", cxxRecordDecl(isFinal()))); | 
|  | EXPECT_TRUE(matches("class X { virtual void f() final; };", | 
|  | cxxMethodDecl(isFinal()))); | 
|  | EXPECT_TRUE(notMatches("class X {};", cxxRecordDecl(isFinal()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X { virtual void f(); };", cxxMethodDecl(isFinal()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesVirtualMethod) { | 
|  | EXPECT_TRUE(matches("class X { virtual int f(); };", | 
|  | cxxMethodDecl(isVirtual(), hasName("::X::f")))); | 
|  | EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(isVirtual()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesVirtualAsWrittenMethod) { | 
|  | EXPECT_TRUE(matches("class A { virtual int f(); };" | 
|  | "class B : public A { int f(); };", | 
|  | cxxMethodDecl(isVirtualAsWritten(), hasName("::A::f")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { virtual int f(); };" | 
|  | "class B : public A { int f(); };", | 
|  | cxxMethodDecl(isVirtualAsWritten(), hasName("::B::f")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesPureMethod) { | 
|  | EXPECT_TRUE(matches("class X { virtual int f() = 0; };", | 
|  | cxxMethodDecl(isPure(), hasName("::X::f")))); | 
|  | EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(isPure()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesCopyAssignmentOperator) { | 
|  | EXPECT_TRUE(matches("class X { X &operator=(X); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(X &); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(const X &); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(volatile X &); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(const volatile X &); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | EXPECT_TRUE(notMatches("class X { X &operator=(X &&); };", | 
|  | cxxMethodDecl(isCopyAssignmentOperator()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesMoveAssignmentOperator) { | 
|  | EXPECT_TRUE(notMatches("class X { X &operator=(X); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(X &&); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(const X &&); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(volatile X &&); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | EXPECT_TRUE(matches("class X { X &operator=(const volatile X &&); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | EXPECT_TRUE(notMatches("class X { X &operator=(X &); };", | 
|  | cxxMethodDecl(isMoveAssignmentOperator()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesConstMethod) { | 
|  | EXPECT_TRUE( | 
|  | matches("struct A { void foo() const; };", cxxMethodDecl(isConst()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("struct A { void foo(); };", cxxMethodDecl(isConst()))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, MatchesOverridingMethod) { | 
|  | EXPECT_TRUE(matches("class X { virtual int f(); }; " | 
|  | "class Y : public X { int f(); };", | 
|  | cxxMethodDecl(isOverride(), hasName("::Y::f")))); | 
|  | EXPECT_TRUE(notMatches("class X { virtual int f(); }; " | 
|  | "class Y : public X { int f(); };", | 
|  | cxxMethodDecl(isOverride(), hasName("::X::f")))); | 
|  | EXPECT_TRUE(notMatches("class X { int f(); }; " | 
|  | "class Y : public X { int f(); };", | 
|  | cxxMethodDecl(isOverride()))); | 
|  | EXPECT_TRUE(notMatches("class X { int f(); int f(int); }; ", | 
|  | cxxMethodDecl(isOverride()))); | 
|  | EXPECT_TRUE( | 
|  | matches("template <typename Base> struct Y : Base { void f() override;};", | 
|  | cxxMethodDecl(isOverride(), hasName("::Y::f")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, ConstructorArgument) { | 
|  | StatementMatcher Constructor = cxxConstructExpr( | 
|  | hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { int y; X x(y); }", | 
|  | Constructor)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { int y; X x = X(y); }", | 
|  | Constructor)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { int y; X x = y; }", | 
|  | Constructor)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X { public: X(int); }; void x() { int z; X x(z); }", | 
|  | Constructor)); | 
|  |  | 
|  | StatementMatcher WrongIndex = cxxConstructExpr( | 
|  | hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X { public: X(int); }; void x() { int y; X x(y); }", | 
|  | WrongIndex)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, ConstructorArgumentCount) { | 
|  | StatementMatcher Constructor1Arg = cxxConstructExpr(argumentCountIs(1)); | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { X x(0); }", | 
|  | Constructor1Arg)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { X x = X(0); }", | 
|  | Constructor1Arg)); | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { X x = 0; }", | 
|  | Constructor1Arg)); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class X { public: X(int, int); }; void x() { X x(0, 0); }", | 
|  | Constructor1Arg)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, ConstructorListInitialization) { | 
|  | StatementMatcher ConstructorListInit = | 
|  | cxxConstructExpr(isListInitialization()); | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | matches("class X { public: X(int); }; void x() { X x{0}; }", | 
|  | ConstructorListInit)); | 
|  | EXPECT_FALSE( | 
|  | matches("class X { public: X(int); }; void x() { X x(0); }", | 
|  | ConstructorListInit)); | 
|  | } | 
|  |  | 
|  | TEST(ConstructorDeclaration, IsImplicit) { | 
|  | // This one doesn't match because the constructor is not added by the | 
|  | // compiler (it is not needed). | 
|  | EXPECT_TRUE(notMatches("class Foo { };", | 
|  | cxxConstructorDecl(isImplicit()))); | 
|  | // The compiler added the implicit default constructor. | 
|  | EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();", | 
|  | cxxConstructorDecl(isImplicit()))); | 
|  | EXPECT_TRUE(matches("class Foo { Foo(){} };", | 
|  | cxxConstructorDecl(unless(isImplicit())))); | 
|  | // The compiler added an implicit assignment operator. | 
|  | EXPECT_TRUE(matches("struct A { int x; } a = {0}, b = a; void f() { a = b; }", | 
|  | cxxMethodDecl(isImplicit(), hasName("operator=")))); | 
|  | } | 
|  |  | 
|  | TEST(ConstructorDeclaration, IsExplicit) { | 
|  | EXPECT_TRUE(matches("struct S { explicit S(int); };", | 
|  | cxxConstructorDecl(isExplicit()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(int); };", | 
|  | cxxConstructorDecl(isExplicit()))); | 
|  | } | 
|  |  | 
|  | TEST(ConstructorDeclaration, Kinds) { | 
|  | EXPECT_TRUE(matches("struct S { S(); };", | 
|  | cxxConstructorDecl(isDefaultConstructor()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(); };", | 
|  | cxxConstructorDecl(isCopyConstructor()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(); };", | 
|  | cxxConstructorDecl(isMoveConstructor()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("struct S { S(const S&); };", | 
|  | cxxConstructorDecl(isDefaultConstructor()))); | 
|  | EXPECT_TRUE(matches("struct S { S(const S&); };", | 
|  | cxxConstructorDecl(isCopyConstructor()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(const S&); };", | 
|  | cxxConstructorDecl(isMoveConstructor()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("struct S { S(S&&); };", | 
|  | cxxConstructorDecl(isDefaultConstructor()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(S&&); };", | 
|  | cxxConstructorDecl(isCopyConstructor()))); | 
|  | EXPECT_TRUE(matches("struct S { S(S&&); };", | 
|  | cxxConstructorDecl(isMoveConstructor()))); | 
|  | } | 
|  |  | 
|  | TEST(ConstructorDeclaration, IsUserProvided) { | 
|  | EXPECT_TRUE(notMatches("struct S { int X = 0; };", | 
|  | cxxConstructorDecl(isUserProvided()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S() = default; };", | 
|  | cxxConstructorDecl(isUserProvided()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S() = delete; };", | 
|  | cxxConstructorDecl(isUserProvided()))); | 
|  | EXPECT_TRUE( | 
|  | matches("struct S { S(); };", cxxConstructorDecl(isUserProvided()))); | 
|  | EXPECT_TRUE(matches("struct S { S(); }; S::S(){}", | 
|  | cxxConstructorDecl(isUserProvided()))); | 
|  | } | 
|  |  | 
|  | TEST(ConstructorDeclaration, IsDelegatingConstructor) { | 
|  | EXPECT_TRUE(notMatches("struct S { S(); S(int); int X; };", | 
|  | cxxConstructorDecl(isDelegatingConstructor()))); | 
|  | EXPECT_TRUE(notMatches("struct S { S(){} S(int X) : X(X) {} int X; };", | 
|  | cxxConstructorDecl(isDelegatingConstructor()))); | 
|  | EXPECT_TRUE(matches( | 
|  | "struct S { S() : S(0) {} S(int X) : X(X) {} int X; };", | 
|  | cxxConstructorDecl(isDelegatingConstructor(), parameterCountIs(0)))); | 
|  | EXPECT_TRUE(matches( | 
|  | "struct S { S(); S(int X); int X; }; S::S(int X) : S() {}", | 
|  | cxxConstructorDecl(isDelegatingConstructor(), parameterCountIs(1)))); | 
|  | } | 
|  |  | 
|  | TEST(StringLiteral, HasSize) { | 
|  | StatementMatcher Literal = stringLiteral(hasSize(4)); | 
|  | EXPECT_TRUE(matches("const char *s = \"abcd\";", Literal)); | 
|  | // wide string | 
|  | EXPECT_TRUE(matches("const wchar_t *s = L\"abcd\";", Literal)); | 
|  | // with escaped characters | 
|  | EXPECT_TRUE(matches("const char *s = \"\x05\x06\x07\x08\";", Literal)); | 
|  | // no matching, too small | 
|  | EXPECT_TRUE(notMatches("const char *s = \"ab\";", Literal)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsNamespaces) { | 
|  | EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("a::b::C")))); | 
|  | EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("::a::b::C")))); | 
|  | EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("b::C")))); | 
|  | EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("c::b::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("a::c::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("a::b::A")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("::b::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("z::a::b::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", | 
|  | recordDecl(hasName("a+b::C")))); | 
|  | EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }", | 
|  | recordDecl(hasName("C")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsOuterClasses) { | 
|  | EXPECT_TRUE( | 
|  | matches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("A::B::C")))); | 
|  | EXPECT_TRUE( | 
|  | matches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("::A::B::C")))); | 
|  | EXPECT_TRUE( | 
|  | matches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("B::C")))); | 
|  | EXPECT_TRUE( | 
|  | matches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("C")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("c::B::C")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("A::c::C")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("A::B::A")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("::C")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("::B::C")))); | 
|  | EXPECT_TRUE(notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("z::A::B::C")))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("class A { class B { class C; }; };", | 
|  | recordDecl(hasName("A+B::C")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsInlinedNamespaces) { | 
|  | std::string code = "namespace a { inline namespace b { class C; } }"; | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("a::b::C")))); | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("a::C")))); | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("::a::b::C")))); | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsAnonymousNamespaces) { | 
|  | std::string code = "namespace a { namespace { class C; } }"; | 
|  | EXPECT_TRUE( | 
|  | matches(code, recordDecl(hasName("a::(anonymous namespace)::C")))); | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("a::C")))); | 
|  | EXPECT_TRUE( | 
|  | matches(code, recordDecl(hasName("::a::(anonymous namespace)::C")))); | 
|  | EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsAnonymousOuterClasses) { | 
|  | EXPECT_TRUE(matches("class A { class { class C; } x; };", | 
|  | recordDecl(hasName("A::(anonymous class)::C")))); | 
|  | EXPECT_TRUE(matches("class A { class { class C; } x; };", | 
|  | recordDecl(hasName("::A::(anonymous class)::C")))); | 
|  | EXPECT_FALSE(matches("class A { class { class C; } x; };", | 
|  | recordDecl(hasName("::A::C")))); | 
|  | EXPECT_TRUE(matches("class A { struct { class C; } x; };", | 
|  | recordDecl(hasName("A::(anonymous struct)::C")))); | 
|  | EXPECT_TRUE(matches("class A { struct { class C; } x; };", | 
|  | recordDecl(hasName("::A::(anonymous struct)::C")))); | 
|  | EXPECT_FALSE(matches("class A { struct { class C; } x; };", | 
|  | recordDecl(hasName("::A::C")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasNameSupportsFunctionScope) { | 
|  | std::string code = | 
|  | "namespace a { void F(int a) { struct S { int m; }; int i; } }"; | 
|  | EXPECT_TRUE(matches(code, varDecl(hasName("i")))); | 
|  | EXPECT_FALSE(matches(code, varDecl(hasName("F()::i")))); | 
|  |  | 
|  | EXPECT_TRUE(matches(code, fieldDecl(hasName("m")))); | 
|  | EXPECT_TRUE(matches(code, fieldDecl(hasName("S::m")))); | 
|  | EXPECT_TRUE(matches(code, fieldDecl(hasName("F(int)::S::m")))); | 
|  | EXPECT_TRUE(matches(code, fieldDecl(hasName("a::F(int)::S::m")))); | 
|  | EXPECT_TRUE(matches(code, fieldDecl(hasName("::a::F(int)::S::m")))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HasAnyName) { | 
|  | const std::string Code = "namespace a { namespace b { class C; } }"; | 
|  |  | 
|  | EXPECT_TRUE(matches(Code, recordDecl(hasAnyName("XX", "a::b::C")))); | 
|  | EXPECT_TRUE(matches(Code, recordDecl(hasAnyName("a::b::C", "XX")))); | 
|  | EXPECT_TRUE(matches(Code, recordDecl(hasAnyName("XX::C", "a::b::C")))); | 
|  | EXPECT_TRUE(matches(Code, recordDecl(hasAnyName("XX", "C")))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches(Code, recordDecl(hasAnyName("::C", "::b::C")))); | 
|  | EXPECT_TRUE( | 
|  | matches(Code, recordDecl(hasAnyName("::C", "::b::C", "::a::b::C")))); | 
|  |  | 
|  | std::vector<StringRef> Names = {"::C", "::b::C", "::a::b::C"}; | 
|  | EXPECT_TRUE(matches(Code, recordDecl(hasAnyName(Names)))); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, IsDefinition) { | 
|  | DeclarationMatcher DefinitionOfClassA = | 
|  | recordDecl(hasName("A"), isDefinition()); | 
|  | EXPECT_TRUE(matches("class A {};", DefinitionOfClassA)); | 
|  | EXPECT_TRUE(notMatches("class A;", DefinitionOfClassA)); | 
|  |  | 
|  | DeclarationMatcher DefinitionOfVariableA = | 
|  | varDecl(hasName("a"), isDefinition()); | 
|  | EXPECT_TRUE(matches("int a;", DefinitionOfVariableA)); | 
|  | EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA)); | 
|  |  | 
|  | DeclarationMatcher DefinitionOfMethodA = | 
|  | cxxMethodDecl(hasName("a"), isDefinition()); | 
|  | EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA)); | 
|  | EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA)); | 
|  | } | 
|  |  | 
|  | TEST(Matcher, HandlesNullQualTypes) { | 
|  | // FIXME: Add a Type matcher so we can replace uses of this | 
|  | // variable with Type(True()) | 
|  | const TypeMatcher AnyType = anything(); | 
|  |  | 
|  | // We don't really care whether this matcher succeeds; we're testing that | 
|  | // it completes without crashing. | 
|  | EXPECT_TRUE(matches( | 
|  | "struct A { };" | 
|  | "template <typename T>" | 
|  | "void f(T t) {" | 
|  | "  T local_t(t /* this becomes a null QualType in the AST */);" | 
|  | "}" | 
|  | "void g() {" | 
|  | "  f(0);" | 
|  | "}", | 
|  | expr(hasType(TypeMatcher( | 
|  | anyOf( | 
|  | TypeMatcher(hasDeclaration(anything())), | 
|  | pointsTo(AnyType), | 
|  | references(AnyType) | 
|  | // Other QualType matchers should go here. | 
|  | )))))); | 
|  | } | 
|  |  | 
|  |  | 
|  | TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) { | 
|  | EXPECT_TRUE(matches("void f() { }", | 
|  | compoundStmt(statementCountIs(0)))); | 
|  | EXPECT_TRUE(notMatches("void f() {}", | 
|  | compoundStmt(statementCountIs(1)))); | 
|  | } | 
|  |  | 
|  | TEST(StatementCountIs, AppearsToMatchOnlyOneCount) { | 
|  | EXPECT_TRUE(matches("void f() { 1; }", | 
|  | compoundStmt(statementCountIs(1)))); | 
|  | EXPECT_TRUE(notMatches("void f() { 1; }", | 
|  | compoundStmt(statementCountIs(0)))); | 
|  | EXPECT_TRUE(notMatches("void f() { 1; }", | 
|  | compoundStmt(statementCountIs(2)))); | 
|  | } | 
|  |  | 
|  | TEST(StatementCountIs, WorksWithMultipleStatements) { | 
|  | EXPECT_TRUE(matches("void f() { 1; 2; 3; }", | 
|  | compoundStmt(statementCountIs(3)))); | 
|  | } | 
|  |  | 
|  | TEST(StatementCountIs, WorksWithNestedCompoundStatements) { | 
|  | EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", | 
|  | compoundStmt(statementCountIs(1)))); | 
|  | EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", | 
|  | compoundStmt(statementCountIs(2)))); | 
|  | EXPECT_TRUE(notMatches("void f() { { 1; } { 1; 2; 3; 4; } }", | 
|  | compoundStmt(statementCountIs(3)))); | 
|  | EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", | 
|  | compoundStmt(statementCountIs(4)))); | 
|  | } | 
|  |  | 
|  | TEST(Member, WorksInSimplestCase) { | 
|  | EXPECT_TRUE(matches("struct { int first; } s; int i(s.first);", | 
|  | memberExpr(member(hasName("first"))))); | 
|  | } | 
|  |  | 
|  | TEST(Member, DoesNotMatchTheBaseExpression) { | 
|  | // Don't pick out the wrong part of the member expression, this should | 
|  | // be checking the member (name) only. | 
|  | EXPECT_TRUE(notMatches("struct { int i; } first; int i(first.i);", | 
|  | memberExpr(member(hasName("first"))))); | 
|  | } | 
|  |  | 
|  | TEST(Member, MatchesInMemberFunctionCall) { | 
|  | EXPECT_TRUE(matches("void f() {" | 
|  | "  struct { void first() {}; } s;" | 
|  | "  s.first();" | 
|  | "};", | 
|  | memberExpr(member(hasName("first"))))); | 
|  | } | 
|  |  | 
|  | TEST(Member, MatchesMember) { | 
|  | EXPECT_TRUE(matches( | 
|  | "struct A { int i; }; void f() { A a; a.i = 2; }", | 
|  | memberExpr(hasDeclaration(fieldDecl(hasType(isInteger())))))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "struct A { float f; }; void f() { A a; a.f = 2.0f; }", | 
|  | memberExpr(hasDeclaration(fieldDecl(hasType(isInteger())))))); | 
|  | } | 
|  |  | 
|  | TEST(Member, BitFields) { | 
|  | EXPECT_TRUE(matches("class C { int a : 2; int b; };", | 
|  | fieldDecl(isBitField(), hasName("a")))); | 
|  | EXPECT_TRUE(notMatches("class C { int a : 2; int b; };", | 
|  | fieldDecl(isBitField(), hasName("b")))); | 
|  | EXPECT_TRUE(matches("class C { int a : 2; int b : 4; };", | 
|  | fieldDecl(isBitField(), hasBitWidth(2), hasName("a")))); | 
|  | } | 
|  |  | 
|  | TEST(Member, UnderstandsAccess) { | 
|  | EXPECT_TRUE(matches( | 
|  | "struct A { int i; };", fieldDecl(isPublic(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "struct A { int i; };", fieldDecl(isProtected(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "struct A { int i; };", fieldDecl(isPrivate(), hasName("i")))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A { int i; };", fieldDecl(isPublic(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A { int i; };", fieldDecl(isProtected(), hasName("i")))); | 
|  | EXPECT_TRUE(matches( | 
|  | "class A { int i; };", fieldDecl(isPrivate(), hasName("i")))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A { protected: int i; };", fieldDecl(isPublic(), hasName("i")))); | 
|  | EXPECT_TRUE(matches("class A { protected: int i; };", | 
|  | fieldDecl(isProtected(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A { protected: int i; };", fieldDecl(isPrivate(), hasName("i")))); | 
|  |  | 
|  | // Non-member decls have the AccessSpecifier AS_none and thus aren't matched. | 
|  | EXPECT_TRUE(notMatches("int i;", varDecl(isPublic(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches("int i;", varDecl(isProtected(), hasName("i")))); | 
|  | EXPECT_TRUE(notMatches("int i;", varDecl(isPrivate(), hasName("i")))); | 
|  | } | 
|  |  | 
|  | TEST(hasDynamicExceptionSpec, MatchesDynamicExceptionSpecifications) { | 
|  | EXPECT_TRUE(notMatches("void f();", functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void g() noexcept;", | 
|  | functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void h() noexcept(true);", | 
|  | functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void i() noexcept(false);", | 
|  | functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void j() throw();", functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void k() throw(int);", functionDecl(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void l() throw(...);", functionDecl(hasDynamicExceptionSpec()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("void f();", functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void g() noexcept;", | 
|  | functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void h() noexcept(true);", | 
|  | functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE(notMatches("void i() noexcept(false);", | 
|  | functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void j() throw();", functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void k() throw(int);", functionProtoType(hasDynamicExceptionSpec()))); | 
|  | EXPECT_TRUE( | 
|  | matches("void l() throw(...);", functionProtoType(hasDynamicExceptionSpec()))); | 
|  | } | 
|  |  | 
|  | TEST(HasObjectExpression, DoesNotMatchMember) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class X {}; struct Z { X m; }; void f(Z z) { z.m; }", | 
|  | memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X"))))))); | 
|  | } | 
|  |  | 
|  | TEST(HasObjectExpression, MatchesBaseOfVariable) { | 
|  | EXPECT_TRUE(matches( | 
|  | "struct X { int m; }; void f(X x) { x.m; }", | 
|  | memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X"))))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "struct X { int m; }; void f(X* x) { x->m; }", | 
|  | memberExpr(hasObjectExpression( | 
|  | hasType(pointsTo(recordDecl(hasName("X")))))))); | 
|  | } | 
|  |  | 
|  | TEST(HasObjectExpression, | 
|  | MatchesObjectExpressionOfImplicitlyFormedMemberExpression) { | 
|  | EXPECT_TRUE(matches( | 
|  | "class X {}; struct S { X m; void f() { this->m; } };", | 
|  | memberExpr(hasObjectExpression( | 
|  | hasType(pointsTo(recordDecl(hasName("S")))))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "class X {}; struct S { X m; void f() { m; } };", | 
|  | memberExpr(hasObjectExpression( | 
|  | hasType(pointsTo(recordDecl(hasName("S")))))))); | 
|  | } | 
|  |  | 
|  | TEST(Field, DoesNotMatchNonFieldMembers) { | 
|  | EXPECT_TRUE(notMatches("class X { void m(); };", fieldDecl(hasName("m")))); | 
|  | EXPECT_TRUE(notMatches("class X { class m {}; };", fieldDecl(hasName("m")))); | 
|  | EXPECT_TRUE(notMatches("class X { enum { m }; };", fieldDecl(hasName("m")))); | 
|  | EXPECT_TRUE(notMatches("class X { enum m {}; };", fieldDecl(hasName("m")))); | 
|  | } | 
|  |  | 
|  | TEST(Field, MatchesField) { | 
|  | EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m")))); | 
|  | } | 
|  |  | 
|  | TEST(IsVolatileQualified, QualifiersMatch) { | 
|  | EXPECT_TRUE(matches("volatile int i = 42;", | 
|  | varDecl(hasType(isVolatileQualified())))); | 
|  | EXPECT_TRUE(notMatches("volatile int *i;", | 
|  | varDecl(hasType(isVolatileQualified())))); | 
|  | EXPECT_TRUE(matches("typedef volatile int v_int; v_int i = 42;", | 
|  | varDecl(hasType(isVolatileQualified())))); | 
|  | } | 
|  |  | 
|  | TEST(IsConstQualified, MatchesConstInt) { | 
|  | EXPECT_TRUE(matches("const int i = 42;", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | } | 
|  |  | 
|  | TEST(IsConstQualified, MatchesConstPointer) { | 
|  | EXPECT_TRUE(matches("int i = 42; int* const p(&i);", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | } | 
|  |  | 
|  | TEST(IsConstQualified, MatchesThroughTypedef) { | 
|  | EXPECT_TRUE(matches("typedef const int const_int; const_int i = 42;", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | EXPECT_TRUE(matches("typedef int* int_ptr; const int_ptr p(0);", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | } | 
|  |  | 
|  | TEST(IsConstQualified, DoesNotMatchInappropriately) { | 
|  | EXPECT_TRUE(notMatches("typedef int nonconst_int; nonconst_int i = 42;", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | EXPECT_TRUE(notMatches("int const* p;", | 
|  | varDecl(hasType(isConstQualified())))); | 
|  | } | 
|  |  | 
|  | TEST(DeclCount, DeclCountIsCorrect) { | 
|  | EXPECT_TRUE(matches("void f() {int i,j;}", | 
|  | declStmt(declCountIs(2)))); | 
|  | EXPECT_TRUE(notMatches("void f() {int i,j; int k;}", | 
|  | declStmt(declCountIs(3)))); | 
|  | EXPECT_TRUE(notMatches("void f() {int i,j, k, l;}", | 
|  | declStmt(declCountIs(3)))); | 
|  | } | 
|  |  | 
|  |  | 
|  | TEST(EachOf, TriggersForEachMatch) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "class A { int a; int b; };", | 
|  | recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), | 
|  | has(fieldDecl(hasName("b")).bind("v")))), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v", 2))); | 
|  | } | 
|  |  | 
|  | TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "class A { int a; int c; };", | 
|  | recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), | 
|  | has(fieldDecl(hasName("b")).bind("v")))), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v", 1))); | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "class A { int c; int b; };", | 
|  | recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), | 
|  | has(fieldDecl(hasName("b")).bind("v")))), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v", 1))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A { int c; int d; };", | 
|  | recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), | 
|  | has(fieldDecl(hasName("b")).bind("v")))))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) { | 
|  | // Make sure that we can both match the class by name (::X) and by the type | 
|  | // the template was instantiated with (via a field). | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> class X {}; class A {}; X<A> x;", | 
|  | cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> class X { T t; }; class A {}; X<A> x;", | 
|  | cxxRecordDecl(isTemplateInstantiation(), hasDescendant( | 
|  | fieldDecl(hasType(recordDecl(hasName("A")))))))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) { | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> void f(T t) {} class A {}; void g() { f(A()); }", | 
|  | functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))), | 
|  | isTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) { | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> class X { T t; }; class A {};" | 
|  | "template class X<A>;", | 
|  | cxxRecordDecl(isTemplateInstantiation(), hasDescendant( | 
|  | fieldDecl(hasType(recordDecl(hasName("A")))))))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, | 
|  | MatchesInstantiationOfPartiallySpecializedClassTemplate) { | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> class X {};" | 
|  | "template <typename T> class X<T*> {}; class A {}; X<A*> x;", | 
|  | cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, | 
|  | MatchesInstantiationOfClassTemplateNestedInNonTemplate) { | 
|  | EXPECT_TRUE(matches( | 
|  | "class A {};" | 
|  | "class X {" | 
|  | "  template <typename U> class Y { U u; };" | 
|  | "  Y<A> y;" | 
|  | "};", | 
|  | cxxRecordDecl(hasName("::X::Y"), isTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { | 
|  | // FIXME: Figure out whether this makes sense. It doesn't affect the | 
|  | // normal use case as long as the uppermost instantiation always is marked | 
|  | // as template instantiation, but it might be confusing as a predicate. | 
|  | EXPECT_TRUE(matches( | 
|  | "class A {};" | 
|  | "template <typename T> class X {" | 
|  | "  template <typename U> class Y { U u; };" | 
|  | "  Y<T> y;" | 
|  | "}; X<A> x;", | 
|  | cxxRecordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> class X {}; class A {};" | 
|  | "template <> class X<A> {}; X<A> x;", | 
|  | cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class A {}; class Y { A a; };", | 
|  | cxxRecordDecl(isTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInstantiated, MatchesInstantiation) { | 
|  | EXPECT_TRUE( | 
|  | matches("template<typename T> class A { T i; }; class Y { A<int> a; };", | 
|  | cxxRecordDecl(isInstantiated()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInstantiated, NotMatchesDefinition) { | 
|  | EXPECT_TRUE(notMatches("template<typename T> class A { T i; };", | 
|  | cxxRecordDecl(isInstantiated()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { | 
|  | EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };" | 
|  | "class Y { A<int> a; }; Y y;", | 
|  | declStmt(isInTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) { | 
|  | EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };", | 
|  | declStmt(isInTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInstantiated, MatchesFunctionInstantiation) { | 
|  | EXPECT_TRUE( | 
|  | matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", | 
|  | functionDecl(isInstantiated()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInstantiated, NotMatchesFunctionDefinition) { | 
|  | EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", | 
|  | varDecl(isInstantiated()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) { | 
|  | EXPECT_TRUE( | 
|  | matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", | 
|  | declStmt(isInTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) { | 
|  | EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", | 
|  | declStmt(isInTemplateInstantiation()))); | 
|  | } | 
|  |  | 
|  | TEST(IsInTemplateInstantiation, Sharing) { | 
|  | auto Matcher = binaryOperator(unless(isInTemplateInstantiation())); | 
|  | // FIXME: Node sharing is an implementation detail, exposing it is ugly | 
|  | // and makes the matcher behave in non-obvious ways. | 
|  | EXPECT_TRUE(notMatches( | 
|  | "int j; template<typename T> void A(T t) { j += 42; } void x() { A(0); }", | 
|  | Matcher)); | 
|  | EXPECT_TRUE(matches( | 
|  | "int j; template<typename T> void A(T t) { j += t; } void x() { A(0); }", | 
|  | Matcher)); | 
|  | } | 
|  |  | 
|  | TEST(IsExplicitTemplateSpecialization, | 
|  | DoesNotMatchPrimaryTemplate) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> class X {};", | 
|  | cxxRecordDecl(isExplicitTemplateSpecialization()))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> void f(T t);", | 
|  | functionDecl(isExplicitTemplateSpecialization()))); | 
|  | } | 
|  |  | 
|  | TEST(IsExplicitTemplateSpecialization, | 
|  | DoesNotMatchExplicitTemplateInstantiations) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> class X {};" | 
|  | "template class X<int>; extern template class X<long>;", | 
|  | cxxRecordDecl(isExplicitTemplateSpecialization()))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> void f(T t) {}" | 
|  | "template void f(int t); extern template void f(long t);", | 
|  | functionDecl(isExplicitTemplateSpecialization()))); | 
|  | } | 
|  |  | 
|  | TEST(IsExplicitTemplateSpecialization, | 
|  | DoesNotMatchImplicitTemplateInstantiations) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> class X {}; X<int> x;", | 
|  | cxxRecordDecl(isExplicitTemplateSpecialization()))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "template <typename T> void f(T t); void g() { f(10); }", | 
|  | functionDecl(isExplicitTemplateSpecialization()))); | 
|  | } | 
|  |  | 
|  | TEST(IsExplicitTemplateSpecialization, | 
|  | MatchesExplicitTemplateSpecializations) { | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> class X {};" | 
|  | "template<> class X<int> {};", | 
|  | cxxRecordDecl(isExplicitTemplateSpecialization()))); | 
|  | EXPECT_TRUE(matches( | 
|  | "template <typename T> void f(T t) {}" | 
|  | "template<> void f(int t) {}", | 
|  | functionDecl(isExplicitTemplateSpecialization()))); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, MatchesBool) { | 
|  | EXPECT_TRUE(matches("struct S { bool func(); };", | 
|  | cxxMethodDecl(returns(booleanType())))); | 
|  | EXPECT_TRUE(notMatches("struct S { void func(); };", | 
|  | cxxMethodDecl(returns(booleanType())))); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, MatchesVoid) { | 
|  | EXPECT_TRUE(matches("struct S { void func(); };", | 
|  | cxxMethodDecl(returns(voidType())))); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, MatchesRealFloats) { | 
|  | EXPECT_TRUE(matches("struct S { float func(); };", | 
|  | cxxMethodDecl(returns(realFloatingPointType())))); | 
|  | EXPECT_TRUE(notMatches("struct S { int func(); };", | 
|  | cxxMethodDecl(returns(realFloatingPointType())))); | 
|  | EXPECT_TRUE(matches("struct S { long double func(); };", | 
|  | cxxMethodDecl(returns(realFloatingPointType())))); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, MatchesArrayTypes) { | 
|  | EXPECT_TRUE(matches("int a[] = {2,3};", arrayType())); | 
|  | EXPECT_TRUE(matches("int a[42];", arrayType())); | 
|  | EXPECT_TRUE(matches("void f(int b) { int a[b]; }", arrayType())); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("struct A {}; A a[7];", | 
|  | arrayType(hasElementType(builtinType())))); | 
|  |  | 
|  | EXPECT_TRUE(matches( | 
|  | "int const a[] = { 2, 3 };", | 
|  | qualType(arrayType(hasElementType(builtinType()))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "int const a[] = { 2, 3 };", | 
|  | qualType(isConstQualified(), arrayType(hasElementType(builtinType()))))); | 
|  | EXPECT_TRUE(matches( | 
|  | "typedef const int T; T x[] = { 1, 2 };", | 
|  | qualType(isConstQualified(), arrayType()))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches( | 
|  | "int a[] = { 2, 3 };", | 
|  | qualType(isConstQualified(), arrayType(hasElementType(builtinType()))))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "int a[] = { 2, 3 };", | 
|  | qualType(arrayType(hasElementType(isConstQualified(), builtinType()))))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "int const a[] = { 2, 3 };", | 
|  | qualType(arrayType(hasElementType(builtinType())), | 
|  | unless(isConstQualified())))); | 
|  |  | 
|  | EXPECT_TRUE(matches("int a[2];", | 
|  | constantArrayType(hasElementType(builtinType())))); | 
|  | EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger()))); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, DecayedType) { | 
|  | EXPECT_TRUE(matches("void f(int i[]);", valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))); | 
|  | EXPECT_TRUE(notMatches("int i[7];", decayedType())); | 
|  | } | 
|  |  | 
|  | TEST(TypeMatching, MatchesComplexTypes) { | 
|  | EXPECT_TRUE(matches("_Complex float f;", complexType())); | 
|  | EXPECT_TRUE(matches( | 
|  | "_Complex float f;", | 
|  | complexType(hasElementType(builtinType())))); | 
|  | EXPECT_TRUE(notMatches( | 
|  | "_Complex float f;", | 
|  | complexType(hasElementType(isInteger())))); | 
|  | } | 
|  |  | 
|  | TEST(NS, Anonymous) { | 
|  | EXPECT_TRUE(notMatches("namespace N {}", namespaceDecl(isAnonymous()))); | 
|  | EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous()))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, QualType) { | 
|  | EXPECT_TRUE(matches( | 
|  | "int i = 1;", varDecl(hasType(qualType().bind("type")), | 
|  | hasInitializer(ignoringParenImpCasts( | 
|  | hasType(qualType(equalsBoundNode("type")))))))); | 
|  | EXPECT_TRUE(notMatches("int i = 1.f;", | 
|  | varDecl(hasType(qualType().bind("type")), | 
|  | hasInitializer(ignoringParenImpCasts(hasType( | 
|  | qualType(equalsBoundNode("type")))))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, NonMatchingTypes) { | 
|  | EXPECT_TRUE(notMatches( | 
|  | "int i = 1;", varDecl(namedDecl(hasName("i")).bind("name"), | 
|  | hasInitializer(ignoringParenImpCasts( | 
|  | hasType(qualType(equalsBoundNode("type")))))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, Stmt) { | 
|  | EXPECT_TRUE( | 
|  | matches("void f() { if(true) {} }", | 
|  | stmt(allOf(ifStmt().bind("if"), | 
|  | hasParent(stmt(has(stmt(equalsBoundNode("if"))))))))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches( | 
|  | "void f() { if(true) { if (true) {} } }", | 
|  | stmt(allOf(ifStmt().bind("if"), has(stmt(equalsBoundNode("if"))))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, Decl) { | 
|  | EXPECT_TRUE(matches( | 
|  | "class X { class Y {}; };", | 
|  | decl(allOf(recordDecl(hasName("::X::Y")).bind("record"), | 
|  | hasParent(decl(has(decl(equalsBoundNode("record"))))))))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches("class X { class Y {}; };", | 
|  | decl(allOf(recordDecl(hasName("::X")).bind("record"), | 
|  | has(decl(equalsBoundNode("record"))))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, Type) { | 
|  | EXPECT_TRUE(matches( | 
|  | "class X { int a; int b; };", | 
|  | recordDecl( | 
|  | has(fieldDecl(hasName("a"), hasType(type().bind("t")))), | 
|  | has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))))); | 
|  |  | 
|  | EXPECT_TRUE(notMatches( | 
|  | "class X { int a; double b; };", | 
|  | recordDecl( | 
|  | has(fieldDecl(hasName("a"), hasType(type().bind("t")))), | 
|  | has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, UsingForEachDescendant) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "int f() {" | 
|  | "  if (1) {" | 
|  | "    int i = 9;" | 
|  | "  }" | 
|  | "  int j = 10;" | 
|  | "  {" | 
|  | "    float k = 9.0;" | 
|  | "  }" | 
|  | "  return 0;" | 
|  | "}", | 
|  | // Look for variable declarations within functions whose type is the same | 
|  | // as the function return type. | 
|  | functionDecl(returns(qualType().bind("type")), | 
|  | forEachDescendant(varDecl(hasType( | 
|  | qualType(equalsBoundNode("type")))).bind("decl"))), | 
|  | // Only i and j should match, not k. | 
|  | llvm::make_unique<VerifyIdIsBoundTo<VarDecl>>("decl", 2))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, FiltersMatchedCombinations) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "void f() {" | 
|  | "  int x;" | 
|  | "  double d;" | 
|  | "  x = d + x - d + x;" | 
|  | "}", | 
|  | functionDecl( | 
|  | hasName("f"), forEachDescendant(varDecl().bind("d")), | 
|  | forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d")))))), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<VarDecl>>("d", 5))); | 
|  | } | 
|  |  | 
|  | TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { | 
|  | EXPECT_TRUE(matchAndVerifyResultTrue( | 
|  | "struct StringRef { int size() const; const char* data() const; };" | 
|  | "void f(StringRef v) {" | 
|  | "  v.data();" | 
|  | "}", | 
|  | cxxMemberCallExpr( | 
|  | callee(cxxMethodDecl(hasName("data"))), | 
|  | on(declRefExpr(to( | 
|  | varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), | 
|  | unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( | 
|  | callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), | 
|  | on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) | 
|  | .bind("data"), | 
|  | llvm::make_unique<VerifyIdIsBoundTo<Expr>>("data", 1))); | 
|  |  | 
|  | EXPECT_FALSE(matches( | 
|  | "struct StringRef { int size() const; const char* data() const; };" | 
|  | "void f(StringRef v) {" | 
|  | "  v.data();" | 
|  | "  v.size();" | 
|  | "}", | 
|  | cxxMemberCallExpr( | 
|  | callee(cxxMethodDecl(hasName("data"))), | 
|  | on(declRefExpr(to( | 
|  | varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), | 
|  | unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( | 
|  | callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), | 
|  | on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) | 
|  | .bind("data"))); | 
|  | } | 
|  |  | 
|  | TEST(NullPointerConstants, Basic) { | 
|  | EXPECT_TRUE(matches("#define NULL ((void *)0)\n" | 
|  | "void *v1 = NULL;", expr(nullPointerConstant()))); | 
|  | EXPECT_TRUE(matches("void *v2 = nullptr;", expr(nullPointerConstant()))); | 
|  | EXPECT_TRUE(matches("void *v3 = __null;", expr(nullPointerConstant()))); | 
|  | EXPECT_TRUE(matches("char *cp = (char *)0;", expr(nullPointerConstant()))); | 
|  | EXPECT_TRUE(matches("int *ip = 0;", expr(nullPointerConstant()))); | 
|  | EXPECT_TRUE(notMatches("int i = 0;", expr(nullPointerConstant()))); | 
|  | } | 
|  |  | 
|  | TEST(HasExternalFormalLinkage, Basic) { | 
|  | EXPECT_TRUE(matches("int a = 0;", namedDecl(hasExternalFormalLinkage()))); | 
|  | EXPECT_TRUE( | 
|  | notMatches("static int a = 0;", namedDecl(hasExternalFormalLinkage()))); | 
|  | EXPECT_TRUE(notMatches("static void f(void) { int a = 0; }", | 
|  | namedDecl(hasExternalFormalLinkage()))); | 
|  | EXPECT_TRUE(matches("void f(void) { int a = 0; }", | 
|  | namedDecl(hasExternalFormalLinkage()))); | 
|  |  | 
|  | // Despite having internal semantic linkage, the anonymous namespace member | 
|  | // has external linkage because the member has a unique name in all | 
|  | // translation units. | 
|  | EXPECT_TRUE(matches("namespace { int a = 0; }", | 
|  | namedDecl(hasExternalFormalLinkage()))); | 
|  | } | 
|  |  | 
|  | } // namespace ast_matchers | 
|  | } // namespace clang |