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,60 @@
Matches C or C++ elaborated `TypeLoc`s.
+
+Given
+ struct s {};
+ struct s ss;
+elaboratedTypeLoc()
+ matches the `TypeLoc` of the variable declaration of `ss`.
+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& l = x; + int&& r = 3; +referenceTypeLoc() + matches `int&` and `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 +3847,7 @@Matcher<Decl> isExpandedFromMacro std::string MacroName @@ -5232,7 +5300,7 @@ 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.Matcher<TypeLoc> isExpandedFromMacro std::string MacroName @@ -6060,6 +6128,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. @@ -7367,6 +7445,20 @@
Matches template specialization `TypeLoc`s where the n'th
+`TemplateArgumentLoc` matches the given `InnerMatcher`.
+
+Given
+ template<typename T, typename U> class A {};
+ A<double, int> b;
+ A<int, double> c;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+ hasTypeLoc(loc(asString("double")))))))
+ matches `A<double, int> b`, but not `A<int, double> c`.
+Matches a DeclRefExpr that refers to a declaration through a
specific using shadow declaration.
@@ -7463,7 +7555,7 @@
}
}
-cxxRecordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
+cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
declaration of class D.
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 ElaboratedTypes whose qualifier, a NestedNameSpecifier, matches InnerMatcher if the qualifier exists. @@ -8014,6 +8122,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 classTemplateSpecializations, templateSpecializationType and functionDecl where the n'th TemplateArgument matches the given InnerMatcher. @@ -8645,6 +8764,17 @@
Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching
+`PointeeMatcher`.
+
+Given
+ int* x;
+pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))
+ matches `int*`.
+Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. @@ -8756,6 +8886,18 @@
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 a node if the declaration associated with that node matches the given matcher. @@ -8790,6 +8932,18 @@
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&`.
+Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. @@ -9077,6 +9231,33 @@
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 template specialization `TypeLoc`s where the n'th
+`TemplateArgumentLoc` matches the given `InnerMatcher`.
+
+Given
+ template<typename T, typename U> class A {};
+ A<double, int> b;
+ A<int, double> c;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+ hasTypeLoc(loc(asString("double")))))))
+ matches `A<double, int> b`, but not `A<int, double> c`.
+Matches classTemplateSpecializations, templateSpecializationType and functionDecl that have at least one TemplateArgument matching the given @@ -9356,16 +9537,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,187 @@
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, internal::Matcher,
+ 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, internal::Matcher,
+ 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, internal::Matcher,
+ PointeeMatcher) {
+ return PointeeMatcher.matches(Node.getPointeeLoc(), Finder, Builder);
+}
+
+/// Matches reference `TypeLoc`s.
+///
+/// Given
+/// \code
+/// int x = 3;
+/// int& l = x;
+/// int&& r = 3;
+/// \endcode
+/// referenceTypeLoc()
+/// matches `int&` and `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, internal::Matcher,
+ 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;
+}
+
+/// 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, Index, internal::Matcher, InnerMatcher) {
+ return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder,
+ Builder);
+}
+
+/// Matches C or C++ elaborated `TypeLoc`s.
+///
+/// Given
+/// \code
+/// struct s {};
+/// struct s ss;
+/// \endcode
+/// elaboratedTypeLoc()
+/// matches the `TypeLoc` of the variable declaration of `ss`.
+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, internal::Matcher,
+ InnerMatcher) {
+ return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder);
+}
+
/// Matches type \c bool.
///
/// Given
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -2308,6 +2308,26 @@
llvm::Regex::RegexFlags Flags,
StringRef MatcherID);
+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);
+}
+
} // namespace internal
} // namespace ast_matchers
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,165 @@
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) {
+ 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,454 @@
IsPlacementNew));
}
+TEST(HasUnqualifiedLoc, BindsToConstIntVarDecl) {
+ EXPECT_TRUE(matches(
+ "const int x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("int"))))))));
+}
+
+TEST(HasUnqualifiedLoc, BindsToVolatileIntVarDecl) {
+ EXPECT_TRUE(matches(
+ "volatile int x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("int"))))))));
+}
+
+TEST(HasUnqualifiedLoc, BindsToConstVolatileIntVarDecl) {
+ EXPECT_TRUE(matches(
+ "const volatile int x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("int"))))))));
+}
+
+TEST(HasUnqualifiedLoc, BindsToConstPointerVarDecl) {
+ auto matcher = varDecl(
+ hasName("x"),
+ hasTypeLoc(qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc()))));
+ EXPECT_TRUE(matches("int* const x = 0;", matcher));
+ EXPECT_TRUE(notMatches("int const x = 0;", matcher));
+}
+
+TEST(HasUnqualifiedLoc, BindsToPointerToConstVolatileIntVarDecl) {
+ EXPECT_TRUE(
+ matches("const volatile int* x = 0;",
+ varDecl(hasName("x"),
+ hasTypeLoc(pointerTypeLoc(hasPointeeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("int"))))))))));
+}
+
+TEST(HasUnqualifiedLoc, BindsToConstIntFunctionDecl) {
+ EXPECT_TRUE(
+ matches("const int f() { return 5; }",
+ functionDecl(hasName("f"),
+ hasReturnTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("int"))))))));
+}
+
+TEST(HasUnqualifiedLoc, FloatBindsToConstFloatVarDecl) {
+ EXPECT_TRUE(matches(
+ "const float x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("float"))))))));
+}
+
+TEST(HasUnqualifiedLoc, FloatDoesNotBindToIntVarDecl) {
+ EXPECT_TRUE(notMatches(
+ "int x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(qualifiedTypeLoc(
+ hasUnqualifiedLoc(loc(asString("float"))))))));
+}
+
+TEST(HasUnqualifiedLoc, FloatDoesNotBindToConstIntVarDecl) {
+ EXPECT_TRUE(notMatches(
+ "const int x = 0;",
+ varDecl(hasName("x"), hasTypeLoc(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