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 @@ <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 different syntaxes (including @@ -600,6 +591,15 @@ </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 @@ 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 @@ </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 @@ </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 @@ <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 different parts of the the statement are expanded from different +if different parts of the statement are expanded from different appearances of the macro. </pre></td></tr> @@ -5232,7 +5300,7 @@ <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 different parts of the the statement are expanded from different +if different parts of the statement are expanded from different appearances of the macro. </pre></td></tr> @@ -6060,6 +6128,16 @@ </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 @@ </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 @@ } } -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 @@ </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 @@ </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 @@ </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 @@ </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 @@ </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 @@ </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 @@ </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 --- 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<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 --- 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<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 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -771,6 +771,19 @@ 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 --- 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 <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 --- 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<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