diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -573,15 +573,6 @@
Matches class bases. - -Examples matches public virtual B. - class B {}; - class C : public virtual B {}; -
Matches attributes. Attributes may be attached with a variety of different syntaxes (including @@ -600,6 +591,15 @@
Matches class bases. + +Examples matches public virtual B. + class B {}; + class C : public virtual B {}; +
Matches constructor initializers. @@ -1160,6 +1160,16 @@ matches using namespace X
Matches using-enum declarations. + +Given + namespace X { enum x {...}; } + using enum X::x; +usingEnumDecl() + matches using enum X::x
Matches any value declaration. @@ -2252,6 +2262,59 @@
Matches elaborated `TypeLoc`s. + +Given + class C {}; + class C c; +elaboratedTypeLoc() + matches `class C`. +
Matches pointer `TypeLoc`s. + +Given + int* x; +pointerTypeLoc() + matches `int*`. +
Matches `QualifiedTypeLoc`s in the clang AST. + +Given + const int x = 0; +qualifiedTypeLoc() + matches `const int`. +
Matches reference `TypeLoc`s. + +Given + int x = 3; + int& xx = x; +referenceTypeLoc() + matches `int&`. +
Matches template specialization `TypeLoc`s. + +Given + template <typename T> class C {}; + C<char> var; +varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) + matches `C<char> var`. +
Matches TypeLocs in the clang AST.
Matches constructor declarations that are move constructors. @@ -3779,7 +3846,7 @@Matcher<Decl> isExpandedFromMacro std::string MacroName @@ -3936,6 +4003,22 @@ Matches statements that are (transitively) expanded from the named macro. Does not match if only part of the statement is expanded from that macro or -if different parts of the the statement are expanded from different +if different parts of the statement are expanded from different appearances of the macro.
Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching +`InnerMatcher`. + +Given + template <typename T> + class C {}; + class C<int> c; + + class D {}; + class D d; +elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); + matches the `TypeLoc` of the variable declaration of `c`, but not `d`. +
Matches C++11 scoped enum declaration. @@ -4110,6 +4193,17 @@
Matches a function declared with the specified return `TypeLoc`. + +Given + int f() { return 5; } + void g() {} +functionDecl(hasReturnTypeLoc(loc(asString("int")))) + matches the declaration of `f`, but not `g`. +
Matches a function declared with a trailing return type. @@ -4856,6 +4950,17 @@
Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching +`PointeeMatcher`. + +Given + int* x; +pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) + matches `int*`. +
Matches if the matched type is represented by the given string. @@ -5005,6 +5110,30 @@
Matches `QualifiedTypeLoc`s that have an unqualified `TypeLoc` matching +`InnerMatcher`. + +Given + int* const x; + const int y; +qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) + matches the `TypeLoc` of the variable declaration of `x`, but not `y`. +
Matches reference `TypeLoc`s that have a referent `TypeLoc` matching +`ReferentMatcher`. + +Given + int x = 3; + int& xx = x; +referenceTypeLoc(hasReferentLoc(loc(asString("int")))) + matches `int&`. +
Matches if a node equals a previously bound node. @@ -5232,7 +5361,7 @@Matcher<TypeLoc> isExpandedFromMacro std::string MacroName @@ -6060,6 +6189,16 @@ Matches statements that are (transitively) expanded from the named macro. Does not match if only part of the statement is expanded from that macro or -if different parts of the the statement are expanded from different +if different parts of the statement are expanded from different appearances of the macro.
Matches any using shadow declaration. + +Given + namespace X { void b(); } + using X::b; +usingDecl(hasAnyUsingShadowDecl(hasName("b")))) + matches using X::b
Matches if either the left hand side or the right hand side of a binary operator matches. @@ -7463,7 +7602,7 @@ } } -cxxRecordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the +cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the declaration of class D.
Matches template specialization `TypeLoc`s that have at least one +`TemplateArgumentLoc` matching the given `InnerMatcher`. + +Given + template<typename T> class A {}; + A<int> a; +varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("int"))))))) + matches `A<int> a`. +
Matches classTemplateSpecializations, templateSpecializationType and functionDecl that have at least one TemplateArgument matching the given @@ -9356,16 +9508,6 @@
Matches any using shadow declaration. - -Given - namespace X { void b(); } - using X::b; -usingDecl(hasAnyUsingShadowDecl(hasName("b")))) - matches using X::b
Matches a using shadow declaration where the target declaration is matched by the given matcher. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -6339,6 +6339,203 @@ new internal::TypeLocTypeMatcher(InnerMatcher)); } +/// Matches `QualifiedTypeLoc`s in the clang AST. +/// +/// Given +/// \code +/// const int x = 0; +/// \endcode +/// qualifiedTypeLoc() +/// matches `const int`. +extern const internal::VariadicDynCastAllOfMatcher+ qualifiedTypeLoc; + +/// Matches `QualifiedTypeLoc`s that have an unqualified `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// int* const x; +/// const int y; +/// \endcode +/// qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) +/// matches the `TypeLoc` of the variable declaration of `x`, but not `y`. +AST_MATCHER_P(QualifiedTypeLoc, hasUnqualifiedLoc, TypeLocMatcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getUnqualifiedLoc(), Finder, Builder); +} + +/// Matches a function declared with the specified return `TypeLoc`. +/// +/// Given +/// \code +/// int f() { return 5; } +/// void g() {} +/// \endcode +/// functionDecl(hasReturnTypeLoc(loc(asString("int")))) +/// matches the declaration of `f`, but not `g`. +AST_MATCHER_P(FunctionDecl, hasReturnTypeLoc, TypeLocMatcher, ReturnMatcher) { + auto Loc = Node.getFunctionTypeLoc(); + return Loc && ReturnMatcher.matches(Loc.getReturnLoc(), Finder, Builder); +} + +/// Matches pointer `TypeLoc`s. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc() +/// matches `int*`. +extern const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; + +/// Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching +/// `PointeeMatcher`. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) +/// matches `int*`. +AST_MATCHER_P(PointerTypeLoc, hasPointeeLoc, TypeLocMatcher, PointeeMatcher) { + return PointeeMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches reference `TypeLoc`s. +/// +/// Given +/// \code +/// int x = 3; +/// int& xx = x; +/// \endcode +/// referenceTypeLoc() +/// matches `int&`. +extern const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; + +/// Matches reference `TypeLoc`s that have a referent `TypeLoc` matching +/// `ReferentMatcher`. +/// +/// Given +/// \code +/// int x = 3; +/// int& xx = x; +/// \endcode +/// referenceTypeLoc(hasReferentLoc(loc(asString("int")))) +/// matches `int&`. +AST_MATCHER_P(ReferenceTypeLoc, hasReferentLoc, TypeLocMatcher, + ReferentMatcher) { + return ReferentMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches template specialization `TypeLoc`s. +/// +/// Given +/// \code +/// template class C {}; +/// C var; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) +/// matches `C var`. +extern const internal::VariadicDynCastAllOfMatcher< + TypeLoc, TemplateSpecializationTypeLoc> + templateSpecializationTypeLoc; + +/// Matches template specialization `TypeLoc`s that have at least one +/// `TemplateArgumentLoc` matching the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A a; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +/// hasTypeLoc(loc(asString("int"))))))) +/// matches `A a`. +AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc, + internal::Matcher , InnerMatcher) { + for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) { + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +inline bool +MatchTemplateArgLocAt(const DeclRefExpr &Node, unsigned int Index, + internal::Matcher InnerMatcher, + internal::ASTMatchFinder *Finder, + internal::BoundNodesTreeBuilder *Builder) { + llvm::ArrayRef ArgLocs = Node.template_arguments(); + return Index < ArgLocs.size() && + InnerMatcher.matches(ArgLocs[Index], Finder, Builder); +} + +inline bool +MatchTemplateArgLocAt(const TemplateSpecializationTypeLoc &Node, + unsigned int Index, + internal::Matcher InnerMatcher, + internal::ASTMatchFinder *Finder, + internal::BoundNodesTreeBuilder *Builder) { + return !Node.isNull() && Index < Node.getNumArgs() && + InnerMatcher.matches(Node.getArgLoc(Index), Finder, Builder); +} + +/// Matches template specialization `TypeLoc`s where the n'th +/// `TemplateArgumentLoc` matches the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A b; +/// A c; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +/// hasTypeLoc(loc(asString("double"))))))) +/// matches `A b`, but not `A c`. +AST_POLYMORPHIC_MATCHER_P2( + hasTemplateArgumentLoc, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc), + unsigned int, Index, internal::Matcher , InnerMatcher) { + return MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder, Builder); +} + +/// Matches elaborated `TypeLoc`s. +/// +/// Given +/// \code +/// class C {}; +/// class C c; +/// \endcode +/// elaboratedTypeLoc() +/// matches `class C`. +extern const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + +/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// template +/// class C {}; +/// class C c; +/// +/// class D {}; +/// class D d; +/// \endcode +/// elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); +/// matches the `TypeLoc` of the variable declaration of `c`, but not `d`. +AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, TypeLocMatcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder); +} + /// Matches type \c bool. /// /// Given diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -771,6 +771,19 @@ const internal::VariadicAllOfMatcher qualType; const internal::VariadicAllOfMatcher type; const internal::VariadicAllOfMatcher typeLoc; + +const internal::VariadicDynCastAllOfMatcher + qualifiedTypeLoc; +const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; +const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; +const internal::VariadicDynCastAllOfMatcher + templateSpecializationTypeLoc; +const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + const internal::VariadicDynCastAllOfMatcher unaryExprOrTypeTraitExpr; const internal::VariadicDynCastAllOfMatcher valueDecl; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -226,6 +226,7 @@ REGISTER_MATCHER(doStmt); REGISTER_MATCHER(eachOf); REGISTER_MATCHER(elaboratedType); + REGISTER_MATCHER(elaboratedTypeLoc); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(enumType); @@ -274,6 +275,7 @@ REGISTER_MATCHER(hasAnySelector); REGISTER_MATCHER(hasAnySubstatement); REGISTER_MATCHER(hasAnyTemplateArgument); + REGISTER_MATCHER(hasAnyTemplateArgumentLoc); REGISTER_MATCHER(hasAnyUsingShadowDecl); REGISTER_MATCHER(hasArgument); REGISTER_MATCHER(hasArgumentOfType); @@ -322,6 +324,7 @@ REGISTER_MATCHER(hasMemberName); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasNamedTypeLoc); REGISTER_MATCHER(hasNullSelector); REGISTER_MATCHER(hasObjectExpression); REGISTER_MATCHER(hasOperands); @@ -329,12 +332,15 @@ REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasPointeeLoc); REGISTER_MATCHER(hasQualifier); REGISTER_MATCHER(hasRHS); REGISTER_MATCHER(hasRangeInit); REGISTER_MATCHER(hasReceiver); REGISTER_MATCHER(hasReceiverType); + REGISTER_MATCHER(hasReferentLoc); REGISTER_MATCHER(hasReplacementType); + REGISTER_MATCHER(hasReturnTypeLoc); REGISTER_MATCHER(hasReturnValue); REGISTER_MATCHER(hasPlacementArg); REGISTER_MATCHER(hasSelector); @@ -348,6 +354,7 @@ REGISTER_MATCHER(hasSyntacticForm); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasTemplateArgumentLoc); REGISTER_MATCHER(hasThen); REGISTER_MATCHER(hasThreadStorageDuration); REGISTER_MATCHER(hasTrailingReturn); @@ -358,6 +365,7 @@ REGISTER_MATCHER(hasUnderlyingDecl); REGISTER_MATCHER(hasUnderlyingType); REGISTER_MATCHER(hasUnqualifiedDesugaredType); + REGISTER_MATCHER(hasUnqualifiedLoc); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); REGISTER_MATCHER(ignoringElidableConstructorCall); @@ -504,13 +512,16 @@ REGISTER_MATCHER(parmVarDecl); REGISTER_MATCHER(pointee); REGISTER_MATCHER(pointerType); + REGISTER_MATCHER(pointerTypeLoc); REGISTER_MATCHER(predefinedExpr); REGISTER_MATCHER(qualType); + REGISTER_MATCHER(qualifiedTypeLoc); REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(realFloatingPointType); REGISTER_MATCHER(recordDecl); REGISTER_MATCHER(recordType); REGISTER_MATCHER(referenceType); + REGISTER_MATCHER(referenceTypeLoc); REGISTER_MATCHER(refersToDeclaration); REGISTER_MATCHER(refersToIntegralType); REGISTER_MATCHER(refersToTemplate); @@ -538,6 +549,7 @@ REGISTER_MATCHER(templateArgumentLoc); REGISTER_MATCHER(templateName); REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(templateSpecializationTypeLoc); REGISTER_MATCHER(templateTemplateParmDecl); REGISTER_MATCHER(templateTypeParmDecl); REGISTER_MATCHER(templateTypeParmType); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2078,6 +2078,168 @@ notMatches(Code, typeAliasTemplateDecl(hasName("typeAliasDecl")))); } +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_BindsToConstIntVarDecl) { + EXPECT_TRUE(matches("const int x = 0;", + qualifiedTypeLoc(loc(asString("const int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_BindsToConstIntFunctionDecl) { + EXPECT_TRUE(matches("const int f() { return 5; }", + qualifiedTypeLoc(loc(asString("const int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_DoesNotBindToUnqualifiedVarDecl) { + EXPECT_TRUE(notMatches("int x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_IntDoesNotBindToConstIntDecl) { + EXPECT_TRUE( + notMatches("const int x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_IntDoesNotBindToConstFloatDecl) { + EXPECT_TRUE( + notMatches("const float x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, PointerTypeLocTest_BindsToAnyPointerTypeLoc) { + auto matcher = varDecl(hasName("x"), hasTypeLoc(pointerTypeLoc())); + EXPECT_TRUE(matches("int* x;", matcher)); + EXPECT_TRUE(matches("float* x;", matcher)); + EXPECT_TRUE(matches("char* x;", matcher)); + EXPECT_TRUE(matches("void* x;", matcher)); +} + +TEST_P(ASTMatchersTest, PointerTypeLocTest_DoesNotBindToNonPointerTypeLoc) { + auto matcher = varDecl(hasName("x"), hasTypeLoc(pointerTypeLoc())); + EXPECT_TRUE(notMatches("int x;", matcher)); + EXPECT_TRUE(notMatches("float x;", matcher)); + EXPECT_TRUE(notMatches("char x;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_BindsToAnyReferenceTypeLoc) { + if (!GetParam().isCXX()) { + return; + } + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; auto& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; const int& r = rr;", matcher)); + EXPECT_TRUE(matches("float rr = 3.0; float& r = rr;", matcher)); + EXPECT_TRUE(matches("char rr = 'a'; char& r = rr;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_DoesNotBindToNonReferenceTypeLoc) { + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(notMatches("int r;", matcher)); + EXPECT_TRUE(notMatches("int r = 3;", matcher)); + EXPECT_TRUE(notMatches("const int r = 3;", matcher)); + EXPECT_TRUE(notMatches("int* r;", matcher)); + EXPECT_TRUE(notMatches("float r;", matcher)); + EXPECT_TRUE(notMatches("char r;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_BindsToAnyRvalueReferenceTypeLoc) { + if (!GetParam().isCXX()) { + return; + } + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(matches("int&& r = 3;", matcher)); + EXPECT_TRUE(matches("auto&& r = 3;", matcher)); + EXPECT_TRUE(matches("float&& r = 3.0;", matcher)); +} + +TEST_P( + ASTMatchersTest, + TemplateSpecializationTypeLocTest_BindsToTemplateSpecializationExplicitInstantiation) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + matches("template class C {}; template class C ;", + classTemplateSpecializationDecl( + hasName("C"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + TemplateSpecializationTypeLocTest_BindsToVarDeclTemplateSpecialization) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches( + "template class C {}; C var;", + varDecl(hasName("var"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P( + ASTMatchersTest, + TemplateSpecializationTypeLocTest_DoesNotBindToNonTemplateSpecialization) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(notMatches( + "class C {}; C var;", + varDecl(hasName("var"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("class C {}; class C c;", + varDecl(hasName("c"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToNamespaceElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("namespace N { class D {}; } N::D d;", + varDecl(hasName("d"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToElaboratedStructDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("struct s {}; struct s ss;", + varDecl(hasName("ss"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNonElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("class C {}; C c;", + varDecl(hasName("c"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P( + ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNamespaceNonElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("namespace N { class D {}; } using N::D; D d;", + varDecl(hasName("d"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNonElaboratedStructDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("struct s {}; s ss;", + varDecl(hasName("ss"), hasTypeLoc(elaboratedTypeLoc())))); +} + TEST(ASTMatchersTestObjC, ObjCMessageExpr) { // Don't find ObjCMessageExpr where none are present. EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything()))); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5764,5 +5764,425 @@ IsPlacementNew)); } +TEST(HasUnqualifiedLoc, BindsToConstIntVarDecl) { + EXPECT_TRUE(matches("const int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToVolatileIntVarDecl) { + EXPECT_TRUE(matches("volatile int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToConstVolatileIntPointerVarDecl) { + EXPECT_TRUE( + matches("const volatile int* x = 0;", + qualifiedTypeLoc(hasUnqualifiedLoc(loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToConstIntFunctionDecl) { + EXPECT_TRUE( + matches("const int f() { return 5; }", + qualifiedTypeLoc(hasUnqualifiedLoc(loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, FloatBindsToConstFloatVarDecl) { + EXPECT_TRUE(matches("const float x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasUnqualifiedLoc, FloatDoesNotBindToIntVarDecl) { + EXPECT_TRUE(notMatches("int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasUnqualifiedLoc, FloatDoesNotBindToConstIntVarDecl) { + EXPECT_TRUE(notMatches("const int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, BindsToIntReturnTypeLoc) { + EXPECT_TRUE(matches( + "int f() { return 5; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("int")))))); +} + +TEST(HasReturnTypeLoc, BindsToFloatReturnTypeLoc) { + EXPECT_TRUE(matches( + "float f() { return 5.0; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, BindsToVoidReturnTypeLoc) { + EXPECT_TRUE(matches( + "void f() {}", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("void")))))); +} + +TEST(HasReturnTypeLoc, FloatDoesNotBindToIntReturnTypeLoc) { + EXPECT_TRUE(notMatches( + "int f() { return 5; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, IntDoesNotBindToFloatReturnTypeLoc) { + EXPECT_TRUE(notMatches( + "float f() { return 5.0; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, BindsToAnyPointeeTypeLoc) { + auto matcher = varDecl(hasName("x"), + hasTypeLoc(pointerTypeLoc(hasPointeeLoc(typeLoc())))); + EXPECT_TRUE(matches("int* x;", matcher)); + EXPECT_TRUE(matches("float* x;", matcher)); + EXPECT_TRUE(matches("char* x;", matcher)); + EXPECT_TRUE(matches("void* x;", matcher)); +} + +TEST(HasPointeeLoc, DoesNotBindToTypeLocWithoutPointee) { + auto matcher = varDecl(hasName("x"), + hasTypeLoc(pointerTypeLoc(hasPointeeLoc(typeLoc())))); + EXPECT_TRUE(notMatches("int x;", matcher)); + EXPECT_TRUE(notMatches("float x;", matcher)); + EXPECT_TRUE(notMatches("char x;", matcher)); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToInt) { + EXPECT_TRUE( + matches("int* x;", pointerTypeLoc(hasPointeeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToIntPointer) { + EXPECT_TRUE(matches("int** x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("int *")))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToTypeLocPointingToInt) { + EXPECT_TRUE(matches("int** x;", pointerTypeLoc(hasPointeeLoc(pointerTypeLoc( + hasPointeeLoc(loc(asString("int")))))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToFloat) { + EXPECT_TRUE(matches("float* x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("float")))))); +} + +TEST(HasPointeeLoc, IntPointeeDoesNotBindToTypeLocPointingToFloat) { + EXPECT_TRUE(notMatches("float* x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, FloatPointeeDoesNotBindToTypeLocPointingToInt) { + EXPECT_TRUE(notMatches( + "int* x;", pointerTypeLoc(hasPointeeLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, BindsToAnyReferentTypeLoc) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; auto& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; const int& r = rr;", matcher)); + EXPECT_TRUE(matches("float rr = 3.0; float& r = rr;", matcher)); + EXPECT_TRUE(matches("char rr = 'a'; char& r = rr;", matcher)); +} + +TEST(HasReferentLoc, DoesNotBindToTypeLocWithoutReferent) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(notMatches("int r;", matcher)); + EXPECT_TRUE(notMatches("int r = 3;", matcher)); + EXPECT_TRUE(notMatches("const int r = 3;", matcher)); + EXPECT_TRUE(notMatches("int* r;", matcher)); + EXPECT_TRUE(notMatches("float r;", matcher)); + EXPECT_TRUE(notMatches("char r;", matcher)); +} + +TEST(HasReferentLoc, BindsToAnyRvalueReference) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(matches("int&& r = 3;", matcher)); + EXPECT_TRUE(matches("auto&& r = 3;", matcher)); + EXPECT_TRUE(matches("float&& r = 3.0;", matcher)); +} + +TEST(HasReferentLoc, BindsToIntReferenceTypeLoc) { + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, BindsToIntRvalueReferenceTypeLoc) { + EXPECT_TRUE(matches("int&& r = 3;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, BindsToFloatReferenceTypeLoc) { + EXPECT_TRUE( + matches("float rr = 3.0; float& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, BindsToParameterWithIntReferenceTypeLoc) { + EXPECT_TRUE(matches( + "int f(int& r) { return r; }", + parmVarDecl(hasName("r"), hasTypeLoc(referenceTypeLoc( + hasReferentLoc(loc(asString("int")))))))); +} + +TEST(HasReferentLoc, IntReferenceDoesNotBindToFloatReferenceTypeLoc) { + EXPECT_TRUE( + notMatches("float rr = 3.0; float& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, FloatReferenceDoesNotBindToIntReferenceTypeLoc) { + EXPECT_TRUE( + notMatches("int rr = 3; int& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, DoesNotBindToParameterWithoutIntReferenceTypeLoc) { + EXPECT_TRUE(notMatches( + "int f(int r) { return r; }", + parmVarDecl(hasName("r"), hasTypeLoc(referenceTypeLoc( + hasReferentLoc(loc(asString("int")))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { + EXPECT_TRUE( + matches("template class A {}; A a;", + varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { + EXPECT_TRUE( + matches("template class A {}; A a;", + varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, + BindsToExplicitSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE( + matches(code, classTemplateSpecializationDecl( + hasName("A"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("double"))))))))); + EXPECT_TRUE(matches( + code, + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; A a;", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, + DoesNotBindToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; A a;", + varDecl(hasName("a"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; A a;", + varDecl(hasName("a"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(matches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(matches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 1, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; A a;", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, + DoesNotBindToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, + DoesNotBindToSpecializationWithMisplacedArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 1, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindWithBadIndex) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + -1, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 100, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithIntArgument) { + EXPECT_TRUE(matches(R"( + template T f(T t) { return t; } + int g() { int i = f (3); return i; } + )", + declRefExpr(to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithDoubleArgument) { + EXPECT_TRUE(matches( + R"( + template T f(T t) { return t; } + double g() { double i = f (3.0); return i; } + )", + declRefExpr( + to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double"))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindToDeclRefExprWithDoubleArgument) { + EXPECT_TRUE(notMatches( + R"( + template T f(T t) { return t; } + double g() { double i = f (3.0); return i; } + )", + declRefExpr( + to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int"))))))); +} + +TEST(HasNamedTypeLoc, BindsToElaboratedObjectDeclaration) { + EXPECT_TRUE(matches( + R"( + template + class C {}; + class C c; + )", + varDecl(hasName("c"), + hasTypeLoc(elaboratedTypeLoc( + hasNamedTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); +} + +TEST(HasNamedTypeLoc, DoesNotBindToNonElaboratedObjectDeclaration) { + EXPECT_TRUE(notMatches( + R"( + template + class C {}; + C c; + )", + varDecl(hasName("c"), + hasTypeLoc(elaboratedTypeLoc( + hasNamedTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); +} + } // namespace ast_matchers } // namespace clang