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. @@ -633,7 +633,7 @@
Matches block declarations. Example matches the declaration of the nameless block printing an input @@ -943,7 +943,7 @@
Matches Objective-C instance variable declarations. Example matches _enabled @@ -954,7 +954,7 @@
Matches Objective-C method declarations. Example matches both declaration and definition of -[Foo method] @@ -968,7 +968,7 @@
Matches Objective-C property declarations. Example matches enabled @@ -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. @@ -1200,7 +1210,7 @@
Matches OpenMP ``default`` clause. Given @@ -1252,7 +1262,7 @@
Matches atomic builtins.
Example matches __atomic_load_n(ptr, 1)
void foo() { int *ptr; __atomic_load_n(ptr, 1); }
@@ -1279,7 +1289,7 @@
Matches binary operator expressions. Example matches a || b @@ -1359,7 +1369,7 @@
Matches GNU __builtin_choose_expr.
Matches nullptr literal.
Matches C11 _Generic expression.
Matches GNU __null expression.
Matches Objective-C @catch statements. Example matches @catch @@ -2011,14 +2021,14 @@
Matches Objective-C statements. Example matches @throw obj;
Matches Objective-C @try statements. Example matches @try @@ -2105,7 +2115,7 @@
Matches statement expression (GNU extension).
Example match: ({ int X = 4; X; })
@@ -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 operator expressions (binary or unary) that have any of the specified names. @@ -2778,7 +2841,7 @@
Matches the operator Name of operator expressions (binary or unary). @@ -2787,7 +2850,7 @@
Matches all kinds of assignment operators. Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator())) @@ -2801,7 +2864,7 @@
Matches comparison operators. Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator())) @@ -3031,6 +3094,10 @@
Matches constructor declarations that are move constructors. @@ -3779,7 +3846,7 @@Matcher<Decl> isExpandedFromMacro std::string MacroName @@ -3936,6 +4003,21 @@ 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;
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+ templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+ templateArgumentLoc()))))))
+ matches `class C<int> c`.
+Matches C++11 scoped enum declaration. @@ -4110,6 +4192,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. @@ -4165,7 +4258,7 @@ @end Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, - Matcher<ObjCMethodDecl> + Matcher<ObjCMethodDecl>
Matches if the OpenMP ``default`` clause has ``firstprivate`` kind specified. @@ -4579,7 +4672,7 @@
Matches if the OpenMP ``default`` clause has ``none`` kind specified. Given @@ -4593,7 +4686,7 @@
Matches if the OpenMP ``default`` clause has ``shared`` kind specified. Given @@ -4772,7 +4865,7 @@
Returns true when the Objective-C method declaration is a class method. Example @@ -4784,7 +4877,7 @@
Matches if a declaration has a body attached. Example matches A, va, fa @@ -4802,11 +4895,11 @@ @end Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, - Matcher<ObjCMethodDecl> + Matcher<ObjCMethodDecl>
Returns true when the Objective-C method declaration is an instance method. Example @@ -4856,6 +4949,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 +5109,29 @@
Matches `QualifiedTypeLoc`s that have an unqualified `TypeLoc` matching +`InnerMatcher`. + +Given + int* x = 0; +qualifiedTypeLoc(hasUnqualifiedLoc(typeLoc())) + matches `int*`. +
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. @@ -5152,7 +5279,7 @@ @end Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, - Matcher<ObjCMethodDecl> + Matcher<ObjCMethodDecl>
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.
Matches the left hand side of binary operator expressions. Example matches a (matcher = binaryOperator(hasLHS())) @@ -6074,7 +6211,7 @@
Matches if both matchers match with opposite sides of the binary operator. Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), @@ -6086,7 +6223,7 @@
Matches the right hand side of binary operator expressions. Example matches b (matcher = binaryOperator(hasRHS())) @@ -6112,7 +6249,7 @@
Matches any parameter of a function or an ObjC method declaration or a block. @@ -6141,7 +6278,7 @@
Matches the n'th parameter of a function or an ObjC method declaration or a block. @@ -6161,7 +6298,7 @@
Matches if the type location of a node matches the inner matcher.
Examples:
@@ -6178,13 +6315,13 @@
cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
matches Foo(1, 2)
-Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
+Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
Matcher<CXXUnresolvedConstructExpr>,
Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
- Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
+ Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
Matcher<TypedefNameDecl>
Matches any clause in an OpenMP directive. Given @@ -8522,7 +8659,7 @@
Matches any parameter of a function or an ObjC method declaration or a block. @@ -8551,7 +8688,7 @@
Matches the n'th parameter of a function or an ObjC method declaration or a block. @@ -8571,7 +8708,7 @@
Matches if the type location of a node matches the inner matcher.
Examples:
@@ -8588,13 +8725,13 @@
cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
matches Foo(1, 2)
-Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
+Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
Matcher<CXXUnresolvedConstructExpr>,
Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
- Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
+ Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
Matcher<TypedefNameDecl>
Matches compound statements where at least one substatement matches
a given matcher. Also matches StmtExprs that have CompoundStmt as children.
@@ -8999,13 +9136,13 @@
cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
matches Foo(1, 2)
-Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
+Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
Matcher<CXXUnresolvedConstructExpr>,
Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
- Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
+ Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
Matcher<TypedefNameDecl>
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
@@ -9210,13 +9360,13 @@
cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
matches Foo(1, 2)
-Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
+Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
Matcher<CXXUnresolvedConstructExpr>,
Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
- Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
+ Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
Matcher<TypedefNameDecl>
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