diff options
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersTest.cpp')
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 765 |
1 files changed, 529 insertions, 236 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 8ef3f15..cd18df8 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -36,7 +36,7 @@ TEST(HasNameDeathTest, DiesOnEmptyPattern) { TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { ASSERT_DEBUG_DEATH({ - DeclarationMatcher IsDerivedFromEmpty = recordDecl(isDerivedFrom("")); + DeclarationMatcher IsDerivedFromEmpty = cxxRecordDecl(isDerivedFrom("")); EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty)); }, ""); } @@ -122,7 +122,7 @@ TEST(DeclarationMatcher, MatchClass) { } TEST(DeclarationMatcher, ClassIsDerived) { - DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X")); + DeclarationMatcher IsDerivedFromX = cxxRecordDecl(isDerivedFrom("X")); EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX)); EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX)); @@ -130,7 +130,7 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX)); EXPECT_TRUE(notMatches("", IsDerivedFromX)); - DeclarationMatcher IsAX = recordDecl(isSameOrDerivedFrom("X")); + DeclarationMatcher IsAX = cxxRecordDecl(isSameOrDerivedFrom("X")); EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX)); EXPECT_TRUE(matches("class X {};", IsAX)); @@ -139,7 +139,7 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(notMatches("", IsAX)); DeclarationMatcher ZIsDerivedFromX = - recordDecl(hasName("Z"), isDerivedFrom("X")); + cxxRecordDecl(hasName("Z"), isDerivedFrom("X")); EXPECT_TRUE( matches("class X {}; class Y : public X {}; class Z : public Y {};", ZIsDerivedFromX)); @@ -258,14 +258,14 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE( notMatches("template<int> struct X;" "template<int i> struct X : public X<i-1> {};", - recordDecl(isDerivedFrom(recordDecl(hasName("Some")))))); + cxxRecordDecl(isDerivedFrom(recordDecl(hasName("Some")))))); EXPECT_TRUE(matches( "struct A {};" "template<int> struct X;" "template<int i> struct X : public X<i-1> {};" "template<> struct X<0> : public A {};" "struct B : public X<42> {};", - recordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A")))))); + cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A")))))); // FIXME: Once we have better matchers for template type matching, // get rid of the Variable(...) matching and match the right template @@ -282,15 +282,15 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(matches( RecursiveTemplateOneParameter, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateOneParameter, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateOneParameter, varDecl(hasName("z_char"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), isDerivedFrom("Base2"))))))); const char *RecursiveTemplateTwoParameters = @@ -307,39 +307,39 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateTwoParameters, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, varDecl(hasName("z_char"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( "namespace ns { class X {}; class Y : public X {}; }", - recordDecl(isDerivedFrom("::ns::X")))); + cxxRecordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(notMatches( "class X {}; class Y : public X {};", - recordDecl(isDerivedFrom("::ns::X")))); + cxxRecordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(matches( "class X {}; class Y : public X {};", - recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); + cxxRecordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); EXPECT_TRUE(matches( "template<typename T> class X {};" "template<typename T> using Z = X<T>;" "template <typename T> class Y : Z<T> {};", - recordDecl(isDerivedFrom(namedDecl(hasName("X")))))); + cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X")))))); } TEST(DeclarationMatcher, hasMethod) { EXPECT_TRUE(matches("class A { void func(); };", - recordDecl(hasMethod(hasName("func"))))); + cxxRecordDecl(hasMethod(hasName("func"))))); EXPECT_TRUE(notMatches("class A { void func(); };", - recordDecl(hasMethod(isPublic())))); + cxxRecordDecl(hasMethod(isPublic())))); } TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { @@ -349,7 +349,7 @@ TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { "};" "template <typename T> struct B : A<T>::template F<T> {};" "B<int> b;", - recordDecl(hasName("B"), isDerivedFrom(recordDecl())))); + cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl())))); } TEST(DeclarationMatcher, hasDeclContext) { @@ -453,11 +453,20 @@ TEST(AllOf, AllOverloadsWork) { hasArgument(3, integerLiteral(equals(4))))))); } -TEST(DeclarationMatcher, MatchAnyOf) { - DeclarationMatcher YOrZDerivedFromX = - recordDecl(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); +TEST(ConstructVariadic, MismatchedTypes_Regression) { EXPECT_TRUE( - matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); + matches("const int a = 0;", + internal::DynTypedMatcher::constructVariadic( + internal::DynTypedMatcher::VO_AnyOf, + ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(), + {isConstQualified(), arrayType()}) + .convertTo<QualType>())); +} + +TEST(DeclarationMatcher, MatchAnyOf) { + DeclarationMatcher YOrZDerivedFromX = cxxRecordDecl( + anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); + EXPECT_TRUE(matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX)); EXPECT_TRUE( notMatches("class X {}; class W : public X {};", YOrZDerivedFromX)); @@ -485,7 +494,7 @@ TEST(DeclarationMatcher, MatchAnyOf) { EXPECT_TRUE( matches("void f() try { } catch (int) { } catch (...) { }", - catchStmt(anyOf(hasDescendant(varDecl()), isCatchAll())))); + cxxCatchStmt(anyOf(hasDescendant(varDecl()), isCatchAll())))); } TEST(DeclarationMatcher, MatchHas) { @@ -592,7 +601,7 @@ TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { TEST(DeclarationMatcher, MatchNot) { DeclarationMatcher NotClassX = - recordDecl( + cxxRecordDecl( isDerivedFrom("Y"), unless(hasName("X"))); EXPECT_TRUE(notMatches("", NotClassX)); @@ -709,11 +718,11 @@ TEST(DeclarationMatcher, HasAttr) { TEST(DeclarationMatcher, MatchCudaDecl) { EXPECT_TRUE(matchesWithCuda("__global__ void f() { }" "void g() { f<<<1, 2>>>(); }", - CUDAKernelCallExpr())); + cudaKernelCallExpr())); EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}", hasAttr(clang::attr::CUDADevice))); EXPECT_TRUE(notMatchesWithCuda("void f() {}", - CUDAKernelCallExpr())); + cudaKernelCallExpr())); EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}", hasAttr(clang::attr::CUDAGlobal))); } @@ -898,7 +907,8 @@ TEST(TypeMatcher, MatchesClassType) { EXPECT_TRUE(matches("class A { public: A *a; };", TypeA)); EXPECT_TRUE(notMatches("class A {};", TypeA)); - TypeMatcher TypeDerivedFromA = hasDeclaration(recordDecl(isDerivedFrom("A"))); + TypeMatcher TypeDerivedFromA = + hasDeclaration(cxxRecordDecl(isDerivedFrom("A"))); EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };", TypeDerivedFromA)); @@ -909,6 +919,57 @@ TEST(TypeMatcher, MatchesClassType) { EXPECT_TRUE( matches("class A { public: A *a; class B {}; };", TypeAHasClassB)); + + EXPECT_TRUE(matchesC("struct S {}; void f(void) { struct S s; }", + varDecl(hasType(namedDecl(hasName("S")))))); +} + +TEST(TypeMatcher, MatchesDeclTypes) { + // TypedefType -> TypedefNameDecl + EXPECT_TRUE(matches("typedef int I; void f(I i);", + parmVarDecl(hasType(namedDecl(hasName("I")))))); + // ObjCObjectPointerType + EXPECT_TRUE(matchesObjC("@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(objcObjectPointerType())))); + // ObjCObjectPointerType -> ObjCInterfaceType -> ObjCInterfaceDecl + EXPECT_TRUE(matchesObjC( + "@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(pointsTo(objcInterfaceDecl(hasName("Foo"))))))); + // TemplateTypeParmType + EXPECT_TRUE(matches("template <typename T> void f(T t);", + parmVarDecl(hasType(templateTypeParmType())))); + // TemplateTypeParmType -> TemplateTypeParmDecl + EXPECT_TRUE(matches("template <typename T> void f(T t);", + parmVarDecl(hasType(namedDecl(hasName("T")))))); + // InjectedClassNameType + EXPECT_TRUE(matches("template <typename T> struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + EXPECT_TRUE(notMatches("template <typename T> struct S {" + " void g(S<T> s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + // InjectedClassNameType -> CXXRecordDecl + EXPECT_TRUE(matches("template <typename T> struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(namedDecl(hasName("S")))))); + + static const char Using[] = "template <typename T>" + "struct Base {" + " typedef T Foo;" + "};" + "" + "template <typename T>" + "struct S : private Base<T> {" + " using typename Base<T>::Foo;" + " void f(Foo);" + "};"; + // UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, unresolvedUsingTypenameDecl(hasName("Foo")))); + // UnresolvedUsingTypenameType -> UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, parmVarDecl(hasType(namedDecl(hasName("Foo")))))); } TEST(Matcher, BindMatchedNodes) { @@ -928,7 +989,7 @@ TEST(Matcher, BindMatchedNodes) { new VerifyIdIsBoundTo<Decl>("b"))); StatementMatcher MethodX = - callExpr(callee(methodDecl(hasName("x")))).bind("x"); + callExpr(callee(cxxMethodDecl(hasName("x")))).bind("x"); EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };", MethodX, @@ -1042,13 +1103,14 @@ TEST(HasTypeLoc, MatchesDeclaratorDecls) { TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take // Matcher<Decl>, too? - StatementMatcher MethodX = callExpr(hasDeclaration(methodDecl(hasName("x")))); + StatementMatcher MethodX = + callExpr(hasDeclaration(cxxMethodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX)); StatementMatcher MethodOnY = - memberCallExpr(on(hasType(recordDecl(hasName("Y"))))); + cxxMemberCallExpr(on(hasType(recordDecl(hasName("Y"))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -1067,7 +1129,7 @@ TEST(Matcher, Call) { MethodOnY)); StatementMatcher MethodOnYPointer = - memberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))); + cxxMemberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", @@ -1094,9 +1156,9 @@ TEST(Matcher, Lambda) { TEST(Matcher, ForRange) { EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };" "void f() { for (auto &a : as); }", - forRangeStmt())); + cxxForRangeStmt())); EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }", - forRangeStmt())); + cxxForRangeStmt())); } TEST(Matcher, SubstNonTypeTemplateParm) { @@ -1110,6 +1172,20 @@ TEST(Matcher, SubstNonTypeTemplateParm) { substNonTypeTemplateParmExpr())); } +TEST(Matcher, NonTypeTemplateParmDecl) { + EXPECT_TRUE(matches("template <int N> void f();", + nonTypeTemplateParmDecl(hasName("N")))); + EXPECT_TRUE( + notMatches("template <typename T> void f();", nonTypeTemplateParmDecl())); +} + +TEST(Matcher, templateTypeParmDecl) { + EXPECT_TRUE(matches("template <typename T> void f();", + templateTypeParmDecl(hasName("T")))); + EXPECT_TRUE( + notMatches("template <int N> void f();", templateTypeParmDecl())); +} + TEST(Matcher, UserDefinedLiteral) { EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {" " return i + 1;" @@ -1130,9 +1206,10 @@ TEST(Matcher, FlowControl) { TEST(HasType, MatchesAsString) { EXPECT_TRUE( matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }", - memberCallExpr(on(hasType(asString("class Y *")))))); - EXPECT_TRUE(matches("class X { void x(int x) {} };", - methodDecl(hasParameter(0, hasType(asString("int")))))); + cxxMemberCallExpr(on(hasType(asString("class Y *")))))); + EXPECT_TRUE( + matches("class X { void x(int x) {} };", + cxxMethodDecl(hasParameter(0, hasType(asString("int")))))); EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };", fieldDecl(hasType(asString("ns::A"))))); EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };", @@ -1140,7 +1217,7 @@ TEST(HasType, MatchesAsString) { } TEST(Matcher, OverloadedOperatorCall) { - StatementMatcher OpCall = operatorCallExpr(); + StatementMatcher OpCall = cxxOperatorCallExpr(); // Unary operator EXPECT_TRUE(matches("class Y { }; " "bool operator!(Y x) { return false; }; " @@ -1167,22 +1244,22 @@ TEST(Matcher, OverloadedOperatorCall) { TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { StatementMatcher OpCallAndAnd = - operatorCallExpr(hasOverloadedOperatorName("&&")); + cxxOperatorCallExpr(hasOverloadedOperatorName("&&")); EXPECT_TRUE(matches("class Y { }; " "bool operator&&(Y x, Y y) { return true; }; " "Y a; Y b; bool c = a && b;", OpCallAndAnd)); StatementMatcher OpCallLessLess = - operatorCallExpr(hasOverloadedOperatorName("<<")); + cxxOperatorCallExpr(hasOverloadedOperatorName("<<")); EXPECT_TRUE(notMatches("class Y { }; " "bool operator&&(Y x, Y y) { return true; }; " "Y a; Y b; bool c = a && b;", OpCallLessLess)); StatementMatcher OpStarCall = - operatorCallExpr(hasOverloadedOperatorName("*")); + cxxOperatorCallExpr(hasOverloadedOperatorName("*")); EXPECT_TRUE(matches("class Y; int operator*(Y &); void f(Y &y) { *y; }", OpStarCall)); DeclarationMatcher ClassWithOpStar = - recordDecl(hasMethod(hasOverloadedOperatorName("*"))); + cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))); EXPECT_TRUE(matches("class Y { int operator*(); };", ClassWithOpStar)); EXPECT_TRUE(notMatches("class Y { void myOperator(); };", @@ -1194,26 +1271,25 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { TEST(Matcher, NestedOverloadedOperatorCalls) { EXPECT_TRUE(matchAndVerifyResultTrue( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"), - new VerifyIdIsBoundTo<CXXOperatorCallExpr>("x", 2))); - EXPECT_TRUE(matches( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasParent(operatorCallExpr())))); - EXPECT_TRUE(matches( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasDescendant(operatorCallExpr())))); + "class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"), + new VerifyIdIsBoundTo<CXXOperatorCallExpr>("x", 2))); + EXPECT_TRUE(matches("class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasParent(cxxOperatorCallExpr())))); + EXPECT_TRUE( + matches("class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasDescendant(cxxOperatorCallExpr())))); } TEST(Matcher, ThisPointerType) { StatementMatcher MethodOnY = - memberCallExpr(thisPointerType(recordDecl(hasName("Y")))); + cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -1245,7 +1321,7 @@ TEST(Matcher, VariableUsage) { StatementMatcher Reference = declRefExpr(to( varDecl(hasInitializer( - memberCallExpr(thisPointerType(recordDecl(hasName("Y")))))))); + cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))))))); EXPECT_TRUE(matches( "class Y {" @@ -1279,6 +1355,29 @@ TEST(Matcher, VarDecl_Storage) { EXPECT_TRUE(matches("void f() { static int X; }", M)); } +TEST(Matcher, VarDecl_StorageDuration) { + std::string T = + "void f() { int x; static int y; } int a;"; + + EXPECT_TRUE(matches(T, varDecl(hasName("x"), hasAutomaticStorageDuration()))); + EXPECT_TRUE( + notMatches(T, varDecl(hasName("y"), hasAutomaticStorageDuration()))); + EXPECT_TRUE( + notMatches(T, varDecl(hasName("a"), hasAutomaticStorageDuration()))); + + EXPECT_TRUE(matches(T, varDecl(hasName("y"), hasStaticStorageDuration()))); + EXPECT_TRUE(matches(T, varDecl(hasName("a"), hasStaticStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasStaticStorageDuration()))); + + // FIXME: It is really hard to test with thread_local itself because not all + // targets support TLS, which causes this to be an error depending on what + // platform the test is being run on. We do not have access to the TargetInfo + // object to be able to test whether the platform supports TLS or not. + EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasThreadStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("y"), hasThreadStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("a"), hasThreadStorageDuration()))); +} + TEST(Matcher, FindsVarDeclInFunctionParameter) { EXPECT_TRUE(matches( "void f(int i) {}", @@ -1287,7 +1386,7 @@ TEST(Matcher, FindsVarDeclInFunctionParameter) { TEST(Matcher, CalledVariable) { StatementMatcher CallOnVariableY = - memberCallExpr(on(declRefExpr(to(varDecl(hasName("y")))))); + cxxMemberCallExpr(on(declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(matches( "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY)); @@ -1370,6 +1469,14 @@ TEST(IsInteger, ReportsNoFalsePositives) { to(varDecl(hasType(isInteger())))))))); } +TEST(IsAnyCharacter, MatchesCharacters) { + EXPECT_TRUE(matches("char i = 0;", varDecl(hasType(isAnyCharacter())))); +} + +TEST(IsAnyCharacter, ReportsNoFalsePositives) { + EXPECT_TRUE(notMatches("int i;", varDecl(hasType(isAnyCharacter())))); +} + TEST(IsArrow, MatchesMemberVariablesViaArrow) { EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };", memberExpr(isArrow()))); @@ -1398,18 +1505,25 @@ TEST(IsArrow, MatchesMemberCallsViaArrow) { } TEST(Callee, MatchesDeclarations) { - StatementMatcher CallMethodX = callExpr(callee(methodDecl(hasName("x")))); + StatementMatcher CallMethodX = callExpr(callee(cxxMethodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX)); - CallMethodX = callExpr(callee(conversionDecl())); + CallMethodX = callExpr(callee(cxxConversionDecl())); EXPECT_TRUE( matches("struct Y { operator int() const; }; int i = Y();", CallMethodX)); EXPECT_TRUE(notMatches("struct Y { operator int() const; }; Y y = Y();", CallMethodX)); } +TEST(ConversionDeclaration, IsExplicit) { + EXPECT_TRUE(matches("struct S { explicit operator int(); };", + cxxConversionDecl(isExplicit()))); + EXPECT_TRUE(notMatches("struct S { operator int(); };", + cxxConversionDecl(isExplicit()))); +} + TEST(Callee, MatchesMemberExpressions) { EXPECT_TRUE(matches("class Y { void x() { this->x(); } };", callExpr(callee(memberExpr())))); @@ -1442,6 +1556,13 @@ TEST(Function, MatchesFunctionDeclarations) { notMatches("void f(int);" "template <typename T> struct S { void g(T t) { f(t); } };", CallFunctionF)); + + EXPECT_TRUE(matches("void f(...);", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("void f(int);", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("template <typename... Ts> void f(Ts...);", + functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatchesC("void f();", functionDecl(isVariadic()))); } TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) { @@ -1545,34 +1666,38 @@ TEST(QualType, hasLocalQualifiers) { TEST(HasParameter, CallsInnerMatcher) { EXPECT_TRUE(matches("class X { void x(int) {} };", - methodDecl(hasParameter(0, varDecl())))); + cxxMethodDecl(hasParameter(0, varDecl())))); EXPECT_TRUE(notMatches("class X { void x(int) {} };", - methodDecl(hasParameter(0, hasName("x"))))); + cxxMethodDecl(hasParameter(0, hasName("x"))))); } TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) { EXPECT_TRUE(notMatches("class X { void x(int) {} };", - methodDecl(hasParameter(42, varDecl())))); + cxxMethodDecl(hasParameter(42, varDecl())))); } TEST(HasType, MatchesParameterVariableTypesStrictly) { - EXPECT_TRUE(matches("class X { void x(X x) {} };", - methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); - EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };", - methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class X { void x(X x) {} };", + cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(notMatches( + "class X { void x(const X &x) {} };", + cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(matches("class X { void x(const X *x) {} };", - methodDecl(hasParameter(0, - hasType(pointsTo(recordDecl(hasName("X")))))))); + cxxMethodDecl(hasParameter( + 0, hasType(pointsTo(recordDecl(hasName("X")))))))); EXPECT_TRUE(matches("class X { void x(const X &x) {} };", - methodDecl(hasParameter(0, - hasType(references(recordDecl(hasName("X")))))))); + cxxMethodDecl(hasParameter( + 0, hasType(references(recordDecl(hasName("X")))))))); } TEST(HasAnyParameter, MatchesIndependentlyOfPosition) { - EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); - EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class Y {}; class X { void x(X x, Y y) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class Y {}; class X { void x(Y y, X x) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(Returns, MatchesReturnTypes) { @@ -1599,6 +1724,15 @@ TEST(IsDeleted, MatchesDeletedFunctionDeclarations) { functionDecl(hasName("Func"), isDeleted()))); } +TEST(IsNoThrow, MatchesNoThrowFunctionDeclarations) { + EXPECT_TRUE(notMatches("void f();", functionDecl(isNoThrow()))); + EXPECT_TRUE(notMatches("void f() throw(int);", functionDecl(isNoThrow()))); + EXPECT_TRUE( + notMatches("void f() noexcept(false);", functionDecl(isNoThrow()))); + EXPECT_TRUE(matches("void f() throw();", functionDecl(isNoThrow()))); + EXPECT_TRUE(matches("void f() noexcept;", functionDecl(isNoThrow()))); +} + TEST(isConstexpr, MatchesConstexprDeclarations) { EXPECT_TRUE(matches("constexpr int foo = 42;", varDecl(hasName("foo"), isConstexpr()))); @@ -1607,21 +1741,22 @@ TEST(isConstexpr, MatchesConstexprDeclarations) { } TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { - EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(notMatches( + "class Y {}; class X { void x(int) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(HasAnyParameter, DoesNotMatchThisPointer) { EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };", - methodDecl(hasAnyParameter(hasType(pointsTo( - recordDecl(hasName("X")))))))); + cxxMethodDecl(hasAnyParameter( + hasType(pointsTo(recordDecl(hasName("X")))))))); } TEST(HasName, MatchesParameterVariableDeclarations) { EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };", - methodDecl(hasAnyParameter(hasName("x"))))); + cxxMethodDecl(hasAnyParameter(hasName("x"))))); EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - methodDecl(hasAnyParameter(hasName("x"))))); + cxxMethodDecl(hasAnyParameter(hasName("x"))))); } TEST(Matcher, MatchesClassTemplateSpecialization) { @@ -1774,46 +1909,68 @@ TEST(Matcher, MatchesAccessSpecDecls) { EXPECT_TRUE(notMatches("class C { int i; };", accessSpecDecl())); } +TEST(Matcher, MatchesFinal) { + EXPECT_TRUE(matches("class X final {};", cxxRecordDecl(isFinal()))); + EXPECT_TRUE(matches("class X { virtual void f() final; };", + cxxMethodDecl(isFinal()))); + EXPECT_TRUE(notMatches("class X {};", cxxRecordDecl(isFinal()))); + EXPECT_TRUE( + notMatches("class X { virtual void f(); };", cxxMethodDecl(isFinal()))); +} + TEST(Matcher, MatchesVirtualMethod) { EXPECT_TRUE(matches("class X { virtual int f(); };", - methodDecl(isVirtual(), hasName("::X::f")))); - EXPECT_TRUE(notMatches("class X { int f(); };", - methodDecl(isVirtual()))); + cxxMethodDecl(isVirtual(), hasName("::X::f")))); + EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(isVirtual()))); } TEST(Matcher, MatchesPureMethod) { EXPECT_TRUE(matches("class X { virtual int f() = 0; };", - methodDecl(isPure(), hasName("::X::f")))); - EXPECT_TRUE(notMatches("class X { int f(); };", - methodDecl(isPure()))); + cxxMethodDecl(isPure(), hasName("::X::f")))); + EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(isPure()))); +} + +TEST(Matcher, MatchesCopyAssignmentOperator) { + EXPECT_TRUE(matches("class X { X &operator=(X); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(const X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(volatile X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(const volatile X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(notMatches("class X { X &operator=(X &&); };", + cxxMethodDecl(isCopyAssignmentOperator()))); } TEST(Matcher, MatchesConstMethod) { - EXPECT_TRUE(matches("struct A { void foo() const; };", - methodDecl(isConst()))); - EXPECT_TRUE(notMatches("struct A { void foo(); };", - methodDecl(isConst()))); + EXPECT_TRUE( + matches("struct A { void foo() const; };", cxxMethodDecl(isConst()))); + EXPECT_TRUE( + notMatches("struct A { void foo(); };", cxxMethodDecl(isConst()))); } TEST(Matcher, MatchesOverridingMethod) { EXPECT_TRUE(matches("class X { virtual int f(); }; " "class Y : public X { int f(); };", - methodDecl(isOverride(), hasName("::Y::f")))); + cxxMethodDecl(isOverride(), hasName("::Y::f")))); EXPECT_TRUE(notMatches("class X { virtual int f(); }; " - "class Y : public X { int f(); };", - methodDecl(isOverride(), hasName("::X::f")))); + "class Y : public X { int f(); };", + cxxMethodDecl(isOverride(), hasName("::X::f")))); EXPECT_TRUE(notMatches("class X { int f(); }; " "class Y : public X { int f(); };", - methodDecl(isOverride()))); + cxxMethodDecl(isOverride()))); EXPECT_TRUE(notMatches("class X { int f(); int f(int); }; ", - methodDecl(isOverride()))); + cxxMethodDecl(isOverride()))); EXPECT_TRUE( matches("template <typename Base> struct Y : Base { void f() override;};", - methodDecl(isOverride(), hasName("::Y::f")))); + cxxMethodDecl(isOverride(), hasName("::Y::f")))); } TEST(Matcher, ConstructorCall) { - StatementMatcher Constructor = constructExpr(); + StatementMatcher Constructor = cxxConstructExpr(); EXPECT_TRUE( matches("class X { public: X(); }; void x() { X x; }", Constructor)); @@ -1827,7 +1984,7 @@ TEST(Matcher, ConstructorCall) { } TEST(Matcher, ConstructorArgument) { - StatementMatcher Constructor = constructExpr( + StatementMatcher Constructor = cxxConstructExpr( hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( @@ -1843,7 +2000,7 @@ TEST(Matcher, ConstructorArgument) { notMatches("class X { public: X(int); }; void x() { int z; X x(z); }", Constructor)); - StatementMatcher WrongIndex = constructExpr( + StatementMatcher WrongIndex = cxxConstructExpr( hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( notMatches("class X { public: X(int); }; void x() { int y; X x(y); }", @@ -1851,7 +2008,7 @@ TEST(Matcher, ConstructorArgument) { } TEST(Matcher, ConstructorArgumentCount) { - StatementMatcher Constructor1Arg = constructExpr(argumentCountIs(1)); + StatementMatcher Constructor1Arg = cxxConstructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { X x(0); }", @@ -1868,7 +2025,8 @@ TEST(Matcher, ConstructorArgumentCount) { } TEST(Matcher, ConstructorListInitialization) { - StatementMatcher ConstructorListInit = constructExpr(isListInitialization()); + StatementMatcher ConstructorListInit = + cxxConstructExpr(isListInitialization()); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { X x{0}; }", @@ -1880,13 +2038,13 @@ TEST(Matcher, ConstructorListInitialization) { TEST(Matcher,ThisExpr) { EXPECT_TRUE( - matches("struct X { int a; int f () { return a; } };", thisExpr())); + matches("struct X { int a; int f () { return a; } };", cxxThisExpr())); EXPECT_TRUE( - notMatches("struct X { int f () { int a; return a; } };", thisExpr())); + notMatches("struct X { int f () { int a; return a; } };", cxxThisExpr())); } TEST(Matcher, BindTemporaryExpression) { - StatementMatcher TempExpression = bindTemporaryExpr(); + StatementMatcher TempExpression = cxxBindTemporaryExpr(); std::string ClassString = "class string { public: string(); ~string(); }; "; @@ -1953,46 +2111,76 @@ TEST(MaterializeTemporaryExpr, MatchesTemporary) { TEST(ConstructorDeclaration, SimpleCase) { EXPECT_TRUE(matches("class Foo { Foo(int i); };", - constructorDecl(ofClass(hasName("Foo"))))); + cxxConstructorDecl(ofClass(hasName("Foo"))))); EXPECT_TRUE(notMatches("class Foo { Foo(int i); };", - constructorDecl(ofClass(hasName("Bar"))))); + cxxConstructorDecl(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 { };", - constructorDecl(isImplicit()))); + cxxConstructorDecl(isImplicit()))); // The compiler added the implicit default constructor. EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();", - constructorDecl(isImplicit()))); + cxxConstructorDecl(isImplicit()))); EXPECT_TRUE(matches("class Foo { Foo(){} };", - constructorDecl(unless(isImplicit())))); + cxxConstructorDecl(unless(isImplicit())))); // The compiler added an implicit assignment operator. EXPECT_TRUE(matches("struct A { int x; } a = {0}, b = a; void f() { a = b; }", - methodDecl(isImplicit(), hasName("operator=")))); + cxxMethodDecl(isImplicit(), hasName("operator=")))); +} + +TEST(ConstructorDeclaration, IsExplicit) { + EXPECT_TRUE(matches("struct S { explicit S(int); };", + cxxConstructorDecl(isExplicit()))); + EXPECT_TRUE(notMatches("struct S { S(int); };", + cxxConstructorDecl(isExplicit()))); +} + +TEST(ConstructorDeclaration, Kinds) { + EXPECT_TRUE(matches("struct S { S(); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(); };", + cxxConstructorDecl(isMoveConstructor()))); + + EXPECT_TRUE(notMatches("struct S { S(const S&); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(matches("struct S { S(const S&); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(const S&); };", + cxxConstructorDecl(isMoveConstructor()))); + + EXPECT_TRUE(notMatches("struct S { S(S&&); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(S&&); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(matches("struct S { S(S&&); };", + cxxConstructorDecl(isMoveConstructor()))); } TEST(DestructorDeclaration, MatchesVirtualDestructor) { EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };", - destructorDecl(ofClass(hasName("Foo"))))); + cxxDestructorDecl(ofClass(hasName("Foo"))))); } TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) { EXPECT_TRUE(notMatches("class Foo {};", - destructorDecl(ofClass(hasName("Foo"))))); + cxxDestructorDecl(ofClass(hasName("Foo"))))); } TEST(HasAnyConstructorInitializer, SimpleCase) { - EXPECT_TRUE(notMatches( - "class Foo { Foo() { } };", - constructorDecl(hasAnyConstructorInitializer(anything())))); - EXPECT_TRUE(matches( - "class Foo {" - " Foo() : foo_() { }" - " int foo_;" - "};", - constructorDecl(hasAnyConstructorInitializer(anything())))); + EXPECT_TRUE( + notMatches("class Foo { Foo() { } };", + cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); + EXPECT_TRUE( + matches("class Foo {" + " Foo() : foo_() { }" + " int foo_;" + "};", + cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); } TEST(HasAnyConstructorInitializer, ForField) { @@ -2003,11 +2191,11 @@ TEST(HasAnyConstructorInitializer, ForField) { " Baz foo_;" " Baz bar_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasType(recordDecl(hasName("Baz")))))))); - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasName("foo_")))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasType(recordDecl(hasName("Bar")))))))); } @@ -2017,9 +2205,9 @@ TEST(HasAnyConstructorInitializer, WithInitializer) { " Foo() : foo_(0) { }" " int foo_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(0))))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(1))))))); } @@ -2031,16 +2219,40 @@ TEST(HasAnyConstructorInitializer, IsWritten) { " Bar foo_;" " Bar bar_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("foo_")), isWritten()))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), isWritten()))))); - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), unless(isWritten())))))); } +TEST(HasAnyConstructorInitializer, IsBaseInitializer) { + static const char Code[] = + "struct B {};" + "struct D : B {" + " int I;" + " D(int i) : I(i) {}" + "};" + "struct E : B {" + " E() : B() {}" + "};"; + EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), + hasName("E"))))); + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), + hasName("D"))))); + EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), + hasName("D"))))); + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), + hasName("E"))))); +} + TEST(Matcher, NewExpression) { - StatementMatcher New = newExpr(); + StatementMatcher New = cxxNewExpr(); EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New)); EXPECT_TRUE( @@ -2051,7 +2263,7 @@ TEST(Matcher, NewExpression) { } TEST(Matcher, NewExpressionArgument) { - StatementMatcher New = constructExpr( + StatementMatcher New = cxxConstructExpr( hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( @@ -2064,7 +2276,7 @@ TEST(Matcher, NewExpressionArgument) { notMatches("class X { public: X(int); }; void x() { int z; new X(z); }", New)); - StatementMatcher WrongIndex = constructExpr( + StatementMatcher WrongIndex = cxxConstructExpr( hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( notMatches("class X { public: X(int); }; void x() { int y; new X(y); }", @@ -2072,7 +2284,7 @@ TEST(Matcher, NewExpressionArgument) { } TEST(Matcher, NewExpressionArgumentCount) { - StatementMatcher New = constructExpr(argumentCountIs(1)); + StatementMatcher New = cxxConstructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { new X(0); }", New)); @@ -2083,11 +2295,11 @@ TEST(Matcher, NewExpressionArgumentCount) { TEST(Matcher, DeleteExpression) { EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }", - deleteExpr())); + cxxDeleteExpr())); } TEST(Matcher, DefaultArgument) { - StatementMatcher Arg = defaultArgExpr(); + StatementMatcher Arg = cxxDefaultArgExpr(); EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg)); EXPECT_TRUE( @@ -2152,7 +2364,7 @@ TEST(Matcher, FloatLiterals) { } TEST(Matcher, NullPtrLiteral) { - EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr())); + EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr())); } TEST(Matcher, GNUNullExpr) { @@ -2164,7 +2376,8 @@ TEST(Matcher, AsmStatement) { } TEST(Matcher, Conditions) { - StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true)))); + StatementMatcher Condition = + ifStmt(hasCondition(cxxBoolLiteral(equals(true)))); EXPECT_TRUE(matches("void x() { if (true) {} }", Condition)); EXPECT_TRUE(notMatches("void x() { if (false) {} }", Condition)); @@ -2175,13 +2388,13 @@ TEST(Matcher, Conditions) { TEST(IfStmt, ChildTraversalMatchers) { EXPECT_TRUE(matches("void f() { if (false) true; else false; }", - ifStmt(hasThen(boolLiteral(equals(true)))))); + ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(notMatches("void f() { if (false) false; else true; }", - ifStmt(hasThen(boolLiteral(equals(true)))))); + ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(matches("void f() { if (false) false; else true; }", - ifStmt(hasElse(boolLiteral(equals(true)))))); + ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(notMatches("void f() { if (false) true; else false; }", - ifStmt(hasElse(boolLiteral(equals(true)))))); + ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); } TEST(MatchBinaryOperator, HasOperatorName) { @@ -2193,17 +2406,22 @@ TEST(MatchBinaryOperator, HasOperatorName) { TEST(MatchBinaryOperator, HasLHSAndHasRHS) { StatementMatcher OperatorTrueFalse = - binaryOperator(hasLHS(boolLiteral(equals(true))), - hasRHS(boolLiteral(equals(false)))); + binaryOperator(hasLHS(cxxBoolLiteral(equals(true))), + hasRHS(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true || false; }", OperatorTrueFalse)); EXPECT_TRUE(matches("void x() { true && false; }", OperatorTrueFalse)); EXPECT_TRUE(notMatches("void x() { false || true; }", OperatorTrueFalse)); + + StatementMatcher OperatorIntPointer = arraySubscriptExpr( + hasLHS(hasType(isInteger())), hasRHS(hasType(pointsTo(qualType())))); + EXPECT_TRUE(matches("void x() { 1[\"abc\"]; }", OperatorIntPointer)); + EXPECT_TRUE(notMatches("void x() { \"abc\"[1]; }", OperatorIntPointer)); } TEST(MatchBinaryOperator, HasEitherOperand) { StatementMatcher HasOperand = - binaryOperator(hasEitherOperand(boolLiteral(equals(false)))); + binaryOperator(hasEitherOperand(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true || false; }", HasOperand)); EXPECT_TRUE(matches("void x() { false && true; }", HasOperand)); @@ -2320,7 +2538,7 @@ TEST(MatchUnaryOperator, HasOperatorName) { TEST(MatchUnaryOperator, HasUnaryOperand) { StatementMatcher OperatorOnFalse = - unaryOperator(hasUnaryOperand(boolLiteral(equals(false)))); + unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { !false; }", OperatorOnFalse)); EXPECT_TRUE(notMatches("void x() { !true; }", OperatorOnFalse)); @@ -2363,15 +2581,15 @@ TEST(Matcher, UnaryOperatorTypes) { TEST(Matcher, ConditionalOperator) { StatementMatcher Conditional = conditionalOperator( - hasCondition(boolLiteral(equals(true))), - hasTrueExpression(boolLiteral(equals(false)))); + hasCondition(cxxBoolLiteral(equals(true))), + hasTrueExpression(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true ? false : true; }", Conditional)); EXPECT_TRUE(notMatches("void x() { false ? false : true; }", Conditional)); EXPECT_TRUE(notMatches("void x() { true ? true : false; }", Conditional)); StatementMatcher ConditionalFalse = conditionalOperator( - hasFalseExpression(boolLiteral(equals(false)))); + hasFalseExpression(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse)); EXPECT_TRUE( @@ -2478,13 +2696,13 @@ TEST(Matcher, IsDefinition) { EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA)); DeclarationMatcher DefinitionOfMethodA = - methodDecl(hasName("a"), isDefinition()); + cxxMethodDecl(hasName("a"), isDefinition()); EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA)); EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA)); } TEST(Matcher, OfClass) { - StatementMatcher Constructor = constructExpr(hasDeclaration(methodDecl( + StatementMatcher Constructor = cxxConstructExpr(hasDeclaration(cxxMethodDecl( ofClass(hasName("X"))))); EXPECT_TRUE( @@ -2502,7 +2720,7 @@ TEST(Matcher, VisitsTemplateInstantiations) { "class A { public: void x(); };" "template <typename T> class B { public: void y() { T t; t.x(); } };" "void f() { B<A> b; b.y(); }", - callExpr(callee(methodDecl(hasName("x")))))); + callExpr(callee(cxxMethodDecl(hasName("x")))))); EXPECT_TRUE(matches( "class A { public: void x(); };" @@ -2513,8 +2731,8 @@ TEST(Matcher, VisitsTemplateInstantiations) { "void f() {" " C::B<A> b; b.y();" "}", - recordDecl(hasName("C"), - hasDescendant(callExpr(callee(methodDecl(hasName("x")))))))); + recordDecl(hasName("C"), hasDescendant(callExpr( + callee(cxxMethodDecl(hasName("x")))))))); } TEST(Matcher, HandlesNullQualTypes) { @@ -2607,10 +2825,10 @@ TEST(For, ForLoopInternals) { TEST(For, ForRangeLoopInternals) { EXPECT_TRUE(matches("void f(){ int a[] {1, 2}; for (int i : a); }", - forRangeStmt(hasLoopVariable(anything())))); + cxxForRangeStmt(hasLoopVariable(anything())))); EXPECT_TRUE(matches( "void f(){ int a[] {1, 2}; for (int i : a); }", - forRangeStmt(hasRangeInit(declRefExpr(to(varDecl(hasName("a")))))))); + cxxForRangeStmt(hasRangeInit(declRefExpr(to(varDecl(hasName("a")))))))); } TEST(For, NegativeForLoopInternals) { @@ -2650,7 +2868,7 @@ TEST(HasBody, FindsBodyOfForWhileDoLoops) { EXPECT_TRUE(matches("void f() { do {} while(true); }", doStmt(hasBody(compoundStmt())))); EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }", - forRangeStmt(hasBody(compoundStmt())))); + cxxForRangeStmt(hasBody(compoundStmt())))); } TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { @@ -2771,16 +2989,16 @@ TEST(Member, MatchesMemberAllocationFunction) { 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")); + cxxMethodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); EXPECT_TRUE(matches("class X { void operator delete(void*); };", - methodDecl(ofClass(hasName("X"))))); + cxxMethodDecl(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")); + cxxMethodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); } TEST(HasObjectExpression, DoesNotMatchMember) { @@ -2822,6 +3040,15 @@ TEST(Field, MatchesField) { EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m")))); } +TEST(IsVolatileQualified, QualifiersMatch) { + EXPECT_TRUE(matches("volatile int i = 42;", + varDecl(hasType(isVolatileQualified())))); + EXPECT_TRUE(notMatches("volatile int *i;", + varDecl(hasType(isVolatileQualified())))); + EXPECT_TRUE(matches("typedef volatile int v_int; v_int i = 42;", + varDecl(hasType(isVolatileQualified())))); +} + TEST(IsConstQualified, MatchesConstInt) { EXPECT_TRUE(matches("const int i = 42;", varDecl(hasType(isConstQualified())))); @@ -2868,59 +3095,59 @@ TEST(CastExpression, DoesNotMatchNonCasts) { TEST(ReinterpretCast, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); } TEST(ReinterpretCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", reinterpretCastExpr())); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); } TEST(FunctionalCast, MatchesSimpleCase) { std::string foo_class = "class Foo { public: Foo(const char*); };"; EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }", - functionalCastExpr())); + cxxFunctionalCastExpr())); } TEST(FunctionalCast, DoesNotMatchOtherCasts) { std::string FooClass = "class Foo { public: Foo(const char*); };"; EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }", - functionalCastExpr())); + cxxFunctionalCastExpr())); EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = \"hello world\"; }", - functionalCastExpr())); + cxxFunctionalCastExpr())); } TEST(DynamicCast, MatchesSimpleCase) { EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - dynamicCastExpr())); + cxxDynamicCastExpr())); } TEST(StaticCast, MatchesSimpleCase) { EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));", - staticCastExpr())); + cxxStaticCastExpr())); } TEST(StaticCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", staticCastExpr())); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxStaticCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - staticCastExpr())); + cxxStaticCastExpr())); EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);", - staticCastExpr())); + cxxStaticCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - staticCastExpr())); + cxxStaticCastExpr())); } TEST(CStyleCast, MatchesSimpleCase) { @@ -2939,7 +3166,7 @@ TEST(CStyleCast, DoesNotMatchOtherCasts) { TEST(HasDestinationType, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = static_cast<char*>(0);", - staticCastExpr(hasDestinationType( + cxxStaticCastExpr(hasDestinationType( pointsTo(TypeMatcher(anything())))))); } @@ -3142,7 +3369,7 @@ TEST(HasSourceExpression, MatchesImplicitCasts) { EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };" "void r() {string a_string; URL url = a_string; }", implicitCastExpr( - hasSourceExpression(constructExpr())))); + hasSourceExpression(cxxConstructExpr())))); } TEST(HasSourceExpression, MatchesExplicitCasts) { @@ -3314,21 +3541,26 @@ TEST(SwitchCase, MatchesEachCase) { TEST(ForEachConstructorInitializer, MatchesInitializers) { EXPECT_TRUE(matches( "struct X { X() : i(42), j(42) {} int i, j; };", - constructorDecl(forEachConstructorInitializer(ctorInitializer())))); + cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer())))); } 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 { } catch(int X) { }", cxxCatchStmt())); + EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxTryStmt())); + EXPECT_TRUE( + notMatches("void foo() try { } catch(int X) { }", cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw; } catch(int X) { }", - throwExpr())); + cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw 5;} catch(int X) { }", - throwExpr())); + cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw; } catch(...) { }", - catchStmt(isCatchAll()))); + cxxCatchStmt(isCatchAll()))); EXPECT_TRUE(notMatches("void foo() try { throw; } catch(int) { }", - catchStmt(isCatchAll()))); + cxxCatchStmt(isCatchAll()))); + EXPECT_TRUE(matches("void foo() try {} catch(int X) { }", + varDecl(isExceptionVariable()))); + EXPECT_TRUE(notMatches("void foo() try { int X; } catch (...) { }", + varDecl(isExceptionVariable()))); } TEST(HasConditionVariableStatement, DoesNotMatchCondition) { @@ -3460,12 +3692,12 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class X { void f(); void g(); };", - recordDecl(decl().bind("x"), hasMethod(hasName("g"))), + cxxRecordDecl(decl().bind("x"), hasMethod(hasName("g"))), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class X { X() : a(1), b(2) {} double a; int b; };", recordDecl(decl().bind("x"), - has(constructorDecl( + has(cxxConstructorDecl( hasAnyConstructorInitializer(forField(hasName("b")))))), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( @@ -3489,12 +3721,12 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A{}; class B{}; class C : B, A {};", - recordDecl(decl().bind("x"), isDerivedFrom("::A")), + cxxRecordDecl(decl().bind("x"), isDerivedFrom("::A")), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A{}; typedef A B; typedef A C; typedef A D;" "class E : A {};", - recordDecl(decl().bind("x"), isDerivedFrom("C")), + cxxRecordDecl(decl().bind("x"), isDerivedFrom("C")), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A { class B { void f() {} }; };", @@ -3513,8 +3745,8 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A { A() : s(), i(42) {} const char *s; int i; };", - constructorDecl(hasName("::A::A"), decl().bind("x"), - forEachConstructorInitializer(forField(hasName("i")))), + cxxConstructorDecl(hasName("::A::A"), decl().bind("x"), + forEachConstructorInitializer(forField(hasName("i")))), new VerifyIdIsBoundTo<Decl>("x", 1))); } @@ -3588,11 +3820,11 @@ TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X {}; class A {}; X<A> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {}; X<A> x;", - recordDecl(isTemplateInstantiation(), hasDescendant( + cxxRecordDecl(isTemplateInstantiation(), hasDescendant( fieldDecl(hasType(recordDecl(hasName("A")))))))); } @@ -3607,7 +3839,7 @@ TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {};" "template class X<A>;", - recordDecl(isTemplateInstantiation(), hasDescendant( + cxxRecordDecl(isTemplateInstantiation(), hasDescendant( fieldDecl(hasType(recordDecl(hasName("A")))))))); } @@ -3616,7 +3848,7 @@ TEST(IsTemplateInstantiation, EXPECT_TRUE(matches( "template <typename T> class X {};" "template <typename T> class X<T*> {}; class A {}; X<A*> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, @@ -3627,7 +3859,7 @@ TEST(IsTemplateInstantiation, " template <typename U> class Y { U u; };" " Y<A> y;" "};", - recordDecl(hasName("::X::Y"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X::Y"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { @@ -3640,31 +3872,31 @@ TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { " template <typename U> class Y { U u; };" " Y<T> y;" "}; X<A> x;", - recordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); + cxxRecordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) { EXPECT_TRUE(notMatches( "template <typename T> class X {}; class A {};" "template <> class X<A> {}; X<A> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { EXPECT_TRUE(notMatches( "class A {}; class Y { A a; };", - recordDecl(isTemplateInstantiation()))); + cxxRecordDecl(isTemplateInstantiation()))); } TEST(IsInstantiated, MatchesInstantiation) { EXPECT_TRUE( matches("template<typename T> class A { T i; }; class Y { A<int> a; };", - recordDecl(isInstantiated()))); + cxxRecordDecl(isInstantiated()))); } TEST(IsInstantiated, NotMatchesDefinition) { EXPECT_TRUE(notMatches("template<typename T> class A { T i; };", - recordDecl(isInstantiated()))); + cxxRecordDecl(isInstantiated()))); } TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { @@ -3716,7 +3948,7 @@ TEST(IsExplicitTemplateSpecialization, DoesNotMatchPrimaryTemplate) { EXPECT_TRUE(notMatches( "template <typename T> class X {};", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t);", functionDecl(isExplicitTemplateSpecialization()))); @@ -3727,7 +3959,7 @@ TEST(IsExplicitTemplateSpecialization, EXPECT_TRUE(notMatches( "template <typename T> class X {};" "template class X<int>; extern template class X<long>;", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t) {}" "template void f(int t); extern template void f(long t);", @@ -3738,7 +3970,7 @@ TEST(IsExplicitTemplateSpecialization, DoesNotMatchImplicitTemplateInstantiations) { EXPECT_TRUE(notMatches( "template <typename T> class X {}; X<int> x;", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t); void g() { f(10); }", functionDecl(isExplicitTemplateSpecialization()))); @@ -3749,7 +3981,7 @@ TEST(IsExplicitTemplateSpecialization, EXPECT_TRUE(matches( "template <typename T> class X {};" "template<> class X<int> {};", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(matches( "template <typename T> void f(T t) {}" "template<> void f(int t) {}", @@ -3831,7 +4063,7 @@ TEST(HasAncestor, MatchesInTemplateInstantiations) { TEST(HasAncestor, MatchesInImplicitCode) { EXPECT_TRUE(matches( "struct X {}; struct A { A() {} X x; };", - constructorDecl( + cxxConstructorDecl( hasAnyConstructorInitializer(withInitializer(expr( hasAncestor(recordDecl(hasName("A"))))))))); } @@ -3854,8 +4086,9 @@ TEST(HasAncestor, MatchesAllAncestors) { "void t() { C<int>::f(); }", integerLiteral( equals(42), - allOf(hasAncestor(recordDecl(isTemplateInstantiation())), - hasAncestor(recordDecl(unless(isTemplateInstantiation()))))))); + allOf( + hasAncestor(cxxRecordDecl(isTemplateInstantiation())), + hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation()))))))); } TEST(HasParent, MatchesAllParents) { @@ -3865,23 +4098,23 @@ TEST(HasParent, MatchesAllParents) { integerLiteral( equals(42), hasParent(compoundStmt(hasParent(functionDecl( - hasParent(recordDecl(isTemplateInstantiation()))))))))); - EXPECT_TRUE(matches( - "template <typename T> struct C { static void f() { 42; } };" - "void t() { C<int>::f(); }", - integerLiteral( - equals(42), - hasParent(compoundStmt(hasParent(functionDecl( - hasParent(recordDecl(unless(isTemplateInstantiation())))))))))); + hasParent(cxxRecordDecl(isTemplateInstantiation()))))))))); + EXPECT_TRUE( + matches("template <typename T> struct C { static void f() { 42; } };" + "void t() { C<int>::f(); }", + integerLiteral( + equals(42), + hasParent(compoundStmt(hasParent(functionDecl(hasParent( + cxxRecordDecl(unless(isTemplateInstantiation())))))))))); EXPECT_TRUE(matches( "template <typename T> struct C { static void f() { 42; } };" "void t() { C<int>::f(); }", integerLiteral(equals(42), - hasParent(compoundStmt(allOf( - hasParent(functionDecl( - hasParent(recordDecl(isTemplateInstantiation())))), - hasParent(functionDecl(hasParent(recordDecl( - unless(isTemplateInstantiation()))))))))))); + hasParent(compoundStmt( + allOf(hasParent(functionDecl(hasParent( + cxxRecordDecl(isTemplateInstantiation())))), + hasParent(functionDecl(hasParent(cxxRecordDecl( + unless(isTemplateInstantiation()))))))))))); EXPECT_TRUE( notMatches("template <typename T> struct C { static void f() {} };" "void t() { C<int>::f(); }", @@ -3913,9 +4146,16 @@ TEST(TypeMatching, MatchesTypes) { EXPECT_TRUE(matches("struct S {};", qualType().bind("loc"))); } +TEST(TypeMatching, MatchesBool) { + EXPECT_TRUE(matches("struct S { bool func(); };", + cxxMethodDecl(returns(booleanType())))); + EXPECT_TRUE(notMatches("struct S { void func(); };", + cxxMethodDecl(returns(booleanType())))); +} + TEST(TypeMatching, MatchesVoid) { - EXPECT_TRUE( - matches("struct S { void func(); };", methodDecl(returns(voidType())))); + EXPECT_TRUE(matches("struct S { void func(); };", + cxxMethodDecl(returns(voidType())))); } TEST(TypeMatching, MatchesArrayTypes) { @@ -3952,6 +4192,11 @@ TEST(TypeMatching, MatchesArrayTypes) { EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger()))); } +TEST(TypeMatching, DecayedType) { + EXPECT_TRUE(matches("void f(int i[]);", valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))); + EXPECT_TRUE(notMatches("int i[7];", decayedType())); +} + TEST(TypeMatching, MatchesComplexTypes) { EXPECT_TRUE(matches("_Complex float f;", complexType())); EXPECT_TRUE(matches( @@ -4247,6 +4492,18 @@ TEST(ElaboratedTypeNarrowing, namesType) { elaboratedType(elaboratedType(namesType(typedefType()))))); } +TEST(TypeMatching, MatchesSubstTemplateTypeParmType) { + const std::string code = "template <typename T>" + "int F() {" + " return 1 + T();" + "}" + "int i = F<int>();"; + EXPECT_FALSE(matches(code, binaryOperator(hasLHS( + expr(hasType(substTemplateTypeParmType())))))); + EXPECT_TRUE(matches(code, binaryOperator(hasRHS( + expr(hasType(substTemplateTypeParmType())))))); +} + TEST(NNS, MatchesNestedNameSpecifiers) { EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", nestedNameSpecifier())); @@ -4254,6 +4511,8 @@ TEST(NNS, MatchesNestedNameSpecifiers) { nestedNameSpecifier())); EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}", nestedNameSpecifier())); + EXPECT_TRUE(matches("namespace a { namespace b {} } namespace ab = a::b;", + nestedNameSpecifier())); EXPECT_TRUE(matches( "struct A { static void f() {} }; void g() { A::f(); }", @@ -4268,6 +4527,16 @@ TEST(NullStatement, SimpleCases) { EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt())); } +TEST(NS, Anonymous) { + EXPECT_TRUE(notMatches("namespace N {}", namespaceDecl(isAnonymous()))); + EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous()))); +} + +TEST(NS, Alias) { + EXPECT_TRUE(matches("namespace test {} namespace alias = ::test;", + namespaceAliasDecl(hasName("alias")))); +} + TEST(NNS, MatchesTypes) { NestedNameSpecifierMatcher Matcher = nestedNameSpecifier( specifiesType(hasDeclaration(recordDecl(hasName("A"))))); @@ -4480,6 +4749,16 @@ public: decl(has(decl(equalsNode(TypedNode)))).bind(""))), *Node, Context)) != nullptr; } + bool verify(const BoundNodes &Nodes, ASTContext &Context, const Type *Node) { + // Use the original typed pointer to verify we can pass pointers to subtypes + // to equalsNode. + const T *TypedNode = cast<T>(Node); + const auto *Dec = Nodes.getNodeAs<FieldDecl>("decl"); + return selectFirst<T>( + "", match(fieldDecl(hasParent(decl(has(fieldDecl( + hasType(type(equalsNode(TypedNode)).bind(""))))))), + *Dec, Context)) != nullptr; + } }; TEST(IsEqualTo, MatchesNodesByIdentity) { @@ -4489,6 +4768,10 @@ TEST(IsEqualTo, MatchesNodesByIdentity) { EXPECT_TRUE(matchAndVerifyResultTrue( "void f() { if (true) if(true) {} }", ifStmt().bind(""), new VerifyAncestorHasChildIsEqual<IfStmt>())); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class X { class Y {} y; };", + fieldDecl(hasName("y"), hasType(type().bind(""))).bind("decl"), + new VerifyAncestorHasChildIsEqual<Type>())); } TEST(MatchFinder, CheckProfiling) { @@ -4656,12 +4939,12 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { "void f(StringRef v) {" " v.data();" "}", - memberCallExpr( - callee(methodDecl(hasName("data"))), - on(declRefExpr(to(varDecl(hasType(recordDecl(hasName("StringRef")))) - .bind("var")))), - unless(hasAncestor(stmt(hasDescendant(memberCallExpr( - callee(methodDecl(anyOf(hasName("size"), hasName("length")))), + cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("data"))), + on(declRefExpr(to( + varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), + unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( + callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) .bind("data"), new VerifyIdIsBoundTo<Expr>("data", 1))); @@ -4672,12 +4955,12 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { " v.data();" " v.size();" "}", - memberCallExpr( - callee(methodDecl(hasName("data"))), - on(declRefExpr(to(varDecl(hasType(recordDecl(hasName("StringRef")))) - .bind("var")))), - unless(hasAncestor(stmt(hasDescendant(memberCallExpr( - callee(methodDecl(anyOf(hasName("size"), hasName("length")))), + cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("data"))), + on(declRefExpr(to( + varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), + unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( + callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) .bind("data"))); } @@ -4687,6 +4970,13 @@ TEST(TypeDefDeclMatcher, Match) { typedefDecl(hasName("typedefDeclTest")))); } +TEST(IsInlineMatcher, IsInline) { + EXPECT_TRUE(matches("void g(); inline void f();", + functionDecl(isInline(), hasName("f")))); + EXPECT_TRUE(matches("namespace n { inline namespace m {} }", + namespaceDecl(isInline(), hasName("m")))); +} + // FIXME: Figure out how to specify paths so the following tests pass on Windows. #ifndef LLVM_ON_WIN32 @@ -4774,6 +5064,9 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) { objcMessageExpr(hasSelector("contents"), hasUnarySelector()))); EXPECT_TRUE(matchesObjC( Objc1String, + objcMessageExpr(hasSelector("contents"), numSelectorArgs(0)))); + EXPECT_TRUE(matchesObjC( + Objc1String, objcMessageExpr(matchesSelector("uppercase*"), argumentCountIs(0) ))); |