diff options
author | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 056abd2059c65a3e908193aeae16fad98017437c (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /unittests/ASTMatchers/ASTMatchersTest.cpp | |
parent | cc73504950eb7b5dff2dded9bedd67bc36d64641 (diff) | |
download | FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.zip FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.tar.gz |
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersTest.cpp')
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 1859 |
1 files changed, 1346 insertions, 513 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index adf0e94..e15940a 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -19,21 +19,21 @@ namespace ast_matchers { #if GTEST_HAS_DEATH_TEST TEST(HasNameDeathTest, DiesOnEmptyName) { ASSERT_DEBUG_DEATH({ - DeclarationMatcher HasEmptyName = record(hasName("")); + DeclarationMatcher HasEmptyName = recordDecl(hasName("")); EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); }, ""); } TEST(HasNameDeathTest, DiesOnEmptyPattern) { ASSERT_DEBUG_DEATH({ - DeclarationMatcher HasEmptyName = record(matchesName("")); + DeclarationMatcher HasEmptyName = recordDecl(matchesName("")); EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); }, ""); } TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { ASSERT_DEBUG_DEATH({ - DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom("")); + DeclarationMatcher IsDerivedFromEmpty = recordDecl(isDerivedFrom("")); EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty)); }, ""); } @@ -46,7 +46,7 @@ TEST(Decl, MatchesDeclarations) { } TEST(NameableDeclaration, MatchesVariousDecls) { - DeclarationMatcher NamedX = nameableDeclaration(hasName("X")); + DeclarationMatcher NamedX = namedDecl(hasName("X")); EXPECT_TRUE(matches("typedef int X;", NamedX)); EXPECT_TRUE(matches("int X;", NamedX)); EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX)); @@ -59,7 +59,7 @@ TEST(NameableDeclaration, MatchesVariousDecls) { } TEST(NameableDeclaration, REMatchesVariousDecls) { - DeclarationMatcher NamedX = nameableDeclaration(matchesName("::X")); + DeclarationMatcher NamedX = namedDecl(matchesName("::X")); EXPECT_TRUE(matches("typedef int Xa;", NamedX)); EXPECT_TRUE(matches("int Xb;", NamedX)); EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX)); @@ -70,11 +70,11 @@ TEST(NameableDeclaration, REMatchesVariousDecls) { EXPECT_TRUE(notMatches("#define Xkl 1", NamedX)); - DeclarationMatcher StartsWithNo = nameableDeclaration(matchesName("::no")); + DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no")); EXPECT_TRUE(matches("int no_foo;", StartsWithNo)); EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo)); - DeclarationMatcher Abc = nameableDeclaration(matchesName("a.*b.*c")); + DeclarationMatcher Abc = namedDecl(matchesName("a.*b.*c")); EXPECT_TRUE(matches("int abc;", Abc)); EXPECT_TRUE(matches("int aFOObBARc;", Abc)); EXPECT_TRUE(notMatches("int cab;", Abc)); @@ -82,7 +82,7 @@ TEST(NameableDeclaration, REMatchesVariousDecls) { } TEST(DeclarationMatcher, MatchClass) { - DeclarationMatcher ClassMatcher(record()); + DeclarationMatcher ClassMatcher(recordDecl()); #if !defined(_MSC_VER) EXPECT_FALSE(matches("", ClassMatcher)); #else @@ -90,7 +90,7 @@ TEST(DeclarationMatcher, MatchClass) { EXPECT_TRUE(matches("", ClassMatcher)); #endif - DeclarationMatcher ClassX = record(record(hasName("X"))); + DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X"))); EXPECT_TRUE(matches("class X;", ClassX)); EXPECT_TRUE(matches("class X {};", ClassX)); EXPECT_TRUE(matches("template<class T> class X {};", ClassX)); @@ -98,17 +98,24 @@ TEST(DeclarationMatcher, MatchClass) { } TEST(DeclarationMatcher, ClassIsDerived) { - DeclarationMatcher IsDerivedFromX = record(isDerivedFrom("X")); + DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X")); EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX)); - EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX)); - EXPECT_TRUE(matches("class X {};", IsDerivedFromX)); - EXPECT_TRUE(matches("class 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 = recordDecl(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 = - record(hasName("Z"), isDerivedFrom("X")); + recordDecl(hasName("Z"), isDerivedFrom("X")); EXPECT_TRUE( matches("class X {}; class Y : public X {}; class Z : public Y {};", ZIsDerivedFromX)); @@ -239,19 +246,17 @@ TEST(DeclarationMatcher, ClassIsDerived) { "void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }"; EXPECT_TRUE(matches( RecursiveTemplateOneParameter, - variable(hasName("z_float"), - hasInitializer(hasType(record(isDerivedFrom("Base1"))))))); + varDecl(hasName("z_float"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateOneParameter, - variable( - hasName("z_float"), - hasInitializer(hasType(record(isDerivedFrom("Base2"))))))); + varDecl(hasName("z_float"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateOneParameter, - variable( - hasName("z_char"), - hasInitializer(hasType(record(isDerivedFrom("Base1"), - isDerivedFrom("Base2"))))))); + varDecl(hasName("z_char"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + isDerivedFrom("Base2"))))))); const char *RecursiveTemplateTwoParameters = "class Base1 {}; class Base2 {};" @@ -266,47 +271,81 @@ TEST(DeclarationMatcher, ClassIsDerived) { " Z<char, void> z_char; }"; EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, - variable( - hasName("z_float"), - hasInitializer(hasType(record(isDerivedFrom("Base1"))))))); + varDecl(hasName("z_float"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateTwoParameters, - variable( - hasName("z_float"), - hasInitializer(hasType(record(isDerivedFrom("Base2"))))))); + varDecl(hasName("z_float"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, - variable( - hasName("z_char"), - hasInitializer(hasType(record(isDerivedFrom("Base1"), - isDerivedFrom("Base2"))))))); + varDecl(hasName("z_char"), + hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( "namespace ns { class X {}; class Y : public X {}; }", - record(isDerivedFrom("::ns::X")))); + recordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(notMatches( "class X {}; class Y : public X {};", - record(isDerivedFrom("::ns::X")))); + recordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(matches( "class X {}; class Y : public X {};", - record(isDerivedFrom(record(hasName("X")).bind("test"))))); + recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); +} + +TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { + EXPECT_TRUE(matches( + "template <typename T> struct A {" + " template <typename T2> struct F {};" + "};" + "template <typename T> struct B : A<T>::template F<T> {};" + "B<int> b;", + recordDecl(hasName("B"), isDerivedFrom(recordDecl())))); +} + +TEST(ClassTemplate, DoesNotMatchClass) { + DeclarationMatcher ClassX = classTemplateDecl(hasName("X")); + EXPECT_TRUE(notMatches("class X;", ClassX)); + EXPECT_TRUE(notMatches("class X {};", ClassX)); +} + +TEST(ClassTemplate, MatchesClassTemplate) { + DeclarationMatcher ClassX = classTemplateDecl(hasName("X")); + EXPECT_TRUE(matches("template<typename T> class X {};", ClassX)); + EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX)); +} + +TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) { + EXPECT_TRUE(notMatches("template<typename T> class X { };" + "template<> class X<int> { int a; };", + classTemplateDecl(hasName("X"), + hasDescendant(fieldDecl(hasName("a")))))); +} + +TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) { + EXPECT_TRUE(notMatches("template<typename T, typename U> class X { };" + "template<typename T> class X<T, int> { int a; };", + classTemplateDecl(hasName("X"), + hasDescendant(fieldDecl(hasName("a")))))); } TEST(AllOf, AllOverloadsWork) { const char Program[] = "struct T { }; int f(int, T*); void g(int x) { T t; f(x, &t); }"; EXPECT_TRUE(matches(Program, - call(allOf(callee(function(hasName("f"))), - hasArgument(0, declarationReference(to(variable()))))))); + callExpr(allOf(callee(functionDecl(hasName("f"))), + hasArgument(0, declRefExpr(to(varDecl()))))))); EXPECT_TRUE(matches(Program, - call(allOf(callee(function(hasName("f"))), - hasArgument(0, declarationReference(to(variable()))), - hasArgument(1, hasType(pointsTo(record(hasName("T"))))))))); + callExpr(allOf(callee(functionDecl(hasName("f"))), + hasArgument(0, declRefExpr(to(varDecl()))), + hasArgument(1, hasType(pointsTo( + recordDecl(hasName("T"))))))))); } TEST(DeclarationMatcher, MatchAnyOf) { DeclarationMatcher YOrZDerivedFromX = - record(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); + recordDecl(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); EXPECT_TRUE( matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX)); @@ -315,13 +354,13 @@ TEST(DeclarationMatcher, MatchAnyOf) { EXPECT_TRUE(notMatches("class Z {};", YOrZDerivedFromX)); DeclarationMatcher XOrYOrZOrU = - record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"))); + recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"))); EXPECT_TRUE(matches("class X {};", XOrYOrZOrU)); EXPECT_TRUE(notMatches("class V {};", XOrYOrZOrU)); DeclarationMatcher XOrYOrZOrUOrV = - record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"), - hasName("V"))); + 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)); @@ -331,13 +370,12 @@ TEST(DeclarationMatcher, MatchAnyOf) { } TEST(DeclarationMatcher, MatchHas) { - DeclarationMatcher HasClassX = record(has(record(hasName("X")))); - + DeclarationMatcher HasClassX = recordDecl(has(recordDecl(hasName("X")))); EXPECT_TRUE(matches("class Y { class X {}; };", HasClassX)); EXPECT_TRUE(matches("class X {};", HasClassX)); DeclarationMatcher YHasClassX = - record(hasName("Y"), has(record(hasName("X")))); + recordDecl(hasName("Y"), has(recordDecl(hasName("X")))); EXPECT_TRUE(matches("class Y { class X {}; };", YHasClassX)); EXPECT_TRUE(notMatches("class X {};", YHasClassX)); EXPECT_TRUE( @@ -346,14 +384,14 @@ TEST(DeclarationMatcher, MatchHas) { TEST(DeclarationMatcher, MatchHasRecursiveAllOf) { DeclarationMatcher Recursive = - record( - has(record( - has(record(hasName("X"))), - has(record(hasName("Y"))), + recordDecl( + has(recordDecl( + has(recordDecl(hasName("X"))), + has(recordDecl(hasName("Y"))), hasName("Z"))), - has(record( - has(record(hasName("A"))), - has(record(hasName("B"))), + has(recordDecl( + has(recordDecl(hasName("A"))), + has(recordDecl(hasName("B"))), hasName("C"))), hasName("F")); @@ -404,21 +442,21 @@ TEST(DeclarationMatcher, MatchHasRecursiveAllOf) { TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { DeclarationMatcher Recursive = - record( + recordDecl( anyOf( - has(record( + has(recordDecl( anyOf( - has(record( + has(recordDecl( hasName("X"))), - has(record( + has(recordDecl( hasName("Y"))), hasName("Z")))), - has(record( + has(recordDecl( anyOf( hasName("C"), - has(record( + has(recordDecl( hasName("A"))), - has(record( + has(recordDecl( hasName("B")))))), hasName("F"))); @@ -435,9 +473,8 @@ TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { TEST(DeclarationMatcher, MatchNot) { DeclarationMatcher NotClassX = - record( + recordDecl( isDerivedFrom("Y"), - unless(hasName("Y")), unless(hasName("X"))); EXPECT_TRUE(notMatches("", NotClassX)); EXPECT_TRUE(notMatches("class Y {};", NotClassX)); @@ -448,11 +485,11 @@ TEST(DeclarationMatcher, MatchNot) { NotClassX)); DeclarationMatcher ClassXHasNotClassY = - record( + recordDecl( hasName("X"), - has(record(hasName("Z"))), + has(recordDecl(hasName("Z"))), unless( - has(record(hasName("Y"))))); + has(recordDecl(hasName("Y"))))); EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY)); EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };", ClassXHasNotClassY)); @@ -460,8 +497,8 @@ TEST(DeclarationMatcher, MatchNot) { TEST(DeclarationMatcher, HasDescendant) { DeclarationMatcher ZDescendantClassX = - record( - hasDescendant(record(hasName("X"))), + recordDecl( + hasDescendant(recordDecl(hasName("X"))), hasName("Z")); EXPECT_TRUE(matches("class Z { class X {}; };", ZDescendantClassX)); EXPECT_TRUE( @@ -475,8 +512,8 @@ TEST(DeclarationMatcher, HasDescendant) { EXPECT_TRUE(notMatches("class Z {};", ZDescendantClassX)); DeclarationMatcher ZDescendantClassXHasClassY = - record( - hasDescendant(record(has(record(hasName("Y"))), + recordDecl( + hasDescendant(recordDecl(has(recordDecl(hasName("Y"))), hasName("X"))), hasName("Z")); EXPECT_TRUE(matches("class Z { class X { class Y {}; }; };", @@ -498,9 +535,9 @@ TEST(DeclarationMatcher, HasDescendant) { "};", ZDescendantClassXHasClassY)); DeclarationMatcher ZDescendantClassXDescendantClassY = - record( - hasDescendant(record(hasDescendant(record(hasName("Y"))), - hasName("X"))), + recordDecl( + hasDescendant(recordDecl(hasDescendant(recordDecl(hasName("Y"))), + hasName("X"))), hasName("Z")); EXPECT_TRUE( matches("class Z { class A { class X { class B { class Y {}; }; }; }; };", @@ -518,6 +555,118 @@ TEST(DeclarationMatcher, HasDescendant) { "};", ZDescendantClassXDescendantClassY)); } +// Implements a run method that returns whether BoundNodes contains a +// Decl bound to Id that can be dynamically cast to T. +// Optionally checks that the check succeeded a specific number of times. +template <typename T> +class VerifyIdIsBoundTo : public BoundNodesCallback { +public: + // Create an object that checks that a node of type \c T was bound to \c Id. + // Does not check for a certain number of matches. + explicit VerifyIdIsBoundTo(llvm::StringRef Id) + : Id(Id), ExpectedCount(-1), Count(0) {} + + // Create an object that checks that a node of type \c T was bound to \c Id. + // Checks that there were exactly \c ExpectedCount matches. + VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount) + : Id(Id), ExpectedCount(ExpectedCount), Count(0) {} + + // Create an object that checks that a node of type \c T was bound to \c Id. + // Checks that there was exactly one match with the name \c ExpectedName. + // Note that \c T must be a NamedDecl for this to work. + VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName) + : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {} + + ~VerifyIdIsBoundTo() { + if (ExpectedCount != -1) + EXPECT_EQ(ExpectedCount, Count); + if (!ExpectedName.empty()) + EXPECT_EQ(ExpectedName, Name); + } + + virtual bool run(const BoundNodes *Nodes) { + if (Nodes->getNodeAs<T>(Id)) { + ++Count; + if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) { + Name = Named->getNameAsString(); + } else if (const NestedNameSpecifier *NNS = + Nodes->getNodeAs<NestedNameSpecifier>(Id)) { + llvm::raw_string_ostream OS(Name); + NNS->print(OS, PrintingPolicy(LangOptions())); + } + return true; + } + return false; + } + + virtual bool run(const BoundNodes *Nodes, ASTContext *Context) { + return run(Nodes); + } + +private: + const std::string Id; + const int ExpectedCount; + int Count; + const std::string ExpectedName; + std::string Name; +}; + +TEST(HasDescendant, MatchesDescendantTypes) { + EXPECT_TRUE(matches("void f() { int i = 3; }", + decl(hasDescendant(loc(builtinType()))))); + EXPECT_TRUE(matches("void f() { int i = 3; }", + stmt(hasDescendant(builtinType())))); + + EXPECT_TRUE(matches("void f() { int i = 3; }", + stmt(hasDescendant(loc(builtinType()))))); + EXPECT_TRUE(matches("void f() { int i = 3; }", + stmt(hasDescendant(qualType(builtinType()))))); + + EXPECT_TRUE(notMatches("void f() { float f = 2.0f; }", + stmt(hasDescendant(isInteger())))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void f() { int a; float c; int d; int e; }", + functionDecl(forEachDescendant( + varDecl(hasDescendant(isInteger())).bind("x"))), + new VerifyIdIsBoundTo<Decl>("x", 3))); +} + +TEST(HasDescendant, MatchesDescendantsOfTypes) { + EXPECT_TRUE(matches("void f() { int*** i; }", + qualType(hasDescendant(builtinType())))); + EXPECT_TRUE(matches("void f() { int*** i; }", + qualType(hasDescendant( + pointerType(pointee(builtinType())))))); + EXPECT_TRUE(matches("void f() { int*** i; }", + typeLoc(hasDescendant(builtinTypeLoc())))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void f() { int*** i; }", + qualType(asString("int ***"), forEachDescendant(pointerType().bind("x"))), + new VerifyIdIsBoundTo<Type>("x", 2))); +} + +TEST(Has, MatchesChildrenOfTypes) { + EXPECT_TRUE(matches("int i;", + varDecl(hasName("i"), has(isInteger())))); + EXPECT_TRUE(notMatches("int** i;", + varDecl(hasName("i"), has(isInteger())))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "int (*f)(float, int);", + qualType(functionType(), forEach(qualType(isInteger()).bind("x"))), + new VerifyIdIsBoundTo<QualType>("x", 2))); +} + +TEST(Has, MatchesChildTypes) { + EXPECT_TRUE(matches( + "int* i;", + varDecl(hasName("i"), hasType(qualType(has(builtinType())))))); + EXPECT_TRUE(notMatches( + "int* i;", + varDecl(hasName("i"), hasType(qualType(has(pointerType())))))); +} + TEST(Enum, DoesNotMatchClasses) { EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X")))); } @@ -527,7 +676,7 @@ TEST(Enum, MatchesEnums) { } TEST(EnumConstant, Matches) { - DeclarationMatcher Matcher = enumConstant(hasName("A")); + DeclarationMatcher Matcher = enumConstantDecl(hasName("A")); EXPECT_TRUE(matches("enum X{ A };", Matcher)); EXPECT_TRUE(notMatches("enum X{ B };", Matcher)); EXPECT_TRUE(notMatches("enum X {};", Matcher)); @@ -535,9 +684,8 @@ TEST(EnumConstant, Matches) { TEST(StatementMatcher, Has) { StatementMatcher HasVariableI = - expression( - hasType(pointsTo(record(hasName("X")))), - has(declarationReference(to(variable(hasName("i")))))); + expr(hasType(pointsTo(recordDecl(hasName("X")))), + has(declRefExpr(to(varDecl(hasName("i")))))); EXPECT_TRUE(matches( "class X; X *x(int); void c() { int i; x(i); }", HasVariableI)); @@ -547,9 +695,8 @@ TEST(StatementMatcher, Has) { TEST(StatementMatcher, HasDescendant) { StatementMatcher HasDescendantVariableI = - expression( - hasType(pointsTo(record(hasName("X")))), - hasDescendant(declarationReference(to(variable(hasName("i")))))); + expr(hasType(pointsTo(recordDecl(hasName("X")))), + hasDescendant(declRefExpr(to(varDecl(hasName("i")))))); EXPECT_TRUE(matches( "class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }", @@ -560,160 +707,127 @@ TEST(StatementMatcher, HasDescendant) { } TEST(TypeMatcher, MatchesClassType) { - TypeMatcher TypeA = hasDeclaration(record(hasName("A"))); + TypeMatcher TypeA = hasDeclaration(recordDecl(hasName("A"))); EXPECT_TRUE(matches("class A { public: A *a; };", TypeA)); EXPECT_TRUE(notMatches("class A {};", TypeA)); - TypeMatcher TypeDerivedFromA = hasDeclaration(record(isDerivedFrom("A"))); + TypeMatcher TypeDerivedFromA = hasDeclaration(recordDecl(isDerivedFrom("A"))); EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };", TypeDerivedFromA)); EXPECT_TRUE(notMatches("class A {};", TypeA)); TypeMatcher TypeAHasClassB = hasDeclaration( - record(hasName("A"), has(record(hasName("B"))))); + recordDecl(hasName("A"), has(recordDecl(hasName("B"))))); EXPECT_TRUE( matches("class A { public: A *a; class B {}; };", TypeAHasClassB)); } -// Returns from Run whether 'bound_nodes' contain a Decl bound to 'Id', which -// can be dynamically casted to T. -// Optionally checks that the check succeeded a specific number of times. -template <typename T> -class VerifyIdIsBoundToDecl : public BoundNodesCallback { -public: - // Create an object that checks that a node of type 'T' was bound to 'Id'. - // Does not check for a certain number of matches. - explicit VerifyIdIsBoundToDecl(const std::string& Id) - : Id(Id), ExpectedCount(-1), Count(0) {} - - // Create an object that checks that a node of type 'T' was bound to 'Id'. - // Checks that there were exactly 'ExpectedCount' matches. - explicit VerifyIdIsBoundToDecl(const std::string& Id, int ExpectedCount) - : Id(Id), ExpectedCount(ExpectedCount), Count(0) {} - - ~VerifyIdIsBoundToDecl() { - if (ExpectedCount != -1) { - EXPECT_EQ(ExpectedCount, Count); - } - } - - virtual bool run(const BoundNodes *Nodes) { - if (Nodes->getDeclAs<T>(Id) != NULL) { - ++Count; - return true; - } - return false; - } - -private: - const std::string Id; - const int ExpectedCount; - int Count; -}; -template <typename T> -class VerifyIdIsBoundToStmt : public BoundNodesCallback { -public: - explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {} - virtual bool run(const BoundNodes *Nodes) { - const T *Node = Nodes->getStmtAs<T>(Id); - return Node != NULL; - } -private: - const std::string Id; -}; - TEST(Matcher, BindMatchedNodes) { - DeclarationMatcher ClassX = has(record(hasName("::X")).bind("x")); + DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x")); EXPECT_TRUE(matchAndVerifyResultTrue("class X {};", - ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x"))); + ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("x"))); EXPECT_TRUE(matchAndVerifyResultFalse("class X {};", - ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id"))); + ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("other-id"))); TypeMatcher TypeAHasClassB = hasDeclaration( - record(hasName("A"), has(record(hasName("B")).bind("b")))); + recordDecl(hasName("A"), has(recordDecl(hasName("B")).bind("b")))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };", TypeAHasClassB, - new VerifyIdIsBoundToDecl<Decl>("b"))); + new VerifyIdIsBoundTo<Decl>("b"))); - StatementMatcher MethodX = call(callee(method(hasName("x")))).bind("x"); + StatementMatcher MethodX = + callExpr(callee(methodDecl(hasName("x")))).bind("x"); EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };", MethodX, - new VerifyIdIsBoundToStmt<CXXMemberCallExpr>("x"))); + new VerifyIdIsBoundTo<CXXMemberCallExpr>("x"))); } TEST(Matcher, BindTheSameNameInAlternatives) { StatementMatcher matcher = anyOf( binaryOperator(hasOperatorName("+"), - hasLHS(expression().bind("x")), + hasLHS(expr().bind("x")), hasRHS(integerLiteral(equals(0)))), binaryOperator(hasOperatorName("+"), hasLHS(integerLiteral(equals(0))), - hasRHS(expression().bind("x")))); + 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, - new VerifyIdIsBoundToStmt<CallExpr>("x"))); + new 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)))), + new VerifyIdIsBoundTo<Decl>("x", 2))); } TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { - TypeMatcher ClassX = hasDeclaration(record(hasName("X"))); + TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X"))); EXPECT_TRUE( - matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX)))); + matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX)))); EXPECT_TRUE( notMatches("class X {}; void y(X *x) { x; }", - expression(hasType(ClassX)))); + expr(hasType(ClassX)))); EXPECT_TRUE( matches("class X {}; void y(X *x) { x; }", - expression(hasType(pointsTo(ClassX))))); + expr(hasType(pointsTo(ClassX))))); } TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) { - TypeMatcher ClassX = hasDeclaration(record(hasName("X"))); + TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X"))); EXPECT_TRUE( - matches("class X {}; void y() { X x; }", variable(hasType(ClassX)))); + matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX)))); EXPECT_TRUE( - notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX)))); + notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX)))); EXPECT_TRUE( matches("class X {}; void y() { X *x; }", - variable(hasType(pointsTo(ClassX))))); + varDecl(hasType(pointsTo(ClassX))))); } TEST(HasType, TakesDeclMatcherAndMatchesExpr) { - DeclarationMatcher ClassX = record(hasName("X")); + DeclarationMatcher ClassX = recordDecl(hasName("X")); EXPECT_TRUE( - matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX)))); + matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX)))); EXPECT_TRUE( notMatches("class X {}; void y(X *x) { x; }", - expression(hasType(ClassX)))); + expr(hasType(ClassX)))); } TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) { - DeclarationMatcher ClassX = record(hasName("X")); + DeclarationMatcher ClassX = recordDecl(hasName("X")); EXPECT_TRUE( - matches("class X {}; void y() { X x; }", variable(hasType(ClassX)))); + matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX)))); EXPECT_TRUE( - notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX)))); + notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX)))); } TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take // Matcher<Decl>, too? - StatementMatcher MethodX = call(hasDeclaration(method(hasName("x")))); + StatementMatcher MethodX = callExpr(hasDeclaration(methodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX)); - StatementMatcher MethodOnY = memberCall(on(hasType(record(hasName("Y"))))); + StatementMatcher MethodOnY = + memberCallExpr(on(hasType(recordDecl(hasName("Y"))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -732,7 +846,7 @@ TEST(Matcher, Call) { MethodOnY)); StatementMatcher MethodOnYPointer = - memberCall(on(hasType(pointsTo(record(hasName("Y")))))); + memberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", @@ -751,20 +865,50 @@ TEST(Matcher, Call) { MethodOnYPointer)); } +TEST(Matcher, Lambda) { + EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };", + lambdaExpr())); +} + +TEST(Matcher, ForRange) { + EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };" + "void f() { for (auto &a : as); }", + forRangeStmt())); + EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }", + forRangeStmt())); +} + +TEST(Matcher, UserDefinedLiteral) { + EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {" + " return i + 1;" + "}" + "char c = 'a'_inc;", + userDefinedLiteral())); +} + +TEST(Matcher, FlowControl) { + EXPECT_TRUE(matches("void f() { while(true) { break; } }", breakStmt())); + EXPECT_TRUE(matches("void f() { while(true) { continue; } }", + continueStmt())); + EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt())); + EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", labelStmt())); + EXPECT_TRUE(matches("void f() { return; }", returnStmt())); +} + TEST(HasType, MatchesAsString) { EXPECT_TRUE( matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }", - memberCall(on(hasType(asString("class Y *")))))); + memberCallExpr(on(hasType(asString("class Y *")))))); EXPECT_TRUE(matches("class X { void x(int x) {} };", - method(hasParameter(0, hasType(asString("int")))))); + methodDecl(hasParameter(0, hasType(asString("int")))))); EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };", - field(hasType(asString("ns::A"))))); + fieldDecl(hasType(asString("ns::A"))))); EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };", - field(hasType(asString("struct <anonymous>::A"))))); + fieldDecl(hasType(asString("struct <anonymous>::A"))))); } TEST(Matcher, OverloadedOperatorCall) { - StatementMatcher OpCall = overloadedOperatorCall(); + StatementMatcher OpCall = operatorCallExpr(); // Unary operator EXPECT_TRUE(matches("class Y { }; " "bool operator!(Y x) { return false; }; " @@ -791,12 +935,12 @@ TEST(Matcher, OverloadedOperatorCall) { TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { StatementMatcher OpCallAndAnd = - overloadedOperatorCall(hasOverloadedOperatorName("&&")); + operatorCallExpr(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 = - overloadedOperatorCall(hasOverloadedOperatorName("<<")); + operatorCallExpr(hasOverloadedOperatorName("<<")); EXPECT_TRUE(notMatches("class Y { }; " "bool operator&&(Y x, Y y) { return true; }; " "Y a; Y b; bool c = a && b;", @@ -805,7 +949,7 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { TEST(Matcher, ThisPointerType) { StatementMatcher MethodOnY = - memberCall(thisPointerType(record(hasName("Y")))); + memberCallExpr(thisPointerType(recordDecl(hasName("Y")))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -835,9 +979,9 @@ TEST(Matcher, ThisPointerType) { TEST(Matcher, VariableUsage) { StatementMatcher Reference = - declarationReference(to( - variable(hasInitializer( - memberCall(thisPointerType(record(hasName("Y")))))))); + declRefExpr(to( + varDecl(hasInitializer( + memberCallExpr(thisPointerType(recordDecl(hasName("Y")))))))); EXPECT_TRUE(matches( "class Y {" @@ -862,12 +1006,12 @@ TEST(Matcher, VariableUsage) { TEST(Matcher, FindsVarDeclInFuncitonParameter) { EXPECT_TRUE(matches( "void f(int i) {}", - variable(hasName("i")))); + varDecl(hasName("i")))); } TEST(Matcher, CalledVariable) { - StatementMatcher CallOnVariableY = expression( - memberCall(on(declarationReference(to(variable(hasName("y"))))))); + StatementMatcher CallOnVariableY = + memberCallExpr(on(declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(matches( "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY)); @@ -904,81 +1048,81 @@ TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) { hasArgumentOfType(asString("float"))))); EXPECT_TRUE(matches( "struct A {}; void x() { A a; int b = sizeof(a); }", - sizeOfExpr(hasArgumentOfType(hasDeclaration(record(hasName("A"))))))); + sizeOfExpr(hasArgumentOfType(hasDeclaration(recordDecl(hasName("A"))))))); EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr( - hasArgumentOfType(hasDeclaration(record(hasName("string"))))))); + hasArgumentOfType(hasDeclaration(recordDecl(hasName("string"))))))); } TEST(MemberExpression, DoesNotMatchClasses) { - EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression())); + EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr())); } TEST(MemberExpression, MatchesMemberFunctionCall) { - EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpression())); + EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr())); } TEST(MemberExpression, MatchesVariable) { EXPECT_TRUE( - matches("class Y { void x() { this->y; } int y; };", memberExpression())); + matches("class Y { void x() { this->y; } int y; };", memberExpr())); EXPECT_TRUE( - matches("class Y { void x() { y; } int y; };", memberExpression())); + matches("class Y { void x() { y; } int y; };", memberExpr())); EXPECT_TRUE( - matches("class Y { void x() { Y y; y.y; } int y; };", - memberExpression())); + matches("class Y { void x() { Y y; y.y; } int y; };", memberExpr())); } TEST(MemberExpression, MatchesStaticVariable) { EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };", - memberExpression())); + memberExpr())); EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };", - memberExpression())); + memberExpr())); EXPECT_TRUE(notMatches("class Y { void x() { Y::y; } static int y; };", - memberExpression())); + memberExpr())); } TEST(IsInteger, MatchesIntegers) { - EXPECT_TRUE(matches("int i = 0;", variable(hasType(isInteger())))); - EXPECT_TRUE(matches("long long i = 0; void f(long long) { }; void g() {f(i);}", - call(hasArgument(0, declarationReference( - to(variable(hasType(isInteger())))))))); + 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;", variable(hasType(isInteger())))); + EXPECT_TRUE(notMatches("int *i;", varDecl(hasType(isInteger())))); EXPECT_TRUE(notMatches("struct T {}; T t; void f(T *) { }; void g() {f(&t);}", - call(hasArgument(0, declarationReference( - to(variable(hasType(isInteger())))))))); + callExpr(hasArgument(0, declRefExpr( + to(varDecl(hasType(isInteger())))))))); } TEST(IsArrow, MatchesMemberVariablesViaArrow) { EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(matches("class Y { void x() { y; } int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); } TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) { EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } static int y; };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); } TEST(IsArrow, MatchesMemberCallsViaArrow) { EXPECT_TRUE(matches("class Y { void x() { this->x(); } };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };", - memberExpression(isArrow()))); + memberExpr(isArrow()))); } TEST(Callee, MatchesDeclarations) { - StatementMatcher CallMethodX = call(callee(method(hasName("x")))); + StatementMatcher CallMethodX = callExpr(callee(methodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX)); @@ -986,13 +1130,13 @@ TEST(Callee, MatchesDeclarations) { TEST(Callee, MatchesMemberExpressions) { EXPECT_TRUE(matches("class Y { void x() { this->x(); } };", - call(callee(memberExpression())))); + callExpr(callee(memberExpr())))); EXPECT_TRUE( - notMatches("class Y { void x() { this->x(); } };", call(callee(call())))); + notMatches("class Y { void x() { this->x(); } };", callExpr(callee(callExpr())))); } TEST(Function, MatchesFunctionDeclarations) { - StatementMatcher CallFunctionF = call(callee(function(hasName("f")))); + StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f")))); EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF)); EXPECT_TRUE(notMatches("void f() { }", CallFunctionF)); @@ -1017,30 +1161,51 @@ TEST(Function, MatchesFunctionDeclarations) { CallFunctionF)); } +TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) { + EXPECT_TRUE( + matches("template <typename T> void f(T t) {}", + functionTemplateDecl(hasName("f")))); +} + +TEST(FunctionTemplate, DoesNotMatchFunctionDeclarations) { + EXPECT_TRUE( + notMatches("void f(double d); void f(int t) {}", + functionTemplateDecl(hasName("f")))); +} + +TEST(FunctionTemplate, DoesNotMatchFunctionTemplateSpecializations) { + EXPECT_TRUE( + notMatches("void g(); template <typename T> void f(T t) {}" + "template <> void f(int t) { g(); }", + functionTemplateDecl(hasName("f"), + hasDescendant(declRefExpr(to( + functionDecl(hasName("g")))))))); +} + TEST(Matcher, Argument) { - StatementMatcher CallArgumentY = expression(call( - hasArgument(0, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher CallArgumentY = callExpr( + hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(matches("void x(int) { int y; x(y); }", CallArgumentY)); EXPECT_TRUE( matches("class X { void x(int) { int y; x(y); } };", CallArgumentY)); EXPECT_TRUE(notMatches("void x(int) { int z; x(z); }", CallArgumentY)); - StatementMatcher WrongIndex = expression(call( - hasArgument(42, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher WrongIndex = callExpr( + hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex)); } TEST(Matcher, AnyArgument) { - StatementMatcher CallArgumentY = expression(call( - hasAnyArgument(declarationReference(to(variable(hasName("y"))))))); + StatementMatcher CallArgumentY = callExpr( + hasAnyArgument(declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }", CallArgumentY)); EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY)); EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY)); } TEST(Matcher, ArgumentCount) { - StatementMatcher Call1Arg = expression(call(argumentCountIs(1))); + 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)); @@ -1048,8 +1213,8 @@ TEST(Matcher, ArgumentCount) { } TEST(Matcher, References) { - DeclarationMatcher ReferenceClassX = variable( - hasType(references(record(hasName("X"))))); + DeclarationMatcher ReferenceClassX = varDecl( + hasType(references(recordDecl(hasName("X"))))); EXPECT_TRUE(matches("class X {}; void y(X y) { X &x = y; }", ReferenceClassX)); EXPECT_TRUE( @@ -1062,81 +1227,86 @@ TEST(Matcher, References) { TEST(HasParameter, CallsInnerMatcher) { EXPECT_TRUE(matches("class X { void x(int) {} };", - method(hasParameter(0, variable())))); + methodDecl(hasParameter(0, varDecl())))); EXPECT_TRUE(notMatches("class X { void x(int) {} };", - method(hasParameter(0, hasName("x"))))); + methodDecl(hasParameter(0, hasName("x"))))); } TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) { EXPECT_TRUE(notMatches("class X { void x(int) {} };", - method(hasParameter(42, variable())))); + methodDecl(hasParameter(42, varDecl())))); } TEST(HasType, MatchesParameterVariableTypesStrictly) { EXPECT_TRUE(matches("class X { void x(X x) {} };", - method(hasParameter(0, hasType(record(hasName("X"))))))); + methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };", - method(hasParameter(0, hasType(record(hasName("X"))))))); + methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(matches("class X { void x(const X *x) {} };", - method(hasParameter(0, hasType(pointsTo(record(hasName("X")))))))); + methodDecl(hasParameter(0, + hasType(pointsTo(recordDecl(hasName("X")))))))); EXPECT_TRUE(matches("class X { void x(const X &x) {} };", - method(hasParameter(0, hasType(references(record(hasName("X")))))))); + methodDecl(hasParameter(0, + hasType(references(recordDecl(hasName("X")))))))); } TEST(HasAnyParameter, MatchesIndependentlyOfPosition) { EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };", - method(hasAnyParameter(hasType(record(hasName("X"))))))); + methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };", - method(hasAnyParameter(hasType(record(hasName("X"))))))); + methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(Returns, MatchesReturnTypes) { EXPECT_TRUE(matches("class Y { int f() { return 1; } };", - function(returns(asString("int"))))); + functionDecl(returns(asString("int"))))); EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };", - function(returns(asString("float"))))); + functionDecl(returns(asString("float"))))); EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };", - function(returns(hasDeclaration(record(hasName("Y"))))))); + functionDecl(returns(hasDeclaration( + recordDecl(hasName("Y"))))))); } TEST(IsExternC, MatchesExternCFunctionDeclarations) { - EXPECT_TRUE(matches("extern \"C\" void f() {}", function(isExternC()))); - EXPECT_TRUE(matches("extern \"C\" { void f() {} }", function(isExternC()))); - EXPECT_TRUE(notMatches("void f() {}", function(isExternC()))); + 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(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - method(hasAnyParameter(hasType(record(hasName("X"))))))); + methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(HasAnyParameter, DoesNotMatchThisPointer) { EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };", - method(hasAnyParameter(hasType(pointsTo(record(hasName("X")))))))); + methodDecl(hasAnyParameter(hasType(pointsTo( + recordDecl(hasName("X")))))))); } TEST(HasName, MatchesParameterVariableDeclartions) { EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };", - method(hasAnyParameter(hasName("x"))))); + methodDecl(hasAnyParameter(hasName("x"))))); EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - method(hasAnyParameter(hasName("x"))))); + methodDecl(hasAnyParameter(hasName("x"))))); } TEST(Matcher, MatchesClassTemplateSpecialization) { EXPECT_TRUE(matches("template<typename T> struct A {};" "template<> struct A<int> {};", - classTemplateSpecialization())); + classTemplateSpecializationDecl())); EXPECT_TRUE(matches("template<typename T> struct A {}; A<int> a;", - classTemplateSpecialization())); + classTemplateSpecializationDecl())); EXPECT_TRUE(notMatches("template<typename T> struct A {};", - classTemplateSpecialization())); + classTemplateSpecializationDecl())); } TEST(Matcher, MatchesTypeTemplateArgument) { EXPECT_TRUE(matches( "template<typename T> struct B {};" "B<int> b;", - classTemplateSpecialization(hasAnyTemplateArgument(refersToType( + classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( asString("int")))))); } @@ -1145,25 +1315,31 @@ TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) { "struct B { int next; };" "template<int(B::*next_ptr)> struct A {};" "A<&B::next> a;", - classTemplateSpecialization(hasAnyTemplateArgument( - refersToDeclaration(field(hasName("next"))))))); + classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToDeclaration(fieldDecl(hasName("next"))))))); + + EXPECT_TRUE(notMatches( + "template <typename T> struct A {};" + "A<int> a;", + classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToDeclaration(decl()))))); } TEST(Matcher, MatchesSpecificArgument) { EXPECT_TRUE(matches( "template<typename T, typename U> class A {};" "A<bool, int> a;", - classTemplateSpecialization(hasTemplateArgument( + classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))))); EXPECT_TRUE(notMatches( "template<typename T, typename U> class A {};" "A<int, bool> a;", - classTemplateSpecialization(hasTemplateArgument( + classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))))); } TEST(Matcher, ConstructorCall) { - StatementMatcher Constructor = expression(constructorCall()); + StatementMatcher Constructor = constructExpr(); EXPECT_TRUE( matches("class X { public: X(); }; void x() { X x; }", Constructor)); @@ -1177,8 +1353,8 @@ TEST(Matcher, ConstructorCall) { } TEST(Matcher, ConstructorArgument) { - StatementMatcher Constructor = expression(constructorCall( - hasArgument(0, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher Constructor = constructExpr( + hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { int y; X x(y); }", @@ -1193,16 +1369,15 @@ TEST(Matcher, ConstructorArgument) { notMatches("class X { public: X(int); }; void x() { int z; X x(z); }", Constructor)); - StatementMatcher WrongIndex = expression(constructorCall( - hasArgument(42, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher WrongIndex = constructExpr( + 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 = - expression(constructorCall(argumentCountIs(1))); + StatementMatcher Constructor1Arg = constructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { X x(0); }", @@ -1218,8 +1393,15 @@ TEST(Matcher, ConstructorArgumentCount) { Constructor1Arg)); } +TEST(Matcher,ThisExpr) { + EXPECT_TRUE( + matches("struct X { int a; int f () { return a; } };", thisExpr())); + EXPECT_TRUE( + notMatches("struct X { int f () { int a; return a; } };", thisExpr())); +} + TEST(Matcher, BindTemporaryExpression) { - StatementMatcher TempExpression = expression(bindTemporaryExpression()); + StatementMatcher TempExpression = bindTemporaryExpr(); std::string ClassString = "class string { public: string(); ~string(); }; "; @@ -1249,44 +1431,80 @@ TEST(Matcher, BindTemporaryExpression) { TempExpression)); } +TEST(MaterializeTemporaryExpr, MatchesTemporary) { + std::string ClassString = + "class string { public: string(); int length(); }; "; + + EXPECT_TRUE( + matches(ClassString + + "string GetStringByValue();" + "void FunctionTakesString(string s);" + "void run() { FunctionTakesString(GetStringByValue()); }", + materializeTemporaryExpr())); + + EXPECT_TRUE( + notMatches(ClassString + + "string* GetStringPointer(); " + "void FunctionTakesStringPtr(string* s);" + "void run() {" + " string* s = GetStringPointer();" + " FunctionTakesStringPtr(GetStringPointer());" + " FunctionTakesStringPtr(s);" + "}", + materializeTemporaryExpr())); + + EXPECT_TRUE( + notMatches(ClassString + + "string GetStringByValue();" + "void run() { int k = GetStringByValue().length(); }", + materializeTemporaryExpr())); + + EXPECT_TRUE( + notMatches(ClassString + + "string GetStringByValue();" + "void run() { GetStringByValue(); }", + materializeTemporaryExpr())); +} + TEST(ConstructorDeclaration, SimpleCase) { EXPECT_TRUE(matches("class Foo { Foo(int i); };", - constructor(ofClass(hasName("Foo"))))); + constructorDecl(ofClass(hasName("Foo"))))); EXPECT_TRUE(notMatches("class Foo { Foo(int i); };", - constructor(ofClass(hasName("Bar"))))); + constructorDecl(ofClass(hasName("Bar"))))); } 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 { };", - constructor(isImplicit()))); + constructorDecl(isImplicit()))); // The compiler added the implicit default constructor. EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();", - constructor(isImplicit()))); + constructorDecl(isImplicit()))); EXPECT_TRUE(matches("class Foo { Foo(){} };", - constructor(unless(isImplicit())))); + constructorDecl(unless(isImplicit())))); } TEST(DestructorDeclaration, MatchesVirtualDestructor) { EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };", - destructor(ofClass(hasName("Foo"))))); + destructorDecl(ofClass(hasName("Foo"))))); } TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) { - EXPECT_TRUE(notMatches("class Foo {};", destructor(ofClass(hasName("Foo"))))); + EXPECT_TRUE(notMatches("class Foo {};", + destructorDecl(ofClass(hasName("Foo"))))); } TEST(HasAnyConstructorInitializer, SimpleCase) { EXPECT_TRUE(notMatches( "class Foo { Foo() { } };", - constructor(hasAnyConstructorInitializer(anything())))); + constructorDecl(hasAnyConstructorInitializer(anything())))); EXPECT_TRUE(matches( "class Foo {" " Foo() : foo_() { }" " int foo_;" "};", - constructor(hasAnyConstructorInitializer(anything())))); + constructorDecl(hasAnyConstructorInitializer(anything())))); } TEST(HasAnyConstructorInitializer, ForField) { @@ -1297,12 +1515,12 @@ TEST(HasAnyConstructorInitializer, ForField) { " Baz foo_;" " Baz bar_;" "};"; - EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer( - forField(hasType(record(hasName("Baz")))))))); - EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + forField(hasType(recordDecl(hasName("Baz")))))))); + EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( forField(hasName("foo_")))))); - EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer( - forField(hasType(record(hasName("Bar")))))))); + EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + forField(hasType(recordDecl(hasName("Bar")))))))); } TEST(HasAnyConstructorInitializer, WithInitializer) { @@ -1311,9 +1529,9 @@ TEST(HasAnyConstructorInitializer, WithInitializer) { " Foo() : foo_(0) { }" " int foo_;" "};"; - EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(0))))))); - EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(1))))))); } @@ -1325,16 +1543,16 @@ TEST(HasAnyConstructorInitializer, IsWritten) { " Bar foo_;" " Bar bar_;" "};"; - EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("foo_")), isWritten()))))); - EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), isWritten()))))); - EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), unless(isWritten())))))); } TEST(Matcher, NewExpression) { - StatementMatcher New = expression(newExpression()); + StatementMatcher New = newExpr(); EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New)); EXPECT_TRUE( @@ -1345,9 +1563,8 @@ TEST(Matcher, NewExpression) { } TEST(Matcher, NewExpressionArgument) { - StatementMatcher New = expression(constructorCall( - hasArgument( - 0, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher New = constructExpr( + hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { int y; new X(y); }", @@ -1359,16 +1576,15 @@ TEST(Matcher, NewExpressionArgument) { notMatches("class X { public: X(int); }; void x() { int z; new X(z); }", New)); - StatementMatcher WrongIndex = expression(constructorCall( - hasArgument( - 42, declarationReference(to(variable(hasName("y"))))))); + StatementMatcher WrongIndex = constructExpr( + hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( notMatches("class X { public: X(int); }; void x() { int y; new X(y); }", WrongIndex)); } TEST(Matcher, NewExpressionArgumentCount) { - StatementMatcher New = constructorCall(argumentCountIs(1)); + StatementMatcher New = constructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { new X(0); }", New)); @@ -1379,11 +1595,11 @@ TEST(Matcher, NewExpressionArgumentCount) { TEST(Matcher, DeleteExpression) { EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }", - deleteExpression())); + deleteExpr())); } TEST(Matcher, DefaultArgument) { - StatementMatcher Arg = defaultArgument(); + StatementMatcher Arg = defaultArgExpr(); EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg)); EXPECT_TRUE( @@ -1392,7 +1608,7 @@ TEST(Matcher, DefaultArgument) { } TEST(Matcher, StringLiterals) { - StatementMatcher Literal = expression(stringLiteral()); + StatementMatcher Literal = stringLiteral(); EXPECT_TRUE(matches("const char *s = \"string\";", Literal)); // wide string EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", Literal)); @@ -1403,7 +1619,7 @@ TEST(Matcher, StringLiterals) { } TEST(Matcher, CharacterLiterals) { - StatementMatcher CharLiteral = expression(characterLiteral()); + StatementMatcher CharLiteral = characterLiteral(); EXPECT_TRUE(matches("const char c = 'c';", CharLiteral)); // wide character EXPECT_TRUE(matches("const char c = L'c';", CharLiteral)); @@ -1413,7 +1629,7 @@ TEST(Matcher, CharacterLiterals) { } TEST(Matcher, IntegerLiterals) { - StatementMatcher HasIntLiteral = expression(integerLiteral()); + StatementMatcher HasIntLiteral = integerLiteral(); EXPECT_TRUE(matches("int i = 10;", HasIntLiteral)); EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral)); EXPECT_TRUE(matches("int i = 10L;", HasIntLiteral)); @@ -1428,6 +1644,14 @@ TEST(Matcher, IntegerLiterals) { EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral)); } +TEST(Matcher, NullPtrLiteral) { + EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr())); +} + +TEST(Matcher, AsmStatement) { + EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt())); +} + TEST(Matcher, Conditions) { StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true)))); @@ -1654,87 +1878,91 @@ TEST(ArraySubscriptMatchers, ArrayIndex) { TEST(ArraySubscriptMatchers, MatchesArrayBase) { EXPECT_TRUE(matches( "int i[2]; void f() { i[1] = 2; }", - arraySubscriptExpr(hasBase(implicitCast( - hasSourceExpression(declarationReference())))))); + arraySubscriptExpr(hasBase(implicitCastExpr( + hasSourceExpression(declRefExpr())))))); } TEST(Matcher, HasNameSupportsNamespaces) { EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", - record(hasName("a::b::C")))); + recordDecl(hasName("a::b::C")))); EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", - record(hasName("::a::b::C")))); + recordDecl(hasName("::a::b::C")))); EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", - record(hasName("b::C")))); + recordDecl(hasName("b::C")))); EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", - record(hasName("C")))); + recordDecl(hasName("C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("c::b::C")))); + recordDecl(hasName("c::b::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("a::c::C")))); + recordDecl(hasName("a::c::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("a::b::A")))); + recordDecl(hasName("a::b::A")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("::C")))); + recordDecl(hasName("::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("::b::C")))); + recordDecl(hasName("::b::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("z::a::b::C")))); + recordDecl(hasName("z::a::b::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }", - record(hasName("a+b::C")))); + recordDecl(hasName("a+b::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }", - record(hasName("C")))); + recordDecl(hasName("C")))); } TEST(Matcher, HasNameSupportsOuterClasses) { EXPECT_TRUE( - matches("class A { class B { class C; }; };", record(hasName("A::B::C")))); + matches("class A { class B { class C; }; };", + recordDecl(hasName("A::B::C")))); EXPECT_TRUE( matches("class A { class B { class C; }; };", - record(hasName("::A::B::C")))); + recordDecl(hasName("::A::B::C")))); EXPECT_TRUE( - matches("class A { class B { class C; }; };", record(hasName("B::C")))); + matches("class A { class B { class C; }; };", + recordDecl(hasName("B::C")))); EXPECT_TRUE( - matches("class A { class B { class C; }; };", record(hasName("C")))); + matches("class A { class B { class C; }; };", + recordDecl(hasName("C")))); EXPECT_TRUE( notMatches("class A { class B { class C; }; };", - record(hasName("c::B::C")))); + recordDecl(hasName("c::B::C")))); EXPECT_TRUE( notMatches("class A { class B { class C; }; };", - record(hasName("A::c::C")))); + recordDecl(hasName("A::c::C")))); EXPECT_TRUE( notMatches("class A { class B { class C; }; };", - record(hasName("A::B::A")))); + recordDecl(hasName("A::B::A")))); EXPECT_TRUE( - notMatches("class A { class B { class C; }; };", record(hasName("::C")))); + notMatches("class A { class B { class C; }; };", + recordDecl(hasName("::C")))); EXPECT_TRUE( notMatches("class A { class B { class C; }; };", - record(hasName("::B::C")))); + recordDecl(hasName("::B::C")))); EXPECT_TRUE(notMatches("class A { class B { class C; }; };", - record(hasName("z::A::B::C")))); + recordDecl(hasName("z::A::B::C")))); EXPECT_TRUE( notMatches("class A { class B { class C; }; };", - record(hasName("A+B::C")))); + recordDecl(hasName("A+B::C")))); } TEST(Matcher, IsDefinition) { DeclarationMatcher DefinitionOfClassA = - record(hasName("A"), isDefinition()); + recordDecl(hasName("A"), isDefinition()); EXPECT_TRUE(matches("class A {};", DefinitionOfClassA)); EXPECT_TRUE(notMatches("class A;", DefinitionOfClassA)); DeclarationMatcher DefinitionOfVariableA = - variable(hasName("a"), isDefinition()); + varDecl(hasName("a"), isDefinition()); EXPECT_TRUE(matches("int a;", DefinitionOfVariableA)); EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA)); DeclarationMatcher DefinitionOfMethodA = - method(hasName("a"), isDefinition()); + methodDecl(hasName("a"), isDefinition()); EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA)); EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA)); } TEST(Matcher, OfClass) { - StatementMatcher Constructor = constructorCall(hasDeclaration(method( + StatementMatcher Constructor = constructExpr(hasDeclaration(methodDecl( ofClass(hasName("X"))))); EXPECT_TRUE( @@ -1751,7 +1979,8 @@ TEST(Matcher, VisitsTemplateInstantiations) { EXPECT_TRUE(matches( "class A { public: void x(); };" "template <typename T> class B { public: void y() { T t; t.x(); } };" - "void f() { B<A> b; b.y(); }", call(callee(method(hasName("x")))))); + "void f() { B<A> b; b.y(); }", + callExpr(callee(methodDecl(hasName("x")))))); EXPECT_TRUE(matches( "class A { public: void x(); };" @@ -1761,8 +1990,9 @@ TEST(Matcher, VisitsTemplateInstantiations) { "};" "void f() {" " C::B<A> b; b.y();" - "}", record(hasName("C"), - hasDescendant(call(callee(method(hasName("x")))))))); + "}", + recordDecl(hasName("C"), + hasDescendant(callExpr(callee(methodDecl(hasName("x")))))))); } TEST(Matcher, HandlesNullQualTypes) { @@ -1781,7 +2011,7 @@ TEST(Matcher, HandlesNullQualTypes) { "void g() {" " f(0);" "}", - expression(hasType(TypeMatcher( + expr(hasType(TypeMatcher( anyOf( TypeMatcher(hasDeclaration(anything())), pointsTo(AnyType), @@ -1798,16 +2028,16 @@ AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) { } TEST(AstMatcherPMacro, Works) { - DeclarationMatcher HasClassB = just(has(record(hasName("B")).bind("b"))); + DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b"))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("b"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("b"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("a"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("a"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("b"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("b"))); } AST_POLYMORPHIC_MATCHER_P( @@ -1815,27 +2045,27 @@ AST_POLYMORPHIC_MATCHER_P( TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) || (llvm::is_same<NodeType, Stmt>::value), assert_node_type_is_accessible); - internal::TypedBaseMatcher<Decl> ChildMatcher(AMatcher); return Finder->matchesChildOf( - Node, ChildMatcher, Builder, + Node, AMatcher, Builder, ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses, ASTMatchFinder::BK_First); } TEST(AstPolymorphicMatcherPMacro, Works) { - DeclarationMatcher HasClassB = polymorphicHas(record(hasName("B")).bind("b")); + DeclarationMatcher HasClassB = + polymorphicHas(recordDecl(hasName("B")).bind("b")); EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("b"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("b"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("a"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("a"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };", - HasClassB, new VerifyIdIsBoundToDecl<Decl>("b"))); + HasClassB, new VerifyIdIsBoundTo<Decl>("b"))); StatementMatcher StatementHasClassB = - polymorphicHas(record(hasName("B"))); + polymorphicHas(recordDecl(hasName("B"))); EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB)); } @@ -1843,6 +2073,9 @@ TEST(AstPolymorphicMatcherPMacro, Works) { TEST(For, FindsForLoops) { EXPECT_TRUE(matches("void f() { for(;;); }", forStmt())); EXPECT_TRUE(matches("void f() { if(true) for(;;); }", forStmt())); + EXPECT_TRUE(notMatches("int as[] = { 1, 2, 3 };" + "void f() { for (auto &a : as); }", + forStmt())); } TEST(For, ForLoopInternals) { @@ -1854,7 +2087,7 @@ TEST(For, ForLoopInternals) { TEST(For, NegativeForLoopInternals) { EXPECT_TRUE(notMatches("void f(){ for (int i = 0; ; ++i); }", - forStmt(hasCondition(expression())))); + forStmt(hasCondition(expr())))); EXPECT_TRUE(notMatches("void f() {int i; for (; i < 4; ++i) {} }", forStmt(hasLoopInit(anything())))); } @@ -1865,29 +2098,29 @@ TEST(For, ReportsNoFalsePositives) { } TEST(CompoundStatement, HandlesSimpleCases) { - EXPECT_TRUE(notMatches("void f();", compoundStatement())); - EXPECT_TRUE(matches("void f() {}", compoundStatement())); - EXPECT_TRUE(matches("void f() {{}}", compoundStatement())); + EXPECT_TRUE(notMatches("void f();", compoundStmt())); + EXPECT_TRUE(matches("void f() {}", compoundStmt())); + EXPECT_TRUE(matches("void f() {{}}", compoundStmt())); } TEST(CompoundStatement, DoesNotMatchEmptyStruct) { // It's not a compound statement just because there's "{}" in the source // text. This is an AST search, not grep. EXPECT_TRUE(notMatches("namespace n { struct S {}; }", - compoundStatement())); + compoundStmt())); EXPECT_TRUE(matches("namespace n { struct S { void f() {{}} }; }", - compoundStatement())); + compoundStmt())); } TEST(HasBody, FindsBodyOfForWhileDoLoops) { EXPECT_TRUE(matches("void f() { for(;;) {} }", - forStmt(hasBody(compoundStatement())))); + forStmt(hasBody(compoundStmt())))); EXPECT_TRUE(notMatches("void f() { for(;;); }", - forStmt(hasBody(compoundStatement())))); + forStmt(hasBody(compoundStmt())))); EXPECT_TRUE(matches("void f() { while(true) {} }", - whileStmt(hasBody(compoundStatement())))); + whileStmt(hasBody(compoundStmt())))); EXPECT_TRUE(matches("void f() { do {} while(true); }", - doStmt(hasBody(compoundStatement())))); + doStmt(hasBody(compoundStmt())))); } TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { @@ -1895,67 +2128,67 @@ TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { // definition, and the function body itself must be a compound // statement. EXPECT_TRUE(matches("void f() { for (;;); }", - compoundStatement(hasAnySubstatement(forStmt())))); + compoundStmt(hasAnySubstatement(forStmt())))); } TEST(HasAnySubstatement, IsNotRecursive) { // It's really "has any immediate substatement". EXPECT_TRUE(notMatches("void f() { if (true) for (;;); }", - compoundStatement(hasAnySubstatement(forStmt())))); + compoundStmt(hasAnySubstatement(forStmt())))); } TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) { EXPECT_TRUE(matches("void f() { if (true) { for (;;); } }", - compoundStatement(hasAnySubstatement(forStmt())))); + compoundStmt(hasAnySubstatement(forStmt())))); } TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) { EXPECT_TRUE(matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }", - compoundStatement(hasAnySubstatement(forStmt())))); + compoundStmt(hasAnySubstatement(forStmt())))); } TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) { EXPECT_TRUE(matches("void f() { }", - compoundStatement(statementCountIs(0)))); + compoundStmt(statementCountIs(0)))); EXPECT_TRUE(notMatches("void f() {}", - compoundStatement(statementCountIs(1)))); + compoundStmt(statementCountIs(1)))); } TEST(StatementCountIs, AppearsToMatchOnlyOneCount) { EXPECT_TRUE(matches("void f() { 1; }", - compoundStatement(statementCountIs(1)))); + compoundStmt(statementCountIs(1)))); EXPECT_TRUE(notMatches("void f() { 1; }", - compoundStatement(statementCountIs(0)))); + compoundStmt(statementCountIs(0)))); EXPECT_TRUE(notMatches("void f() { 1; }", - compoundStatement(statementCountIs(2)))); + compoundStmt(statementCountIs(2)))); } TEST(StatementCountIs, WorksWithMultipleStatements) { EXPECT_TRUE(matches("void f() { 1; 2; 3; }", - compoundStatement(statementCountIs(3)))); + compoundStmt(statementCountIs(3)))); } TEST(StatementCountIs, WorksWithNestedCompoundStatements) { EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", - compoundStatement(statementCountIs(1)))); + compoundStmt(statementCountIs(1)))); EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", - compoundStatement(statementCountIs(2)))); + compoundStmt(statementCountIs(2)))); EXPECT_TRUE(notMatches("void f() { { 1; } { 1; 2; 3; 4; } }", - compoundStatement(statementCountIs(3)))); + compoundStmt(statementCountIs(3)))); EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }", - compoundStatement(statementCountIs(4)))); + compoundStmt(statementCountIs(4)))); } TEST(Member, WorksInSimplestCase) { EXPECT_TRUE(matches("struct { int first; } s; int i(s.first);", - memberExpression(member(hasName("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);", - memberExpression(member(hasName("first"))))); + memberExpr(member(hasName("first"))))); } TEST(Member, MatchesInMemberFunctionCall) { @@ -1963,211 +2196,246 @@ TEST(Member, MatchesInMemberFunctionCall) { " struct { void first() {}; } s;" " s.first();" "};", - memberExpression(member(hasName("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, MatchesMemberAllocationFunction) { + // Fails in C++11 mode + EXPECT_TRUE(matchesConditionally( + "namespace std { typedef typeof(sizeof(int)) size_t; }" + "class X { void *operator new(std::size_t); };", + methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); + + EXPECT_TRUE(matches("class X { void operator delete(void*); };", + methodDecl(ofClass(hasName("X"))))); + + // Fails in C++11 mode + EXPECT_TRUE(matchesConditionally( + "namespace std { typedef typeof(sizeof(int)) size_t; }" + "class X { void operator delete[](void*, std::size_t); };", + methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); } TEST(HasObjectExpression, DoesNotMatchMember) { EXPECT_TRUE(notMatches( "class X {}; struct Z { X m; }; void f(Z z) { z.m; }", - memberExpression(hasObjectExpression(hasType(record(hasName("X"))))))); + memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X"))))))); } TEST(HasObjectExpression, MatchesBaseOfVariable) { EXPECT_TRUE(matches( "struct X { int m; }; void f(X x) { x.m; }", - memberExpression(hasObjectExpression(hasType(record(hasName("X"))))))); + memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(matches( "struct X { int m; }; void f(X* x) { x->m; }", - memberExpression(hasObjectExpression( - hasType(pointsTo(record(hasName("X")))))))); + memberExpr(hasObjectExpression( + hasType(pointsTo(recordDecl(hasName("X")))))))); } TEST(HasObjectExpression, MatchesObjectExpressionOfImplicitlyFormedMemberExpression) { EXPECT_TRUE(matches( "class X {}; struct S { X m; void f() { this->m; } };", - memberExpression(hasObjectExpression( - hasType(pointsTo(record(hasName("S")))))))); + memberExpr(hasObjectExpression( + hasType(pointsTo(recordDecl(hasName("S")))))))); EXPECT_TRUE(matches( "class X {}; struct S { X m; void f() { m; } };", - memberExpression(hasObjectExpression( - hasType(pointsTo(record(hasName("S")))))))); + memberExpr(hasObjectExpression( + hasType(pointsTo(recordDecl(hasName("S")))))))); } TEST(Field, DoesNotMatchNonFieldMembers) { - EXPECT_TRUE(notMatches("class X { void m(); };", field(hasName("m")))); - EXPECT_TRUE(notMatches("class X { class m {}; };", field(hasName("m")))); - EXPECT_TRUE(notMatches("class X { enum { m }; };", field(hasName("m")))); - EXPECT_TRUE(notMatches("class X { enum m {}; };", field(hasName("m")))); + 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; };", field(hasName("m")))); + EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m")))); } TEST(IsConstQualified, MatchesConstInt) { EXPECT_TRUE(matches("const int i = 42;", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); } TEST(IsConstQualified, MatchesConstPointer) { EXPECT_TRUE(matches("int i = 42; int* const p(&i);", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); } TEST(IsConstQualified, MatchesThroughTypedef) { EXPECT_TRUE(matches("typedef const int const_int; const_int i = 42;", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); EXPECT_TRUE(matches("typedef int* int_ptr; const int_ptr p(0);", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); } TEST(IsConstQualified, DoesNotMatchInappropriately) { EXPECT_TRUE(notMatches("typedef int nonconst_int; nonconst_int i = 42;", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); EXPECT_TRUE(notMatches("int const* p;", - variable(hasType(isConstQualified())))); + varDecl(hasType(isConstQualified())))); } TEST(CastExpression, MatchesExplicitCasts) { - EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);", - expression(castExpr()))); - EXPECT_TRUE(matches("void *p = (void *)(&p);", expression(castExpr()))); - EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", - expression(castExpr()))); - EXPECT_TRUE(matches("char c = char(0);", expression(castExpr()))); + EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",castExpr())); + EXPECT_TRUE(matches("void *p = (void *)(&p);", castExpr())); + EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", castExpr())); + EXPECT_TRUE(matches("char c = char(0);", castExpr())); } TEST(CastExpression, MatchesImplicitCasts) { // This test creates an implicit cast from int to char. - EXPECT_TRUE(matches("char c = 0;", expression(castExpr()))); + EXPECT_TRUE(matches("char c = 0;", castExpr())); // This test creates an implicit cast from lvalue to rvalue. - EXPECT_TRUE(matches("char c = 0, d = c;", expression(castExpr()))); + EXPECT_TRUE(matches("char c = 0, d = c;", castExpr())); } TEST(CastExpression, DoesNotMatchNonCasts) { - EXPECT_TRUE(notMatches("char c = '0';", expression(castExpr()))); - EXPECT_TRUE(notMatches("char c, &q = c;", expression(castExpr()))); - EXPECT_TRUE(notMatches("int i = (0);", expression(castExpr()))); - EXPECT_TRUE(notMatches("int i = 0;", expression(castExpr()))); + EXPECT_TRUE(notMatches("char c = '0';", castExpr())); + EXPECT_TRUE(notMatches("char c, &q = c;", castExpr())); + EXPECT_TRUE(notMatches("int i = (0);", castExpr())); + EXPECT_TRUE(notMatches("int i = 0;", castExpr())); } TEST(ReinterpretCast, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);", - expression(reinterpretCast()))); + reinterpretCastExpr())); } TEST(ReinterpretCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", - expression(reinterpretCast()))); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", reinterpretCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - expression(reinterpretCast()))); + reinterpretCastExpr())); EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);", - expression(reinterpretCast()))); + reinterpretCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - expression(reinterpretCast()))); + reinterpretCastExpr())); } TEST(FunctionalCast, MatchesSimpleCase) { std::string foo_class = "class Foo { public: Foo(char*); };"; EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }", - expression(functionalCast()))); + functionalCastExpr())); } TEST(FunctionalCast, DoesNotMatchOtherCasts) { std::string FooClass = "class Foo { public: Foo(char*); };"; EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }", - expression(functionalCast()))); + functionalCastExpr())); EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = \"hello world\"; }", - expression(functionalCast()))); + functionalCastExpr())); } TEST(DynamicCast, MatchesSimpleCase) { EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - expression(dynamicCast()))); + dynamicCastExpr())); } TEST(StaticCast, MatchesSimpleCase) { EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));", - expression(staticCast()))); + staticCastExpr())); } TEST(StaticCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", - expression(staticCast()))); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", staticCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - expression(staticCast()))); + staticCastExpr())); EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);", - expression(staticCast()))); + staticCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - expression(staticCast()))); + staticCastExpr())); +} + +TEST(CStyleCast, MatchesSimpleCase) { + EXPECT_TRUE(matches("int i = (int) 2.2f;", cStyleCastExpr())); +} + +TEST(CStyleCast, DoesNotMatchOtherCasts) { + EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);" + "char q, *r = const_cast<char*>(&q);" + "void* s = reinterpret_cast<char*>(&s);" + "struct B { virtual ~B() {} }; struct D : B {};" + "B b;" + "D* t = dynamic_cast<D*>(&b);", + cStyleCastExpr())); } TEST(HasDestinationType, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = static_cast<char*>(0);", - expression( - staticCast(hasDestinationType( - pointsTo(TypeMatcher(anything()))))))); + staticCastExpr(hasDestinationType( + pointsTo(TypeMatcher(anything())))))); } TEST(HasImplicitDestinationType, MatchesSimpleCase) { // This test creates an implicit const cast. EXPECT_TRUE(matches("int x; const int i = x;", - expression(implicitCast( - hasImplicitDestinationType(isInteger()))))); + implicitCastExpr( + hasImplicitDestinationType(isInteger())))); // This test creates an implicit array-to-pointer cast. EXPECT_TRUE(matches("int arr[3]; int *p = arr;", - expression(implicitCast(hasImplicitDestinationType( - pointsTo(TypeMatcher(anything()))))))); + implicitCastExpr(hasImplicitDestinationType( + pointsTo(TypeMatcher(anything())))))); } TEST(HasImplicitDestinationType, DoesNotMatchIncorrectly) { // This test creates an implicit cast from int to char. EXPECT_TRUE(notMatches("char c = 0;", - expression(implicitCast(hasImplicitDestinationType( - unless(anything())))))); + implicitCastExpr(hasImplicitDestinationType( + unless(anything()))))); // This test creates an implicit array-to-pointer cast. EXPECT_TRUE(notMatches("int arr[3]; int *p = arr;", - expression(implicitCast(hasImplicitDestinationType( - unless(anything())))))); + implicitCastExpr(hasImplicitDestinationType( + unless(anything()))))); } TEST(ImplicitCast, MatchesSimpleCase) { // This test creates an implicit const cast. EXPECT_TRUE(matches("int x = 0; const int y = x;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); // This test creates an implicit cast from int to char. EXPECT_TRUE(matches("char c = 0;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); // This test creates an implicit array-to-pointer cast. EXPECT_TRUE(matches("int arr[6]; int *p = arr;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); } TEST(ImplicitCast, DoesNotMatchIncorrectly) { - // This test verifies that implicitCast() matches exactly when implicit casts + // This test verifies that implicitCastExpr() matches exactly when implicit casts // are present, and that it ignores explicit and paren casts. // These two test cases have no casts. EXPECT_TRUE(notMatches("int x = 0;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); EXPECT_TRUE(notMatches("int x = 0, &y = x;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); EXPECT_TRUE(notMatches("int x = 0; double d = (double) x;", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); EXPECT_TRUE(notMatches("const int *p; int *q = const_cast<int *>(p);", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); EXPECT_TRUE(notMatches("int x = (0);", - variable(hasInitializer(implicitCast())))); + varDecl(hasInitializer(implicitCastExpr())))); } TEST(IgnoringImpCasts, MatchesImpCasts) { @@ -2175,11 +2443,11 @@ TEST(IgnoringImpCasts, MatchesImpCasts) { // present and its inner matcher alone does not match. // Note that this test creates an implicit const cast. EXPECT_TRUE(matches("int x = 0; const int y = x;", - variable(hasInitializer(ignoringImpCasts( - declarationReference(to(variable(hasName("x"))))))))); + varDecl(hasInitializer(ignoringImpCasts( + declRefExpr(to(varDecl(hasName("x"))))))))); // This test creates an implict cast from int to char. EXPECT_TRUE(matches("char x = 0;", - variable(hasInitializer(ignoringImpCasts( + varDecl(hasInitializer(ignoringImpCasts( integerLiteral(equals(0))))))); } @@ -2188,82 +2456,82 @@ TEST(IgnoringImpCasts, DoesNotMatchIncorrectly) { // matcher does not match. // Note that the first test creates an implicit const cast. EXPECT_TRUE(notMatches("int x; const int y = x;", - variable(hasInitializer(ignoringImpCasts( + varDecl(hasInitializer(ignoringImpCasts( unless(anything())))))); EXPECT_TRUE(notMatches("int x; int y = x;", - variable(hasInitializer(ignoringImpCasts( + varDecl(hasInitializer(ignoringImpCasts( unless(anything())))))); // These tests verify that ignoringImplictCasts does not look through explicit // casts or parentheses. EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);", - variable(hasInitializer(ignoringImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringImpCasts( + integerLiteral()))))); EXPECT_TRUE(notMatches("int i = (0);", - variable(hasInitializer(ignoringImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringImpCasts( + integerLiteral()))))); EXPECT_TRUE(notMatches("float i = (float)0;", - variable(hasInitializer(ignoringImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringImpCasts( + integerLiteral()))))); EXPECT_TRUE(notMatches("float i = float(0);", - variable(hasInitializer(ignoringImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringImpCasts( + integerLiteral()))))); } TEST(IgnoringImpCasts, MatchesWithoutImpCasts) { // This test verifies that expressions that do not have implicit casts // still match the inner matcher. EXPECT_TRUE(matches("int x = 0; int &y = x;", - variable(hasInitializer(ignoringImpCasts( - declarationReference(to(variable(hasName("x"))))))))); + varDecl(hasInitializer(ignoringImpCasts( + declRefExpr(to(varDecl(hasName("x"))))))))); } TEST(IgnoringParenCasts, MatchesParenCasts) { // This test checks that ignoringParenCasts matches when parentheses and/or // casts are present and its inner matcher alone does not match. EXPECT_TRUE(matches("int x = (0);", - variable(hasInitializer(ignoringParenCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenCasts( + integerLiteral(equals(0))))))); EXPECT_TRUE(matches("int x = (((((0)))));", - variable(hasInitializer(ignoringParenCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenCasts( + integerLiteral(equals(0))))))); // This test creates an implict cast from int to char in addition to the // parentheses. EXPECT_TRUE(matches("char x = (0);", - variable(hasInitializer(ignoringParenCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenCasts( + integerLiteral(equals(0))))))); EXPECT_TRUE(matches("char x = (char)0;", - variable(hasInitializer(ignoringParenCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenCasts( + integerLiteral(equals(0))))))); EXPECT_TRUE(matches("char* p = static_cast<char*>(0);", - variable(hasInitializer(ignoringParenCasts( + varDecl(hasInitializer(ignoringParenCasts( integerLiteral(equals(0))))))); } TEST(IgnoringParenCasts, MatchesWithoutParenCasts) { // This test verifies that expressions that do not have any casts still match. EXPECT_TRUE(matches("int x = 0;", - variable(hasInitializer(ignoringParenCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenCasts( + integerLiteral(equals(0))))))); } TEST(IgnoringParenCasts, DoesNotMatchIncorrectly) { // These tests verify that ignoringImpCasts does not match if the inner // matcher does not match. EXPECT_TRUE(notMatches("int x = ((0));", - variable(hasInitializer(ignoringParenCasts( + varDecl(hasInitializer(ignoringParenCasts( unless(anything())))))); // This test creates an implicit cast from int to char in addition to the // parentheses. EXPECT_TRUE(notMatches("char x = ((0));", - variable(hasInitializer(ignoringParenCasts( + varDecl(hasInitializer(ignoringParenCasts( unless(anything())))))); EXPECT_TRUE(notMatches("char *x = static_cast<char *>((0));", - variable(hasInitializer(ignoringParenCasts( + varDecl(hasInitializer(ignoringParenCasts( unless(anything())))))); } @@ -2273,23 +2541,23 @@ TEST(IgnoringParenAndImpCasts, MatchesParenImpCasts) { // does not match. // Note that this test creates an implicit const cast. EXPECT_TRUE(matches("int x = 0; const int y = x;", - variable(hasInitializer(ignoringParenImpCasts( - declarationReference(to(variable(hasName("x"))))))))); + varDecl(hasInitializer(ignoringParenImpCasts( + declRefExpr(to(varDecl(hasName("x"))))))))); // This test creates an implicit cast from int to char. EXPECT_TRUE(matches("const char x = (0);", - variable(hasInitializer(ignoringParenImpCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral(equals(0))))))); } TEST(IgnoringParenAndImpCasts, MatchesWithoutParenImpCasts) { // This test verifies that expressions that do not have parentheses or // implicit casts still match. EXPECT_TRUE(matches("int x = 0; int &y = x;", - variable(hasInitializer(ignoringParenImpCasts( - declarationReference(to(variable(hasName("x"))))))))); + varDecl(hasInitializer(ignoringParenImpCasts( + declRefExpr(to(varDecl(hasName("x"))))))))); EXPECT_TRUE(matches("int x = 0;", - variable(hasInitializer(ignoringParenImpCasts( - integerLiteral(equals(0))))))); + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral(equals(0))))))); } TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) { @@ -2297,56 +2565,56 @@ TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) { // the inner matcher does not match. // This test creates an implicit cast. EXPECT_TRUE(notMatches("char c = ((3));", - variable(hasInitializer(ignoringParenImpCasts( + varDecl(hasInitializer(ignoringParenImpCasts( unless(anything())))))); // These tests verify that ignoringParenAndImplictCasts does not look // through explicit casts. EXPECT_TRUE(notMatches("float y = (float(0));", - variable(hasInitializer(ignoringParenImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral()))))); EXPECT_TRUE(notMatches("float y = (float)0;", - variable(hasInitializer(ignoringParenImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral()))))); EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);", - variable(hasInitializer(ignoringParenImpCasts( - integerLiteral()))))); + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral()))))); } TEST(HasSourceExpression, MatchesImplicitCasts) { EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };" "void r() {string a_string; URL url = a_string; }", - expression(implicitCast( - hasSourceExpression(constructorCall()))))); + implicitCastExpr( + hasSourceExpression(constructExpr())))); } TEST(HasSourceExpression, MatchesExplicitCasts) { EXPECT_TRUE(matches("float x = static_cast<float>(42);", - expression(explicitCast( - hasSourceExpression(hasDescendant( - expression(integerLiteral()))))))); + explicitCastExpr( + hasSourceExpression(hasDescendant( + expr(integerLiteral())))))); } TEST(Statement, DoesNotMatchDeclarations) { - EXPECT_TRUE(notMatches("class X {};", statement())); + EXPECT_TRUE(notMatches("class X {};", stmt())); } TEST(Statement, MatchesCompoundStatments) { - EXPECT_TRUE(matches("void x() {}", statement())); + EXPECT_TRUE(matches("void x() {}", stmt())); } TEST(DeclarationStatement, DoesNotMatchCompoundStatements) { - EXPECT_TRUE(notMatches("void x() {}", declarationStatement())); + EXPECT_TRUE(notMatches("void x() {}", declStmt())); } TEST(DeclarationStatement, MatchesVariableDeclarationStatements) { - EXPECT_TRUE(matches("void x() { int a; }", declarationStatement())); + EXPECT_TRUE(matches("void x() { int a; }", declStmt())); } TEST(InitListExpression, MatchesInitListExpression) { EXPECT_TRUE(matches("int a[] = { 1, 2 };", initListExpr(hasType(asString("int [2]"))))); EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };", - initListExpr(hasType(record(hasName("B")))))); + initListExpr(hasType(recordDecl(hasName("B")))))); } TEST(UsingDeclaration, MatchesUsingDeclarations) { @@ -2362,24 +2630,24 @@ TEST(UsingDeclaration, MatchesShadowUsingDelcarations) { TEST(UsingDeclaration, MatchesSpecificTarget) { EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;", usingDecl(hasAnyUsingShadowDecl( - hasTargetDecl(function()))))); + hasTargetDecl(functionDecl()))))); EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;", usingDecl(hasAnyUsingShadowDecl( - hasTargetDecl(function()))))); + hasTargetDecl(functionDecl()))))); } TEST(UsingDeclaration, ThroughUsingDeclaration) { EXPECT_TRUE(matches( "namespace a { void f(); } using a::f; void g() { f(); }", - declarationReference(throughUsingDecl(anything())))); + declRefExpr(throughUsingDecl(anything())))); EXPECT_TRUE(notMatches( "namespace a { void f(); } using a::f; void g() { a::f(); }", - declarationReference(throughUsingDecl(anything())))); + declRefExpr(throughUsingDecl(anything())))); } TEST(SingleDecl, IsSingleDecl) { StatementMatcher SingleDeclStmt = - declarationStatement(hasSingleDecl(variable(hasInitializer(anything())))); + declStmt(hasSingleDecl(varDecl(hasInitializer(anything())))); EXPECT_TRUE(matches("void f() {int a = 4;}", SingleDeclStmt)); EXPECT_TRUE(notMatches("void f() {int a;}", SingleDeclStmt)); EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}", @@ -2387,28 +2655,26 @@ TEST(SingleDecl, IsSingleDecl) { } TEST(DeclStmt, ContainsDeclaration) { - DeclarationMatcher MatchesInit = variable(hasInitializer(anything())); + DeclarationMatcher MatchesInit = varDecl(hasInitializer(anything())); EXPECT_TRUE(matches("void f() {int a = 4;}", - declarationStatement(containsDeclaration(0, - MatchesInit)))); + declStmt(containsDeclaration(0, MatchesInit)))); EXPECT_TRUE(matches("void f() {int a = 4, b = 3;}", - declarationStatement(containsDeclaration(0, MatchesInit), - containsDeclaration(1, - MatchesInit)))); + declStmt(containsDeclaration(0, MatchesInit), + containsDeclaration(1, MatchesInit)))); unsigned WrongIndex = 42; EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}", - declarationStatement(containsDeclaration(WrongIndex, + declStmt(containsDeclaration(WrongIndex, MatchesInit)))); } TEST(DeclCount, DeclCountIsCorrect) { EXPECT_TRUE(matches("void f() {int i,j;}", - declarationStatement(declCountIs(2)))); + declStmt(declCountIs(2)))); EXPECT_TRUE(notMatches("void f() {int i,j; int k;}", - declarationStatement(declCountIs(3)))); + declStmt(declCountIs(3)))); EXPECT_TRUE(notMatches("void f() {int i,j, k, l;}", - declarationStatement(declCountIs(3)))); + declStmt(declCountIs(3)))); } TEST(While, MatchesWhileLoops) { @@ -2433,61 +2699,91 @@ TEST(SwitchCase, MatchesCase) { EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase())); } +TEST(SwitchCase, MatchesSwitch) { + EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchStmt())); + EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchStmt())); + EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchStmt())); + EXPECT_TRUE(notMatches("void x() {}", switchStmt())); +} + +TEST(ExceptionHandling, SimpleCases) { + EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt())); + EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt())); + EXPECT_TRUE(notMatches("void foo() try { } catch(int X) { }", throwExpr())); + EXPECT_TRUE(matches("void foo() try { throw; } catch(int X) { }", + throwExpr())); + EXPECT_TRUE(matches("void foo() try { throw 5;} catch(int X) { }", + throwExpr())); +} + TEST(HasConditionVariableStatement, DoesNotMatchCondition) { EXPECT_TRUE(notMatches( "void x() { if(true) {} }", - ifStmt(hasConditionVariableStatement(declarationStatement())))); + ifStmt(hasConditionVariableStatement(declStmt())))); EXPECT_TRUE(notMatches( "void x() { int x; if((x = 42)) {} }", - ifStmt(hasConditionVariableStatement(declarationStatement())))); + ifStmt(hasConditionVariableStatement(declStmt())))); } TEST(HasConditionVariableStatement, MatchesConditionVariables) { EXPECT_TRUE(matches( "void x() { if(int* a = 0) {} }", - ifStmt(hasConditionVariableStatement(declarationStatement())))); + ifStmt(hasConditionVariableStatement(declStmt())))); } TEST(ForEach, BindsOneNode) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };", - record(hasName("C"), forEach(field(hasName("x")).bind("x"))), - new VerifyIdIsBoundToDecl<FieldDecl>("x", 1))); + recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))), + new VerifyIdIsBoundTo<FieldDecl>("x", 1))); } TEST(ForEach, BindsMultipleNodes) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };", - record(hasName("C"), forEach(field().bind("f"))), - new VerifyIdIsBoundToDecl<FieldDecl>("f", 3))); + recordDecl(hasName("C"), forEach(fieldDecl().bind("f"))), + new VerifyIdIsBoundTo<FieldDecl>("f", 3))); } TEST(ForEach, BindsRecursiveCombinations) { EXPECT_TRUE(matchAndVerifyResultTrue( "class C { class D { int x; int y; }; class E { int y; int z; }; };", - record(hasName("C"), forEach(record(forEach(field().bind("f"))))), - new VerifyIdIsBoundToDecl<FieldDecl>("f", 4))); + recordDecl(hasName("C"), + forEach(recordDecl(forEach(fieldDecl().bind("f"))))), + new VerifyIdIsBoundTo<FieldDecl>("f", 4))); } TEST(ForEachDescendant, BindsOneNode) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };", - record(hasName("C"), forEachDescendant(field(hasName("x")).bind("x"))), - new VerifyIdIsBoundToDecl<FieldDecl>("x", 1))); + recordDecl(hasName("C"), + forEachDescendant(fieldDecl(hasName("x")).bind("x"))), + new VerifyIdIsBoundTo<FieldDecl>("x", 1))); } TEST(ForEachDescendant, BindsMultipleNodes) { EXPECT_TRUE(matchAndVerifyResultTrue( "class C { class D { int x; int y; }; " " class E { class F { int y; int z; }; }; };", - record(hasName("C"), forEachDescendant(field().bind("f"))), - new VerifyIdIsBoundToDecl<FieldDecl>("f", 4))); + recordDecl(hasName("C"), forEachDescendant(fieldDecl().bind("f"))), + new VerifyIdIsBoundTo<FieldDecl>("f", 4))); } TEST(ForEachDescendant, BindsRecursiveCombinations) { EXPECT_TRUE(matchAndVerifyResultTrue( "class C { class D { " " class E { class F { class G { int y; int z; }; }; }; }; };", - record(hasName("C"), forEachDescendant(record( - forEachDescendant(field().bind("f"))))), - new VerifyIdIsBoundToDecl<FieldDecl>("f", 8))); + recordDecl(hasName("C"), forEachDescendant(recordDecl( + forEachDescendant(fieldDecl().bind("f"))))), + new VerifyIdIsBoundTo<FieldDecl>("f", 8))); +} + +TEST(ForEachDescendant, BindsCorrectNodes) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { void f(); int i; };", + recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))), + new VerifyIdIsBoundTo<FieldDecl>("decl", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { void f() {} int i; };", + recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))), + new VerifyIdIsBoundTo<FunctionDecl>("decl", 1))); } @@ -2497,18 +2793,18 @@ TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X {}; class A {}; X<A> x;", - record(hasName("::X"), isTemplateInstantiation()))); + recordDecl(hasName("::X"), isTemplateInstantiation()))); EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {}; X<A> x;", - record(isTemplateInstantiation(), hasDescendant( - field(hasType(record(hasName("A")))))))); + recordDecl(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()); }", - function(hasParameter(0, hasType(record(hasName("A")))), + functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))), isTemplateInstantiation()))); } @@ -2516,8 +2812,8 @@ TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {};" "template class X<A>;", - record(isTemplateInstantiation(), hasDescendant( - field(hasType(record(hasName("A")))))))); + recordDecl(isTemplateInstantiation(), hasDescendant( + fieldDecl(hasType(recordDecl(hasName("A")))))))); } TEST(IsTemplateInstantiation, @@ -2525,7 +2821,7 @@ TEST(IsTemplateInstantiation, EXPECT_TRUE(matches( "template <typename T> class X {};" "template <typename T> class X<T*> {}; class A {}; X<A*> x;", - record(hasName("::X"), isTemplateInstantiation()))); + recordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, @@ -2536,7 +2832,7 @@ TEST(IsTemplateInstantiation, " template <typename U> class Y { U u; };" " Y<A> y;" "};", - record(hasName("::X::Y"), isTemplateInstantiation()))); + recordDecl(hasName("::X::Y"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { @@ -2549,20 +2845,557 @@ TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { " template <typename U> class Y { U u; };" " Y<T> y;" "}; X<A> x;", - record(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); + recordDecl(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;", - record(hasName("::X"), isTemplateInstantiation()))); + recordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { EXPECT_TRUE(notMatches( "class A {}; class Y { A a; };", - record(isTemplateInstantiation()))); + recordDecl(isTemplateInstantiation()))); +} + +TEST(IsExplicitTemplateSpecialization, + DoesNotMatchPrimaryTemplate) { + EXPECT_TRUE(notMatches( + "template <typename T> class X {};", + recordDecl(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>;", + recordDecl(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;", + recordDecl(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> {};", + recordDecl(isExplicitTemplateSpecialization()))); + EXPECT_TRUE(matches( + "template <typename T> void f(T t) {}" + "template<> void f(int t) {}", + functionDecl(isExplicitTemplateSpecialization()))); +} + +TEST(HasAncenstor, MatchesDeclarationAncestors) { + EXPECT_TRUE(matches( + "class A { class B { class C {}; }; };", + recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("A")))))); +} + +TEST(HasAncenstor, FailsIfNoAncestorMatches) { + EXPECT_TRUE(notMatches( + "class A { class B { class C {}; }; };", + recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("X")))))); +} + +TEST(HasAncestor, MatchesDeclarationsThatGetVisitedLater) { + EXPECT_TRUE(matches( + "class A { class B { void f() { C c; } class C {}; }; };", + varDecl(hasName("c"), hasType(recordDecl(hasName("C"), + hasAncestor(recordDecl(hasName("A")))))))); +} + +TEST(HasAncenstor, MatchesStatementAncestors) { + EXPECT_TRUE(matches( + "void f() { if (true) { while (false) { 42; } } }", + integerLiteral(equals(42), hasAncestor(ifStmt())))); +} + +TEST(HasAncestor, DrillsThroughDifferentHierarchies) { + EXPECT_TRUE(matches( + "void f() { if (true) { int x = 42; } }", + integerLiteral(equals(42), hasAncestor(functionDecl(hasName("f")))))); +} + +TEST(HasAncestor, BindsRecursiveCombinations) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { class D { class E { class F { int y; }; }; }; };", + fieldDecl(hasAncestor(recordDecl(hasAncestor(recordDecl().bind("r"))))), + new VerifyIdIsBoundTo<CXXRecordDecl>("r", 1))); +} + +TEST(HasAncestor, BindsCombinationsWithHasDescendant) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { class D { class E { class F { int y; }; }; }; };", + fieldDecl(hasAncestor( + decl( + hasDescendant(recordDecl(isDefinition(), + hasAncestor(recordDecl()))) + ).bind("d") + )), + new VerifyIdIsBoundTo<CXXRecordDecl>("d", "E"))); +} + +TEST(HasAncestor, MatchesInTemplateInstantiations) { + EXPECT_TRUE(matches( + "template <typename T> struct A { struct B { struct C { T t; }; }; }; " + "A<int>::B::C a;", + fieldDecl(hasType(asString("int")), + hasAncestor(recordDecl(hasName("A")))))); +} + +TEST(HasAncestor, MatchesInImplicitCode) { + EXPECT_TRUE(matches( + "struct X {}; struct A { A() {} X x; };", + constructorDecl( + hasAnyConstructorInitializer(withInitializer(expr( + hasAncestor(recordDecl(hasName("A"))))))))); +} + +TEST(HasParent, MatchesOnlyParent) { + EXPECT_TRUE(matches( + "void f() { if (true) { int x = 42; } }", + compoundStmt(hasParent(ifStmt())))); + EXPECT_TRUE(notMatches( + "void f() { for (;;) { int x = 42; } }", + compoundStmt(hasParent(ifStmt())))); + EXPECT_TRUE(notMatches( + "void f() { if (true) for (;;) { int x = 42; } }", + compoundStmt(hasParent(ifStmt())))); +} + +TEST(TypeMatching, MatchesTypes) { + EXPECT_TRUE(matches("struct S {};", qualType().bind("loc"))); +} + +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, 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(TypeMatching, MatchesConstantArrayTypes) { + EXPECT_TRUE(matches("int a[2];", constantArrayType())); + EXPECT_TRUE(notMatches( + "void f() { int a[] = { 2, 3 }; int b[a[0]]; }", + constantArrayType(hasElementType(builtinType())))); + + EXPECT_TRUE(matches("int a[42];", constantArrayType(hasSize(42)))); + EXPECT_TRUE(matches("int b[2*21];", constantArrayType(hasSize(42)))); + EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42)))); +} + +TEST(TypeMatching, MatchesDependentSizedArrayTypes) { + EXPECT_TRUE(matches( + "template <typename T, int Size> class array { T data[Size]; };", + dependentSizedArrayType())); + EXPECT_TRUE(notMatches( + "int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }", + dependentSizedArrayType())); +} + +TEST(TypeMatching, MatchesIncompleteArrayType) { + EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType())); + EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType())); + + EXPECT_TRUE(notMatches("int a[42]; void f() { int b[a[0]]; }", + incompleteArrayType())); +} + +TEST(TypeMatching, MatchesVariableArrayType) { + EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType())); + EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType())); + + EXPECT_TRUE(matches( + "void f(int b) { int a[b]; }", + variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to( + varDecl(hasName("b"))))))))); +} + +TEST(TypeMatching, MatchesAtomicTypes) { + EXPECT_TRUE(matches("_Atomic(int) i;", atomicType())); + + EXPECT_TRUE(matches("_Atomic(int) i;", + atomicType(hasValueType(isInteger())))); + EXPECT_TRUE(notMatches("_Atomic(float) f;", + atomicType(hasValueType(isInteger())))); +} + +TEST(TypeMatching, MatchesAutoTypes) { + EXPECT_TRUE(matches("auto i = 2;", autoType())); + EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }", + autoType())); + + EXPECT_TRUE(matches("auto a = 1;", + autoType(hasDeducedType(isInteger())))); + EXPECT_TRUE(notMatches("auto b = 2.0;", + autoType(hasDeducedType(isInteger())))); +} + +TEST(TypeMatching, MatchesFunctionTypes) { + EXPECT_TRUE(matches("int (*f)(int);", functionType())); + EXPECT_TRUE(matches("void f(int i) {}", functionType())); +} + +TEST(TypeMatching, PointerTypes) { + // FIXME: Reactive when these tests can be more specific (not matching + // implicit code on certain platforms), likely when we have hasDescendant for + // Types/TypeLocs. + //EXPECT_TRUE(matchAndVerifyResultTrue( + // "int* a;", + // pointerTypeLoc(pointeeLoc(typeLoc().bind("loc"))), + // new VerifyIdIsBoundTo<TypeLoc>("loc", 1))); + //EXPECT_TRUE(matchAndVerifyResultTrue( + // "int* a;", + // pointerTypeLoc().bind("loc"), + // new VerifyIdIsBoundTo<TypeLoc>("loc", 1))); + EXPECT_TRUE(matches( + "int** a;", + pointerTypeLoc(pointeeLoc(loc(qualType()))))); + EXPECT_TRUE(matches( + "int** a;", + loc(pointerType(pointee(pointerType()))))); + EXPECT_TRUE(matches( + "int* b; int* * const a = &b;", + loc(qualType(isConstQualified(), pointerType())))); + + std::string Fragment = "struct A { int i; }; int A::* ptr = &A::i;"; + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(blockPointerType())))); + EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"), + hasType(memberPointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(pointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(referenceType())))); + + Fragment = "int *ptr;"; + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(blockPointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(memberPointerType())))); + EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"), + hasType(pointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"), + hasType(referenceType())))); + + Fragment = "int a; int &ref = a;"; + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"), + hasType(blockPointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"), + hasType(memberPointerType())))); + EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"), + hasType(pointerType())))); + EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"), + hasType(referenceType())))); +} + +TEST(TypeMatching, PointeeTypes) { + EXPECT_TRUE(matches("int b; int &a = b;", + referenceType(pointee(builtinType())))); + EXPECT_TRUE(matches("int *a;", pointerType(pointee(builtinType())))); + + EXPECT_TRUE(matches("int *a;", + pointerTypeLoc(pointeeLoc(loc(builtinType()))))); + + EXPECT_TRUE(matches( + "int const *A;", + pointerType(pointee(isConstQualified(), builtinType())))); + EXPECT_TRUE(notMatches( + "int *A;", + pointerType(pointee(isConstQualified(), builtinType())))); +} + +TEST(TypeMatching, MatchesPointersToConstTypes) { + EXPECT_TRUE(matches("int b; int * const a = &b;", + loc(pointerType()))); + EXPECT_TRUE(matches("int b; int * const a = &b;", + pointerTypeLoc())); + EXPECT_TRUE(matches( + "int b; const int * a = &b;", + pointerTypeLoc(pointeeLoc(builtinTypeLoc())))); + EXPECT_TRUE(matches( + "int b; const int * a = &b;", + pointerType(pointee(builtinType())))); +} + +TEST(TypeMatching, MatchesTypedefTypes) { + EXPECT_TRUE(matches("typedef int X; X a;", varDecl(hasName("a"), + hasType(typedefType())))); + + EXPECT_TRUE(matches("typedef int X; X a;", + varDecl(hasName("a"), + hasType(typedefType(hasDecl(decl())))))); +} + +TEST(NNS, MatchesNestedNameSpecifiers) { + EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", + nestedNameSpecifier())); + EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };", + nestedNameSpecifier())); + EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}", + nestedNameSpecifier())); + + EXPECT_TRUE(matches( + "struct A { static void f() {} }; void g() { A::f(); }", + nestedNameSpecifier())); + EXPECT_TRUE(notMatches( + "struct A { static void f() {} }; void g(A* a) { a->f(); }", + nestedNameSpecifier())); +} + +TEST(NullStatement, SimpleCases) { + EXPECT_TRUE(matches("void f() {int i;;}", nullStmt())); + EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt())); +} + +TEST(NNS, MatchesTypes) { + NestedNameSpecifierMatcher Matcher = nestedNameSpecifier( + specifiesType(hasDeclaration(recordDecl(hasName("A"))))); + EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher)); + EXPECT_TRUE(matches("struct A { struct B { struct C {}; }; }; A::B::C c;", + Matcher)); + EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher)); +} + +TEST(NNS, MatchesNamespaceDecls) { + NestedNameSpecifierMatcher Matcher = nestedNameSpecifier( + specifiesNamespace(hasName("ns"))); + EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher)); + EXPECT_TRUE(notMatches("namespace xx { struct A {}; } xx::A a;", Matcher)); + EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher)); +} + +TEST(NNS, BindsNestedNameSpecifiers) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "namespace ns { struct E { struct B {}; }; } ns::E::B b;", + nestedNameSpecifier(specifiesType(asString("struct ns::E"))).bind("nns"), + new VerifyIdIsBoundTo<NestedNameSpecifier>("nns", "ns::struct E::"))); +} + +TEST(NNS, BindsNestedNameSpecifierLocs) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "namespace ns { struct B {}; } ns::B b;", + loc(nestedNameSpecifier()).bind("loc"), + new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("loc", 1))); +} + +TEST(NNS, MatchesNestedNameSpecifierPrefixes) { + EXPECT_TRUE(matches( + "struct A { struct B { struct C {}; }; }; A::B::C c;", + nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))))); + EXPECT_TRUE(matches( + "struct A { struct B { struct C {}; }; }; A::B::C c;", + nestedNameSpecifierLoc(hasPrefix( + specifiesTypeLoc(loc(qualType(asString("struct A")))))))); +} + +TEST(NNS, DescendantsOfNestedNameSpecifiers) { + std::string Fragment = + "namespace a { struct A { struct B { struct C {}; }; }; };" + "void f() { a::A::B::C c; }"; + EXPECT_TRUE(matches( + Fragment, + nestedNameSpecifier(specifiesType(asString("struct a::A::B")), + hasDescendant(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); + EXPECT_TRUE(notMatches( + Fragment, + nestedNameSpecifier(specifiesType(asString("struct a::A::B")), + has(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); + EXPECT_TRUE(matches( + Fragment, + nestedNameSpecifier(specifiesType(asString("struct a::A")), + has(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); + + // Not really useful because a NestedNameSpecifier can af at most one child, + // but to complete the interface. + EXPECT_TRUE(matchAndVerifyResultTrue( + Fragment, + nestedNameSpecifier(specifiesType(asString("struct a::A::B")), + forEach(nestedNameSpecifier().bind("x"))), + new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 1))); +} + +TEST(NNS, NestedNameSpecifiersAsDescendants) { + std::string Fragment = + "namespace a { struct A { struct B { struct C {}; }; }; };" + "void f() { a::A::B::C c; }"; + EXPECT_TRUE(matches( + Fragment, + decl(hasDescendant(nestedNameSpecifier(specifiesType( + asString("struct a::A"))))))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Fragment, + functionDecl(hasName("f"), + forEachDescendant(nestedNameSpecifier().bind("x"))), + // Nested names: a, a::A and a::A::B. + new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 3))); +} + +TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) { + std::string Fragment = + "namespace a { struct A { struct B { struct C {}; }; }; };" + "void f() { a::A::B::C c; }"; + EXPECT_TRUE(matches( + Fragment, + nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), + hasDescendant(loc(nestedNameSpecifier( + specifiesNamespace(hasName("a")))))))); + EXPECT_TRUE(notMatches( + Fragment, + nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), + has(loc(nestedNameSpecifier( + specifiesNamespace(hasName("a")))))))); + EXPECT_TRUE(matches( + Fragment, + nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))), + has(loc(nestedNameSpecifier( + specifiesNamespace(hasName("a")))))))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + Fragment, + nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), + forEach(nestedNameSpecifierLoc().bind("x"))), + new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 1))); +} + +TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) { + std::string Fragment = + "namespace a { struct A { struct B { struct C {}; }; }; };" + "void f() { a::A::B::C c; }"; + EXPECT_TRUE(matches( + Fragment, + decl(hasDescendant(loc(nestedNameSpecifier(specifiesType( + asString("struct a::A")))))))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Fragment, + functionDecl(hasName("f"), + forEachDescendant(nestedNameSpecifierLoc().bind("x"))), + // Nested names: a, a::A and a::A::B. + new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3))); +} + +template <typename T> +class VerifyRecursiveMatch : public BoundNodesCallback { +public: + explicit VerifyRecursiveMatch(StringRef Id, + const internal::Matcher<T> &InnerMatcher) + : Id(Id), InnerMatcher(InnerMatcher) {} + + virtual bool run(const BoundNodes *Nodes) { + return false; + } + + virtual bool run(const BoundNodes *Nodes, ASTContext *Context) { + const T *Node = Nodes->getNodeAs<T>(Id); + bool Found = false; + MatchFinder Finder; + Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found)); + Finder.findAll(*Node, *Context); + return Found; + } +private: + std::string Id; + internal::Matcher<T> InnerMatcher; +}; + +TEST(MatchFinder, CanMatchDeclarationsRecursively) { + EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };", + recordDecl(hasName("::X")).bind("X"), + new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y"))))); + EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };", + recordDecl(hasName("::X")).bind("X"), + new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z"))))); +} + +TEST(MatchFinder, CanMatchStatementsRecursively) { + EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }", + ifStmt().bind("if"), + new VerifyRecursiveMatch<clang::Stmt>("if", forStmt()))); + EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }", + ifStmt().bind("if"), + new VerifyRecursiveMatch<clang::Stmt>("if", declStmt()))); +} + +class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback { +public: + VerifyStartOfTranslationUnit() : Called(false) {} + virtual void run(const MatchFinder::MatchResult &Result) { + EXPECT_TRUE(Called); + } + virtual void onStartOfTranslationUnit() { + Called = true; + } + bool Called; +}; + +TEST(MatchFinder, InterceptsStartOfTranslationUnit) { + MatchFinder Finder; + VerifyStartOfTranslationUnit VerifyCallback; + Finder.addMatcher(decl(), &VerifyCallback); + OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); + ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;")); + EXPECT_TRUE(VerifyCallback.Called); } } // end namespace ast_matchers |