[clang] ac74296 - Add `TypeLoc`-related matchers.
Yitzhak Mandelbaum via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 8 10:43:26 PDT 2021
Author: James King
Date: 2021-10-08T17:42:18Z
New Revision: ac742965628631059af7fdc77e8661fa660ac180
URL: https://github.com/llvm/llvm-project/commit/ac742965628631059af7fdc77e8661fa660ac180
DIFF: https://github.com/llvm/llvm-project/commit/ac742965628631059af7fdc77e8661fa660ac180.diff
LOG: Add `TypeLoc`-related matchers.
Contributes several matchers that involve `TypeLoc`s. These matchers are (in alphabetical order):
- elaboratedTypeLoc
- hasAnyTemplateArgumentLoc
- hasNamedTypeLoc
- hasPointeeLoc
- hasReferentLoc
- hasReturnTypeLoc
- hasTemplateArgumentLoc
- hasUnqualifiedLoc
- pointerTypeLoc
- qualifiedTypeLoc
- referenceTypeLoc
- templateSpecializationTypeLoc
Reviewed By: ymandel, aaron.ballman
Differential Revision: https://reviews.llvm.org/D111242
Added:
Modified:
clang/docs/LibASTMatchersReference.html
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/lib/ASTMatchers/ASTMatchersInternal.cpp
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 016531043a831..3977d26414521 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -573,15 +573,6 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_DECL_MATCHERS -->
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('cxxBaseSpecifier0')"><a name="cxxBaseSpecifier0Anchor">cxxBaseSpecifier</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxBaseSpecifier0"><pre>Matches class bases.
-
-Examples matches public virtual B.
- class B {};
- class C : public virtual B {};
-</pre></td></tr>
-
-
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>></td><td class="name" onclick="toggle('attr0')"><a name="attr0Anchor">attr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="attr0"><pre>Matches attributes.
Attributes may be attached with a variety of
diff erent syntaxes (including
@@ -600,6 +591,15 @@ <h2 id="decl-matchers">Node Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('cxxBaseSpecifier0')"><a name="cxxBaseSpecifier0Anchor">cxxBaseSpecifier</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxBaseSpecifier0"><pre>Matches class bases.
+
+Examples matches public virtual B.
+ class B {};
+ class C : public virtual B {};
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers.
@@ -1160,6 +1160,16 @@ <h2 id="decl-matchers">Node Matchers</h2>
matches using namespace X </pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingEnumDecl0')"><a name="usingEnumDecl0Anchor">usingEnumDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingEnumDecl.html">UsingEnumDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="usingEnumDecl0"><pre>Matches using-enum declarations.
+
+Given
+ namespace X { enum x {...}; }
+ using enum X::x;
+usingEnumDecl()
+ matches using enum X::x </pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('valueDecl0')"><a name="valueDecl0Anchor">valueDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="valueDecl0"><pre>Matches any value declaration.
@@ -2252,6 +2262,60 @@ <h2 id="decl-matchers">Node Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('elaboratedTypeLoc0')"><a name="elaboratedTypeLoc0Anchor">elaboratedTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ElaboratedTypeLoc.html">ElaboratedTypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="elaboratedTypeLoc0"><pre>Matches C or C++ elaborated `TypeLoc`s.
+
+Given
+ struct s {};
+ struct s ss;
+elaboratedTypeLoc()
+ matches the `TypeLoc` of the variable declaration of `ss`.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('pointerTypeLoc0')"><a name="pointerTypeLoc0Anchor">pointerTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="pointerTypeLoc0"><pre>Matches pointer `TypeLoc`s.
+
+Given
+ int* x;
+pointerTypeLoc()
+ matches `int*`.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('qualifiedTypeLoc0')"><a name="qualifiedTypeLoc0Anchor">qualifiedTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualifiedTypeLoc.html">QualifiedTypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="qualifiedTypeLoc0"><pre>Matches `QualifiedTypeLoc`s in the clang AST.
+
+Given
+ const int x = 0;
+qualifiedTypeLoc()
+ matches `const int`.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('referenceTypeLoc0')"><a name="referenceTypeLoc0Anchor">referenceTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches reference `TypeLoc`s.
+
+Given
+ int x = 3;
+ int& l = x;
+ int&& r = 3;
+referenceTypeLoc()
+ matches `int&` and `int&&`.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('templateSpecializationTypeLoc0')"><a name="templateSpecializationTypeLoc0Anchor">templateSpecializationTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationTypeLoc.html">TemplateSpecializationTypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="templateSpecializationTypeLoc0"><pre>Matches template specialization `TypeLoc`s.
+
+Given
+ template <typename T> class C {};
+ C<char> var;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc())))
+ matches `C<char> var`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
</pre></td></tr>
@@ -3031,6 +3095,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isInheritingConstructor0')"><a name="isInheritingConstructor0Anchor">isInheritingConstructor</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInheritingConstructor0"><pre></pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isMoveConstructor0')"><a name="isMoveConstructor0Anchor">isMoveConstructor</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isMoveConstructor0"><pre>Matches constructor declarations that are move constructors.
@@ -3779,7 +3847,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpandedFromMacro0')"><a name="isExpandedFromMacro0Anchor">isExpandedFromMacro</a></td><td>std::string MacroName</td></tr>
<tr><td colspan="4" class="doc" id="isExpandedFromMacro0"><pre>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
diff erent parts of the the statement are expanded from
diff erent
+if
diff erent parts of the statement are expanded from
diff erent
appearances of the macro.
</pre></td></tr>
@@ -5232,7 +5300,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpandedFromMacro2')"><a name="isExpandedFromMacro2Anchor">isExpandedFromMacro</a></td><td>std::string MacroName</td></tr>
<tr><td colspan="4" class="doc" id="isExpandedFromMacro2"><pre>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
diff erent parts of the the statement are expanded from
diff erent
+if
diff erent parts of the statement are expanded from
diff erent
appearances of the macro.
</pre></td></tr>
@@ -6060,6 +6128,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BaseUsingDecl.html">BaseUsingDecl</a>></td><td class="name" onclick="toggle('hasAnyUsingShadowDecl0')"><a name="hasAnyUsingShadowDecl0Anchor">hasAnyUsingShadowDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyUsingShadowDecl0"><pre>Matches any using shadow declaration.
+
+Given
+ namespace X { void b(); }
+ using X::b;
+usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
+ matches using X::b </pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a
binary operator matches.
@@ -7367,6 +7445,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('hasTemplateArgumentLoc0')"><a name="hasTemplateArgumentLoc0Anchor">hasTemplateArgumentLoc</a></td><td>unsigned Index, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTemplateArgumentLoc0"><pre>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`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('throughUsingDecl0')"><a name="throughUsingDecl0Anchor">throughUsingDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="throughUsingDecl0"><pre>Matches a DeclRefExpr that refers to a declaration through a
specific using shadow declaration.
@@ -7463,7 +7555,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
}
}
-cxxRecordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
+cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
declaration of class D.
</pre></td></tr>
@@ -7529,6 +7621,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ElaboratedTypeLoc.html">ElaboratedTypeLoc</a>></td><td class="name" onclick="toggle('hasNamedTypeLoc0')"><a name="hasNamedTypeLoc0Anchor">hasNamedTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasNamedTypeLoc0"><pre>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`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
matches InnerMatcher if the qualifier exists.
@@ -8014,6 +8122,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasReturnTypeLoc0')"><a name="hasReturnTypeLoc0Anchor">hasReturnTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> ReturnMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasReturnTypeLoc0"><pre>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`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasTemplateArgument2')"><a name="hasTemplateArgument2Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasTemplateArgument2"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
@@ -8645,6 +8764,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>></td><td class="name" onclick="toggle('hasPointeeLoc0')"><a name="hasPointeeLoc0Anchor">hasPointeeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> PointeeMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasPointeeLoc0"><pre>Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching
+`PointeeMatcher`.
+
+Given
+ int* x;
+pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))
+ matches `int*`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>></td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
@@ -8756,6 +8886,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualifiedTypeLoc.html">QualifiedTypeLoc</a>></td><td class="name" onclick="toggle('hasUnqualifiedLoc0')"><a name="hasUnqualifiedLoc0Anchor">hasUnqualifiedLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasUnqualifiedLoc0"><pre>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`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>></td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a node if the declaration associated with that node
matches the given matcher.
@@ -8790,6 +8932,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>></td><td class="name" onclick="toggle('hasReferentLoc0')"><a name="hasReferentLoc0Anchor">hasReferentLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> ReferentMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasReferentLoc0"><pre>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&`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>></td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
pointee matches a given matcher.
@@ -9077,6 +9231,33 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationTypeLoc.html">TemplateSpecializationTypeLoc</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgumentLoc0')"><a name="hasAnyTemplateArgumentLoc0Anchor">hasAnyTemplateArgumentLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyTemplateArgumentLoc0"><pre>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`.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationTypeLoc.html">TemplateSpecializationTypeLoc</a>></td><td class="name" onclick="toggle('hasTemplateArgumentLoc1')"><a name="hasTemplateArgumentLoc1Anchor">hasTemplateArgumentLoc</a></td><td>unsigned Index, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTemplateArgumentLoc1"><pre>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`.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument1')"><a name="hasAnyTemplateArgument1Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
@@ -9356,16 +9537,6 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>></td><td class="name" onclick="toggle('hasAnyUsingShadowDecl0')"><a name="hasAnyUsingShadowDecl0Anchor">hasAnyUsingShadowDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyUsingShadowDecl0"><pre>Matches any using shadow declaration.
-
-Given
- namespace X { void b(); }
- using X::b;
-usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
- matches using X::b </pre></td></tr>
-
-
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>></td><td class="name" onclick="toggle('hasTargetDecl0')"><a name="hasTargetDecl0Anchor">hasTargetDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasTargetDecl0"><pre>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
index 5887263a43e8c..dfd1d8bc56fc8 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6339,6 +6339,187 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
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<TypeLoc, QualifiedTypeLoc>
+ 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<TypeLoc>,
+ 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<TypeLoc>,
+ 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<TypeLoc, PointerTypeLoc>
+ 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<TypeLoc>,
+ 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<TypeLoc, ReferenceTypeLoc>
+ 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<TypeLoc>,
+ ReferentMatcher) {
+ return ReferentMatcher.matches(Node.getPointeeLoc(), Finder, Builder);
+}
+
+/// Matches template specialization `TypeLoc`s.
+///
+/// Given
+/// \code
+/// template <typename T> class C {};
+/// C<char> var;
+/// \endcode
+/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc())))
+/// matches `C<char> 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<typename T> class A {};
+/// A<int> a;
+/// \endcode
+/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+/// hasTypeLoc(loc(asString("int")))))))
+/// matches `A<int> a`.
+AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
+ internal::Matcher<TemplateArgumentLoc>, 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<typename T, typename U> class A {};
+/// A<double, int> b;
+/// A<int, double> c;
+/// \endcode
+/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+/// hasTypeLoc(loc(asString("double")))))))
+/// matches `A<double, int> b`, but not `A<int, double> c`.
+AST_POLYMORPHIC_MATCHER_P2(
+ hasTemplateArgumentLoc,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc),
+ unsigned, Index, internal::Matcher<TemplateArgumentLoc>, 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<TypeLoc, ElaboratedTypeLoc>
+ elaboratedTypeLoc;
+
+/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching
+/// `InnerMatcher`.
+///
+/// Given
+/// \code
+/// template <typename T>
+/// class C {};
+/// class C<int> 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<TypeLoc>,
+ 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
index a6b21d99bdc41..488f9d80d604d 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -2308,6 +2308,26 @@ std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex,
llvm::Regex::RegexFlags Flags,
StringRef MatcherID);
+inline bool
+MatchTemplateArgLocAt(const DeclRefExpr &Node, unsigned int Index,
+ internal::Matcher<TemplateArgumentLoc> InnerMatcher,
+ internal::ASTMatchFinder *Finder,
+ internal::BoundNodesTreeBuilder *Builder) {
+ llvm::ArrayRef<TemplateArgumentLoc> 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<TemplateArgumentLoc> 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
index 1134402dc06ca..12e3c488d61a3 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -771,6 +771,19 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTemplateParmDecl>
const internal::VariadicAllOfMatcher<QualType> qualType;
const internal::VariadicAllOfMatcher<Type> type;
const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
+
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, QualifiedTypeLoc>
+ qualifiedTypeLoc;
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, PointerTypeLoc>
+ pointerTypeLoc;
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, ReferenceTypeLoc>
+ referenceTypeLoc;
+const internal::VariadicDynCastAllOfMatcher<TypeLoc,
+ TemplateSpecializationTypeLoc>
+ templateSpecializationTypeLoc;
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>
+ elaboratedTypeLoc;
+
const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 64d6b79e4af82..7b52a083f54c9 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -226,6 +226,7 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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 @@ RegistryMaps::RegistryMaps() {
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
index ed5f9089de17d..92fd5306deb16 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2078,6 +2078,165 @@ TEST_P(ASTMatchersTest, TypeAliasTemplateDecl) {
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 <typename T> class C {}; template class C<int>;",
+ classTemplateSpecializationDecl(
+ hasName("C"), hasTypeLoc(templateSpecializationTypeLoc()))));
+}
+
+TEST_P(ASTMatchersTest,
+ TemplateSpecializationTypeLocTest_BindsToVarDeclTemplateSpecialization) {
+ if (!GetParam().isCXX()) {
+ return;
+ }
+ EXPECT_TRUE(matches(
+ "template <typename T> class C {}; C<char> 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
index 8592898544b6d..7746c82f7ec52 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -5764,5 +5764,454 @@ TEST(CXXNewExpr, PlacementArgs) {
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<typename T> class A {}; A<int> a;",
+ varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc(
+ hasAnyTemplateArgumentLoc(hasTypeLoc(
+ loc(asString("int")))))))));
+}
+
+TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) {
+ EXPECT_TRUE(
+ matches("template<typename T> class A {}; A<double> a;",
+ varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc(
+ hasAnyTemplateArgumentLoc(hasTypeLoc(
+ loc(asString("double")))))))));
+}
+
+TEST(HasAnyTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; template<> class A<int> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(
+ hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int")))))))));
+}
+
+TEST(HasAnyTemplateArgumentLoc,
+ BindsToExplicitSpecializationWithDoubleArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; template<> class A<double> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+ hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
+ auto code = R"(
+ template<typename T, typename U> class A {};
+ template<> class A<double, int> {};
+ )";
+ 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<typename T> class A {}; A<int> a;",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+ hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasAnyTemplateArgumentLoc,
+ DoesNotBindToExplicitSpecializationWithIntArgument) {
+ EXPECT_TRUE(notMatches(
+ "template<typename T> class A {}; template<> class A<int> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+ hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToSpecializationWithIntArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; A<int> a;",
+ varDecl(hasName("a"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("int")))))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; A<double> a;",
+ varDecl(hasName("a"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; template<> class A<int> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(
+ hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int")))))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithDoubleArgument) {
+ EXPECT_TRUE(matches(
+ "template<typename T> class A {}; template<> class A<double> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
+ auto code = R"(
+ template<typename T, typename U> class A {};
+ template<> class A<double, int> {};
+ )";
+ 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<typename T> class A {}; A<int> a;",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasTemplateArgumentLoc,
+ DoesNotBindToExplicitSpecializationWithIntArgument) {
+ EXPECT_TRUE(notMatches(
+ "template<typename T> class A {}; template<> class A<int> {};",
+ classTemplateSpecializationDecl(
+ hasName("A"),
+ hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("double")))))))));
+}
+
+TEST(HasTemplateArgumentLoc,
+ DoesNotBindToSpecializationWithMisplacedArguments) {
+ auto code = R"(
+ template<typename T, typename U> class A {};
+ template<> class A<double, int> {};
+ )";
+ 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<typename T, typename U> class A {};
+ template<> class A<double, int> {};
+ )";
+ 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<typename T> T f(T t) { return t; }
+ int g() { int i = f<int>(3); return i; }
+ )",
+ declRefExpr(to(functionDecl(hasName("f"))),
+ hasTemplateArgumentLoc(
+ 0, hasTypeLoc(loc(asString("int")))))));
+}
+
+TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithDoubleArgument) {
+ EXPECT_TRUE(matches(
+ R"(
+ template<typename T> T f(T t) { return t; }
+ double g() { double i = f<double>(3.0); return i; }
+ )",
+ declRefExpr(
+ to(functionDecl(hasName("f"))),
+ hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double")))))));
+}
+
+TEST(HasTemplateArgumentLoc, DoesNotBindToDeclRefExprWithDoubleArgument) {
+ EXPECT_TRUE(notMatches(
+ R"(
+ template<typename T> T f(T t) { return t; }
+ double g() { double i = f<double>(3.0); return i; }
+ )",
+ declRefExpr(
+ to(functionDecl(hasName("f"))),
+ hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int")))))));
+}
+
+TEST(HasNamedTypeLoc, BindsToElaboratedObjectDeclaration) {
+ EXPECT_TRUE(matches(
+ R"(
+ template <typename T>
+ class C {};
+ class C<int> c;
+ )",
+ varDecl(hasName("c"),
+ hasTypeLoc(elaboratedTypeLoc(
+ hasNamedTypeLoc(templateSpecializationTypeLoc(
+ hasAnyTemplateArgumentLoc(templateArgumentLoc()))))))));
+}
+
+TEST(HasNamedTypeLoc, DoesNotBindToNonElaboratedObjectDeclaration) {
+ EXPECT_TRUE(notMatches(
+ R"(
+ template <typename T>
+ class C {};
+ C<int> c;
+ )",
+ varDecl(hasName("c"),
+ hasTypeLoc(elaboratedTypeLoc(
+ hasNamedTypeLoc(templateSpecializationTypeLoc(
+ hasAnyTemplateArgumentLoc(templateArgumentLoc()))))))));
+}
+
} // namespace ast_matchers
} // namespace clang
More information about the cfe-commits
mailing list