[clang] 53e92e4 - Reland: [clang][test] add testing for the AST matcher reference (#112168)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 15 01:51:22 PST 2024
Author: Julian Schmidt
Date: 2024-11-15T10:51:15+01:00
New Revision: 53e92e48d0c03a2475e8517dd4c28968d84fc217
URL: https://github.com/llvm/llvm-project/commit/53e92e48d0c03a2475e8517dd4c28968d84fc217
DIFF: https://github.com/llvm/llvm-project/commit/53e92e48d0c03a2475e8517dd4c28968d84fc217.diff
LOG: Reland: [clang][test] add testing for the AST matcher reference (#112168)
## Problem Statement
Previously, the examples in the AST matcher reference, which gets
generated by the Doxygen comments in `ASTMatchers.h`, were untested and
best effort.
Some of the matchers had no or wrong examples of how to use the matcher.
## Solution
This patch introduces a simple DSL around Doxygen commands to enable
testing the AST matcher documentation in a way that should be relatively
easy to use.
In `ASTMatchers.h`, most matchers are documented with a Doxygen comment.
Most of these also have a code example that aims to show what the
matcher will match, given a matcher somewhere in the documentation text.
The way that the documentation is tested, is by using Doxygen's alias
feature to declare custom aliases. These aliases forward to
`<tt>text</tt>` (which is what Doxygen's `\c` does, but for multiple
words). Using the Doxygen aliases is the obvious choice, because there
are (now) four consumers:
- people reading the header/using signature help
- the Doxygen generated documentation
- the generated HTML AST matcher reference
- (new) the generated matcher tests
This patch rewrites/extends the documentation such that all matchers
have a documented example.
The new `generate_ast_matcher_doc_tests.py` script will warn on any
undocumented matchers (but not on matchers without a Doxygen comment)
and provides diagnostics and statistics about the matchers.
The current statistics emitted by the parser are:
```text
Statistics:
doxygen_blocks : 519
missing_tests : 10
skipped_objc : 42
code_snippets : 503
matches : 820
matchers : 580
tested_matchers : 574
none_type_matchers : 6
```
The tests are generated during building, and the script will only print
something if it found an issue with the specified tests (e.g., missing
tests).
## Description
DSL for generating the tests from documentation.
TLDR:
```
\header{a.h}
\endheader <- zero or more header
\code
int a = 42;
\endcode
\compile_args{-std=c++,c23-or-later} <- optional, the std flag supports std ranges and
whole languages
\matcher{expr()} <- one or more matchers in succession
\match{42} <- one or more matches in succession
\matcher{varDecl()} <- new matcher resets the context, the above
\match will not count for this new
matcher(-group)
\match{int a = 42} <- only applies to the previous matcher (not to the
previous case)
```
The above block can be repeated inside a Doxygen command for multiple
code examples for a single matcher.
The test generation script will only look for these annotations and
ignore anything else like `\c` or the sentences where these annotations
are embedded into: `The matcher \matcher{expr()} matches the number
\match{42}.`.
### Language Grammar
[] denotes an optional, and <> denotes user-input
```
compile_args j:= \compile_args{[<compile_arg>;]<compile_arg>}
matcher_tag_key ::= type
match_tag_key ::= type || std || count || sub
matcher_tags ::= [matcher_tag_key=<value>;]matcher_tag_key=<value>
match_tags ::= [match_tag_key=<value>;]match_tag_key=<value>
matcher ::= \matcher{[matcher_tags$]<matcher>}
matchers ::= [matcher] matcher
match ::= \match{[match_tags$]<match>}
matches ::= [match] match
case ::= matchers matches
cases ::= [case] case
header-block ::= \header{<name>} <code> \endheader
code-block ::= \code <code> \endcode
testcase ::= code-block [compile_args] cases
```
### Language Standard Versions
The 'std' tag and '\compile_args' support specifying a specific language
version, a whole language and all of its versions, and thresholds
(implies ranges). Multiple arguments are passed with a ',' separator.
For a language and version to execute a tested matcher, it has to match
the specified '\compile_args' for the code, and the 'std' tag for the
matcher. Predicates for the 'std' compiler flag are used with
disjunction between languages (e.g. 'c || c++') and conjunction for all
predicates specific to each language (e.g. 'c++11-or-later &&
c++23-or-earlier').
Examples:
- `c` all available versions of C
- `c++11` only C++11
- `c++11-or-later` C++11 or later
- `c++11-or-earlier` C++11 or earlier
- `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and
23 (inclusive)
- `c++11-23,c` same as above
### Tags
#### `type`:
**Match types** are used to select where the string that is used to
check if a node matches comes from.
Available: `code`, `name`, `typestr`, `typeofstr`. The default is
`code`.
- `code`: Forwards to `tooling::fixit::getText(...)` and should be the
preferred way to show what matches.
- `name`: Casts the match to a `NamedDecl` and returns the result of
`getNameAsString`. Useful when the matched AST node is not easy to spell
out (`code` type), e.g., namespaces or classes with many members.
- `typestr`: Returns the result of `QualType::getAsString` for the type
derived from `Type` (otherwise, if it is derived from `Decl`, recurses
with `Node->getTypeForDecl()`)
**Matcher types** are used to mark matchers as sub-matcher with 'sub' or
as deactivated using 'none'. Testing sub-matcher is not implemented.
#### `count`:
Specifying a 'count=n' on a match will result in a test that requires
that the specified match will be matched n times. Default is 1.
#### `std`:
A match allows specifying if it matches only in specific language
versions. This may be needed when the AST differs between language
versions.
#### `sub`:
The `sub` tag on a `\match` will indicate that the match is for a node
of a bound sub-matcher.
E.g., `\matcher{expr(expr().bind("inner"))}` has a sub-matcher that
binds to `inner`, which is the value for the `sub` tag of the expected
match for the sub-matcher `\match{sub=inner$...}`. Currently,
sub-matchers are not tested in any way.
### What if ...?
#### ... I want to add a matcher?
Add a Doxygen comment to the matcher with a code example, corresponding
matchers and matches, that shows what the matcher is supposed to do.
Specify the compile arguments/supported languages if required, and run
`ninja check-clang-unit` to test the documentation.
#### ... the example I wrote is wrong?
The test-failure output of the generated test file will provide
information about
- where the generated test file is located
- which line in `ASTMatcher.h` the example is from
- which matches were: found, not-(yet)-found, expected
- in case of an unexpected match: what the node looks like using the
different `type`s
- the language version and if the test ran with a windows `-target` flag
(also in failure summary)
#### ... I don't adhere to the required order of the syntax?
The script will diagnose any found issues, such as `matcher is missing
an example` with a `file:line:` prefix,
which should provide enough information about the issue.
#### ... the script diagnoses a false-positive issue with a Doxygen
comment?
It hopefully shouldn't, but if you, e.g., added some non-matcher code
and documented it with Doxygen, then the script will consider that as a
matcher documentation. As a result, the script will print that it
detected a mismatch between the actual and the expected number of
failures. If the diagnostic truly is a false-positive, change the
`expected_failure_statistics` at the top of the
`generate_ast_matcher_doc_tests.py` file.
Fixes #57607
Fixes #63748
Added:
clang/utils/generate_ast_matcher_doc_tests.py
Modified:
clang/docs/LibASTMatchersReference.html
clang/docs/ReleaseNotes.rst
clang/docs/doxygen.cfg.in
clang/docs/tools/dump_ast_matchers.py
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/unittests/ASTMatchers/ASTMatchersTest.h
clang/unittests/ASTMatchers/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index c6307954d7f1bb..99917ccff52604 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -586,28 +586,36 @@ <h2 id="decl-matchers">Node Matchers</h2>
#pragma omp declare simd
int min();
-attr()
- matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line.
+
+The matcher attr()
+matches nodiscard, nonnull, noinline, and
+declare simd.
</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.
+Given
class B {};
class C : public virtual B {};
+
+The matcher cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))
+matches C.
</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.
-Examples matches i(42).
+Given
class C {
C() : i(42) {}
int i;
};
+
+The matcher cxxCtorInitializer()
+matches i(42).
</pre></td></tr>
@@ -619,17 +627,22 @@ <h2 id="decl-matchers">Node Matchers</h2>
public:
int a;
};
-accessSpecDecl()
- matches 'public:'
+
+The matcher accessSpecDecl()
+matches public:.
</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('bindingDecl0')"><a name="bindingDecl0Anchor">bindingDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="bindingDecl0"><pre>Matches binding declarations
-Example matches foo and bar
-(matcher = bindingDecl()
- auto [foo, bar] = std::make_pair{42, 42};
+Given
+ struct pair { int x; int y; };
+ pair make(int, int);
+ auto [foo, bar] = make(42, 42);
+
+The matcher bindingDecl()
+matches foo and bar.
</pre></td></tr>
@@ -642,14 +655,18 @@ <h2 id="decl-matchers">Node Matchers</h2>
myFunc(^(int p) {
printf("%d", p);
})
+
</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('classTemplateDecl0')"><a name="classTemplateDecl0Anchor">classTemplateDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="classTemplateDecl0"><pre>Matches C++ class template declarations.
-Example matches Z
+Given
template<class T> class Z {};
+
+The matcher classTemplateDecl()
+matches Z.
</pre></td></tr>
@@ -660,13 +677,14 @@ <h2 id="decl-matchers">Node Matchers</h2>
template<class T1, class T2, int I>
class A {};
- template<class T, int I>
- class A<T, T*, I> {};
+ template<class T, int I> class A<T, T*, I> {};
template<>
class A<int, int, 1> {};
-classTemplatePartialSpecializationDecl()
- matches the specialization A<T,T*,I> but not A<int,int,1>
+
+The matcher classTemplatePartialSpecializationDecl()
+matches template<class T, int I> class A<T, T*, I> {},
+but does not match A<int, int, 1>.
</pre></td></tr>
@@ -677,87 +695,128 @@ <h2 id="decl-matchers">Node Matchers</h2>
template<typename T> class A {};
template<> class A<double> {};
A<int> a;
-classTemplateSpecializationDecl()
- matches the specializations A<int> and A<double>
+
+The matcher classTemplateSpecializationDecl()
+matches class A<int>
+and class A<double>.
</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('conceptDecl0')"><a name="conceptDecl0Anchor">conceptDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConceptDecl.html">ConceptDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="conceptDecl0"><pre>Matches concept declarations.
-Example matches integral
- template<typename T>
- concept integral = std::is_integral_v<T>;
+Given
+ template<typename T> concept my_concept = true;
+
+
+The matcher conceptDecl()
+matches template<typename T>
+concept my_concept = true.
</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('cxxConstructorDecl0')"><a name="cxxConstructorDecl0Anchor">cxxConstructorDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxConstructorDecl0"><pre>Matches C++ constructor declarations.
-Example matches Foo::Foo() and Foo::Foo(int)
+Given
class Foo {
public:
Foo();
Foo(int);
int DoSomething();
};
+
+ struct Bar {};
+
+
+The matcher cxxConstructorDecl()
+matches Foo() and Foo(int).
</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('cxxConversionDecl0')"><a name="cxxConversionDecl0Anchor">cxxConversionDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxConversionDecl0"><pre>Matches conversion operator declarations.
-Example matches the operator.
+Given
class X { operator int() const; };
+
+
+The matcher cxxConversionDecl()
+matches operator int() const.
</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('cxxDeductionGuideDecl0')"><a name="cxxDeductionGuideDecl0Anchor">cxxDeductionGuideDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDeductionGuideDecl.html">CXXDeductionGuideDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxDeductionGuideDecl0"><pre>Matches user-defined and implicitly generated deduction guide.
-Example matches the deduction guide.
+Given
template<typename T>
- class X { X(int) };
+ class X { X(int); };
X(int) -> X<int>;
+
+
+The matcher cxxDeductionGuideDecl()
+matches the written deduction guide
+auto (int) -> X<int>,
+the implicit copy deduction guide auto (int) -> X<T>
+and the implicitly declared deduction guide
+auto (X<T>) -> X<T>.
</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('cxxDestructorDecl0')"><a name="cxxDestructorDecl0Anchor">cxxDestructorDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDestructorDecl.html">CXXDestructorDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxDestructorDecl0"><pre>Matches explicit C++ destructor declarations.
-Example matches Foo::~Foo()
+Given
class Foo {
public:
virtual ~Foo();
};
+
+ struct Bar {};
+
+
+The matcher cxxDestructorDecl()
+matches virtual ~Foo().
</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('cxxMethodDecl0')"><a name="cxxMethodDecl0Anchor">cxxMethodDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxMethodDecl0"><pre>Matches method declarations.
-Example matches y
+Given
class X { void y(); };
+
+
+The matcher cxxMethodDecl()
+matches void y().
</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('cxxRecordDecl0')"><a name="cxxRecordDecl0Anchor">cxxRecordDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxRecordDecl0"><pre>Matches C++ class declarations.
-Example matches X, Z
+Given
class X;
template<class T> class Z {};
+
+The matcher cxxRecordDecl()
+matches X and Z.
</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('decl0')"><a name="decl0Anchor">decl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="decl0"><pre>Matches declarations.
-Examples matches X, C, and the friend declaration inside C;
+Given
void X();
class C {
- friend X;
+ friend void X();
};
+
+The matcher decl()
+matches void X(), C
+and friend void X().
</pre></td></tr>
@@ -767,40 +826,49 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
class X { int y; };
-declaratorDecl()
- matches int y.
+
+The matcher declaratorDecl()
+matches int y.
</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('decompositionDecl0')"><a name="decompositionDecl0Anchor">decompositionDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecompositionDecl.html">DecompositionDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="decompositionDecl0"><pre>Matches decomposition-declarations.
-Examples matches the declaration node with foo and bar, but not
-number.
-(matcher = declStmt(has(decompositionDecl())))
-
+Given
+ struct pair { int x; int y; };
+ pair make(int, int);
int number = 42;
- auto [foo, bar] = std::make_pair{42, 42};
+ auto [foo, bar] = make(42, 42);
+
+The matcher decompositionDecl()
+matches auto [foo, bar] = make(42, 42),
+but does not match number.
</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('enumConstantDecl0')"><a name="enumConstantDecl0Anchor">enumConstantDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1EnumConstantDecl.html">EnumConstantDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="enumConstantDecl0"><pre>Matches enum constants.
-Example matches A, B, C
+Given
enum X {
A, B, C
};
+The matcher enumConstantDecl()
+matches A, B and C.
</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('enumDecl0')"><a name="enumDecl0Anchor">enumDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1EnumDecl.html">EnumDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="enumDecl0"><pre>Matches enum declarations.
-Example matches X
+Given
enum X {
A, B, C
};
+
+The matcher enumDecl()
+matches the enum X.
</pre></td></tr>
@@ -808,9 +876,14 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.
Given
- class X { int m; };
-fieldDecl()
- matches 'm'.
+ int a;
+ struct Foo {
+ int x;
+ };
+ void bar(int val);
+
+The matcher fieldDecl()
+matches int x.
</pre></td></tr>
@@ -819,16 +892,20 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
class X { friend void foo(); };
-friendDecl()
- matches 'friend void foo()'.
+
+The matcher friendDecl()
+matches friend void foo().
</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('functionDecl0')"><a name="functionDecl0Anchor">functionDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="functionDecl0"><pre>Matches function declarations.
-Example matches f
+Given
void f();
+
+The matcher functionDecl()
+matches void f().
</pre></td></tr>
@@ -837,6 +914,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches f
template<class T> void f(T t) {}
+
+
+The matcher functionTemplateDecl()
+matches template<class T> void f(T t) {}.
</pre></td></tr>
@@ -845,8 +926,8 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
struct X { struct { int a; }; };
-indirectFieldDecl()
- matches 'a'.
+The matcher indirectFieldDecl()
+matches a.
</pre></td></tr>
@@ -854,10 +935,13 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="labelDecl0"><pre>Matches a declaration of label.
Given
- goto FOO;
- FOO: bar();
-labelDecl()
- matches 'FOO:'
+ void bar();
+ void foo() {
+ goto FOO;
+ FOO: bar();
+ }
+The matcher labelDecl()
+matches FOO: bar().
</pre></td></tr>
@@ -866,8 +950,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
extern "C" {}
-linkageSpecDecl()
- matches "extern "C" {}"
+
+The matcher linkageSpecDecl()
+matches extern "C" {}.
</pre></td></tr>
@@ -875,12 +960,18 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="namedDecl0"><pre>Matches a declaration of anything that could have a name.
Example matches X, S, the anonymous union type, i, and U;
+Given
typedef int X;
struct S {
union {
int i;
} U;
};
+The matcher namedDecl()
+matches typedef int X, S, int i
+ and U,
+with S matching twice in C++.
+Once for the injected class name and once for the declaration itself.
</pre></td></tr>
@@ -890,8 +981,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
namespace test {}
namespace alias = ::test;
-namespaceAliasDecl()
- matches "namespace alias" but not "namespace test"
+
+The matcher namespaceAliasDecl()
+matches alias,
+but does not match test.
</pre></td></tr>
@@ -901,8 +994,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
namespace {}
namespace test {}
-namespaceDecl()
- matches "namespace {}" and "namespace test {}"
+
+The matcher namespaceDecl()
+matches namespace {} and namespace test {}.
</pre></td></tr>
@@ -911,8 +1005,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T, int N> struct C {};
-nonTypeTemplateParmDecl()
- matches 'N', but not 'T'.
+
+The matcher nonTypeTemplateParmDecl()
+matches int N,
+but does not match typename T.
</pre></td></tr>
@@ -922,6 +1018,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches Foo (Additions)
@interface Foo (Additions)
@end
+
</pre></td></tr>
@@ -931,6 +1028,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches Foo (Additions)
@implementation Foo (Additions)
@end
+
</pre></td></tr>
@@ -940,6 +1038,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches Foo
@implementation Foo
@end
+
</pre></td></tr>
@@ -949,6 +1048,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches Foo
@interface Foo
@end
+
</pre></td></tr>
@@ -960,6 +1060,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
BOOL _enabled;
}
@end
+
</pre></td></tr>
@@ -974,6 +1075,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
@implementation Foo
- (void)method {}
@end
+
</pre></td></tr>
@@ -984,6 +1086,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
@interface Foo
@property BOOL enabled;
@end
+
</pre></td></tr>
@@ -993,6 +1096,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches FooDelegate
@protocol FooDelegate
@end
+
</pre></td></tr>
@@ -1001,48 +1105,58 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
void f(int x);
-parmVarDecl()
- matches int x.
+The matcher parmVarDecl()
+matches int 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('recordDecl0')"><a name="recordDecl0Anchor">recordDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="recordDecl0"><pre>Matches class, struct, and union declarations.
-Example matches X, Z, U, and S
+Given
class X;
template<class T> class Z {};
struct S {};
union U {};
+
+The matcher recordDecl()
+matches X, Z,
+S and U.
</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('staticAssertDecl0')"><a name="staticAssertDecl0Anchor">staticAssertDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StaticAssertDecl.html">StaticAssertDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="staticAssertDecl0"><pre>Matches a C++ static_assert declaration.
-Example:
- staticAssertDecl()
-matches
- static_assert(sizeof(S) == sizeof(int))
-in
+Given
struct S {
int x;
};
static_assert(sizeof(S) == sizeof(int));
+
+
+The matcher staticAssertDecl()
+matches static_assert(sizeof(S) == sizeof(int)).
</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('tagDecl0')"><a name="tagDecl0Anchor">tagDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="tagDecl0"><pre>Matches tag declarations.
-Example matches X, Z, U, S, E
+Given
class X;
template<class T> class Z {};
struct S {};
union U {};
- enum E {
- A, B, C
- };
+ enum E { A, B, C };
+
+
+The matcher tagDecl()
+matches class X, class Z {}, the injected class name
+class Z, struct S {},
+the injected class name struct S, union U {},
+the injected class name union U
+and enum E { A, B, C }.
</pre></td></tr>
@@ -1051,8 +1165,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <template <typename> class Z, int N> struct C {};
-templateTypeParmDecl()
- matches 'Z', but not 'N'.
+
+The matcher templateTemplateParmDecl()
+matches template <typename> class Z,
+but does not match int N.
</pre></td></tr>
@@ -1061,8 +1177,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T, int N> struct C {};
-templateTypeParmDecl()
- matches 'T', but not 'N'.
+
+The matcher templateTypeParmDecl()
+matches typename T,
+but does not int N.
</pre></td></tr>
@@ -1072,10 +1190,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
int X;
namespace NS {
- int Y;
+ int Y;
} // namespace NS
-decl(hasDeclContext(translationUnitDecl()))
- matches "int X", but not "int Y".
+
+The matcher namedDecl(hasDeclContext(translationUnitDecl()))
+matches X and NS,
+but does not match Y.
</pre></td></tr>
@@ -1085,17 +1205,22 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
typedef int X;
using Y = int;
-typeAliasDecl()
- matches "using Y = int", but not "typedef int X"
+
+The matcher typeAliasDecl()
+matches using Y = int,
+but does not match typedef int 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('typeAliasTemplateDecl0')"><a name="typeAliasTemplateDecl0Anchor">typeAliasTemplateDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeAliasTemplateDecl.html">TypeAliasTemplateDecl</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="typeAliasTemplateDecl0"><pre>Matches type alias template declarations.
-typeAliasTemplateDecl() matches
- template <typename T>
- using Y = X<T>;
+Given
+ template <typename T> struct X {};
+ template <typename T> using Y = X<T>;
+
+The matcher typeAliasTemplateDecl()
+matches template <typename T> using Y = X<T>.
</pre></td></tr>
@@ -1105,8 +1230,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
typedef int X;
using Y = int;
-typedefDecl()
- matches "typedef int X", but not "using Y = int"
+
+The matcher typedefDecl()
+matches typedef int X,
+but does not match using Y = int.
</pre></td></tr>
@@ -1116,8 +1243,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
typedef int X;
using Y = int;
-typedefNameDecl()
- matches "typedef int X" and "using Y = int"
+
+The matcher typedefNameDecl()
+matches typedef int X and using Y = int.
</pre></td></tr>
@@ -1133,8 +1261,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
struct S : private Base<T> {
using typename Base<T>::Foo;
};
-unresolvedUsingTypenameDecl()
- matches using Base<T>::Foo </pre></td></tr>
+
+The matcher unresolvedUsingTypenameDecl()
+ matches using typename Base<T>::Foo
+</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('unresolvedUsingValueDecl0')"><a name="unresolvedUsingValueDecl0Anchor">unresolvedUsingValueDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingValueDecl.html">UnresolvedUsingValueDecl</a>>...</td></tr>
@@ -1145,8 +1275,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
class C : private X {
using X::x;
};
-unresolvedUsingValueDecl()
- matches using X::x </pre></td></tr>
+
+The matcher unresolvedUsingValueDecl()
+ matches using 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('usingDecl0')"><a name="usingDecl0Anchor">usingDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>>...</td></tr>
@@ -1155,8 +1287,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
namespace X { int x; }
using X::x;
-usingDecl()
- matches using X::x </pre></td></tr>
+
+The matcher usingDecl()
+ matches using 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('usingDirectiveDecl0')"><a name="usingDirectiveDecl0Anchor">usingDirectiveDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingDirectiveDecl.html">UsingDirectiveDecl</a>>...</td></tr>
@@ -1165,26 +1299,34 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
namespace X { int x; }
using namespace X;
-usingDirectiveDecl()
- matches using namespace X </pre></td></tr>
+
+The matcher usingDirectiveDecl()
+ 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 {...}; }
+ namespace X { enum x { val1, val2 }; }
using enum X::x;
-usingEnumDecl()
- matches using enum X::x </pre></td></tr>
+
+The matcher 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.
-Example matches A, B, C and F
+Given
enum X { A, B, C };
void F();
+ int V = 0;
+The matcher valueDecl()
+matches A, B, C, void F()
+and int V = 0.
</pre></td></tr>
@@ -1196,6 +1338,13 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches a
int a;
+ struct Foo {
+ int x;
+ };
+ void bar(int val);
+
+The matcher varDecl()
+matches int a and int val, but not int x.
</pre></td></tr>
@@ -1208,13 +1357,29 @@ <h2 id="decl-matchers">Node Matchers</h2>
auto f = [x](){};
auto g = [x = 1](){};
}
-In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`,
-`lambdaCapture()` matches `x` and `x=1`.
+
+The matcher
+lambdaExpr(hasAnyCapture(lambdaCapture().bind("capture"))),
+matches [x](){} and [x = 1](){},
+with lambdaCapture() matching
+x and x = 1.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('nestedNameSpecifierLoc0')"><a name="nestedNameSpecifierLoc0Anchor">nestedNameSpecifierLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="nestedNameSpecifierLoc0"><pre>Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
+
+Given
+ namespace ns {
+ struct A { static void f(); };
+ void A::f() {}
+ void g() { A::f(); }
+ }
+ ns::A a;
+
+
+The matcher nestedNameSpecifierLoc() matches
+A:: twice, and ns:: once.
</pre></td></tr>
@@ -1228,8 +1393,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
void g() { A::f(); }
}
ns::A a;
-nestedNameSpecifier()
- matches "ns::" and both "A::"
+
+The matcher nestedNameSpecifier()
+matches ns and both A
</pre></td></tr>
@@ -1237,20 +1403,38 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="ompDefaultClause0"><pre>Matches OpenMP ``default`` clause.
Given
+ void foo() {
+ #pragma omp parallel default(none)
+ ;
+ #pragma omp parallel default(shared)
+ ;
+ #pragma omp parallel default(private)
+ ;
+ #pragma omp parallel default(firstprivate)
+ ;
+ #pragma omp parallel
+ ;
+ }
- #pragma omp parallel default(none)
- #pragma omp parallel default(shared)
- #pragma omp parallel default(private)
- #pragma omp parallel default(firstprivate)
- #pragma omp parallel
-``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``,
-`` default(private)`` and ``default(firstprivate)``
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause())) matches
+#pragma omp parallel default(none),
+#pragma omp parallel default(shared),
+#pragma omp parallel default(private) and
+#pragma omp parallel default(firstprivate).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="qualType0"><pre>Matches QualTypes in the clang AST.
+
+Given
+ int a = 0;
+ const int b = 1;
+
+The matcher varDecl(hasType(qualType(isConstQualified())))
+matches const int b = 1, but not int a = 0.
</pre></td></tr>
@@ -1258,34 +1442,39 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="addrLabelExpr0"><pre>Matches address of label statements (GNU extension).
Given
+void bar();
+void foo() {
FOO: bar();
void *ptr = &&FOO;
- goto *bar;
-addrLabelExpr()
- matches '&&FOO'
+ goto *ptr;
+}
+The matcher addrLabelExpr()
+matches &&FOO
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('arrayInitIndexExpr0')"><a name="arrayInitIndexExpr0Anchor">arrayInitIndexExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArrayInitIndexExpr.html">ArrayInitIndexExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="arrayInitIndexExpr0"><pre>The arrayInitIndexExpr consists of two subexpressions: a common expression
-(the source array) that is evaluated once up-front, and a per-element initializer
-that runs once for each array element. Within the per-element initializer,
-the current index may be obtained via an ArrayInitIndexExpr.
+(the source array) that is evaluated once up-front, and a per-element
+initializer that runs once for each array element. Within the per-element
+initializer, the current index may be obtained via an ArrayInitIndexExpr.
Given
- void testStructBinding() {
+ void testStructuredBinding() {
int a[2] = {1, 2};
auto [x, y] = a;
}
-arrayInitIndexExpr() matches the array index that implicitly iterates
-over the array `a` to copy each element to the anonymous array
-that backs the structured binding `[x, y]` elements of which are
-referred to by their aliases `x` and `y`.
+
+
+The matcher arrayInitIndexExpr() matches the array index
+that implicitly iterates over the array `a` to copy each element to the
+anonymous array that backs the structured binding.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('arrayInitLoopExpr0')"><a name="arrayInitLoopExpr0Anchor">arrayInitLoopExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArrayInitLoopExpr.html">ArrayInitLoopExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="arrayInitLoopExpr0"><pre>Matches a loop initializing the elements of an array in a number of contexts:
+<tr><td colspan="4" class="doc" id="arrayInitLoopExpr0"><pre>Matches a loop initializing the elements of an array in a number of
+contexts:
* in the implicit copy/move constructor for a class with an array member
* when a lambda-expression captures an array by value
* when a decomposition declaration decomposes an array
@@ -1293,13 +1482,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
void testLambdaCapture() {
int a[10];
- auto Lam1 = [a]() {
- return;
- };
+ [a]() {};
}
-arrayInitLoopExpr() matches the implicit loop that initializes each element of
-the implicit array field inside the lambda object, that represents the array `a`
-captured by value.
+
+The matcher arrayInitLoopExpr() matches the implicit loop that
+initializes each element of the implicit array field inside the lambda
+object, that represents the array a captured by value.
</pre></td></tr>
@@ -1307,26 +1495,34 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
Given
- int i = a[1];
-arraySubscriptExpr()
- matches "a[1]"
+ void foo() {
+ int a[2] = {0, 1};
+ int i = a[1];
+ }
+The matcher arraySubscriptExpr()
+matches a[1].
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('asmStmt0')"><a name="asmStmt0Anchor">asmStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AsmStmt.html">AsmStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="asmStmt0"><pre>Matches asm statements.
+void foo() {
int i = 100;
- __asm("mov al, 2");
-asmStmt()
- matches '__asm("mov al, 2")'
+ __asm("mov %al, 2");
+}
+The matcher asmStmt()
+matches __asm("mov %al, 2")
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('atomicExpr0')"><a name="atomicExpr0Anchor">atomicExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AtomicExpr.html">AtomicExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="atomicExpr0"><pre>Matches atomic builtins.
-Example matches __atomic_load_n(ptr, 1)
+
+Given
void foo() { int *ptr; __atomic_load_n(ptr, 1); }
+
+The matcher atomicExpr() matches __atomic_load_n(ptr, 1).
</pre></td></tr>
@@ -1337,24 +1533,35 @@ <h2 id="decl-matchers">Node Matchers</h2>
@autoreleasepool {
int x = 0;
}
-autoreleasePoolStmt(stmt()) matches the declaration of "x"
-inside the autorelease pool.
+
+The matcher autoreleasePoolStmt(stmt()) matches the declaration of
+int x = 0 inside the autorelease pool.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryConditionalOperator0')"><a name="binaryConditionalOperator0Anchor">binaryConditionalOperator</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryConditionalOperator.html">BinaryConditionalOperator</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="binaryConditionalOperator0"><pre>Matches binary conditional operator expressions (GNU extension).
-Example matches a ?: b
- (a ?: b) + 42;
+Given
+ int f(int a, int b) {
+ return (a ?: b) + 42;
+ }
+
+The matcher binaryConditionalOperator() matches a ?: b.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
-Example matches a || b
- !(a || b)
+Given
+ void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+
+The matcher binaryOperator() matches a || b.
+
See also the binaryOperation() matcher for more-general matching.
</pre></td></tr>
@@ -1362,8 +1569,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('blockExpr0')"><a name="blockExpr0Anchor">blockExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockExpr.html">BlockExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="blockExpr0"><pre>Matches a reference to a block.
-Example: matches "^{}":
+Given
void f() { ^{}(); }
+
+
+The matcher blockExpr() matches ^{}.
</pre></td></tr>
@@ -1371,17 +1581,23 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="breakStmt0"><pre>Matches break statements.
Given
+void foo() {
while (true) { break; }
-breakStmt()
- matches 'break'
+}
+
+The matcher breakStmt()
+matches break
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cStyleCastExpr0')"><a name="cStyleCastExpr0Anchor">cStyleCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CStyleCastExpr.html">CStyleCastExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cStyleCastExpr0"><pre>Matches a C-style cast expression.
-Example: Matches (int) 2.2f in
+Given
int i = (int) 2.2f;
+
+The matcher cStyleCastExpr()
+matches (int) 2.2f.
</pre></td></tr>
@@ -1389,9 +1605,16 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
Example matches x.y() and y()
- X x;
- x.y();
- y();
+ struct X { void foo(); };
+ void bar();
+ void foobar() {
+ X x;
+ x.foo();
+ bar();
+ }
+
+The matcher callExpr()
+matches x.foo() and bar();
</pre></td></tr>
@@ -1399,22 +1622,41 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="caseStmt0"><pre>Matches case statements inside switch statements.
Given
+void foo(int a) {
switch(a) { case 42: break; default: break; }
-caseStmt()
- matches 'case 42:'.
+}
+The matcher caseStmt()
+matches case 42: break.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
-Example: castExpr() matches each of the following:
- (int) 3;
- const_cast<Expr *>(SubExpr);
- char c = 0;
-but does not match
- int i = (0);
- int k = 0;
+Given
+ struct S {};
+ const S* s;
+ S* s2 = const_cast<S*>(s);
+
+ const int val = 0;
+ char val0 = 1;
+ char val1 = (char)2;
+ char val2 = static_cast<char>(3);
+ int* val3 = reinterpret_cast<int*>(4);
+ char val4 = char(5);
+
+
+The matcher castExpr()
+matches
+const_cast<S*>(s) and the implicit l- to r-value cast for s,
+the implicit cast to char for the initializer 1,
+the c-style cast (char)2 and it's implicit cast to char
+(part of the c-style cast) 2,
+static_cast<char>(3) and it's implicit cast to char
+(part of the static_cast) 3,
+reinterpret_cast<int*>(4),
+char(5) and it's implicit cast to char
+(part of the functional cast) 5.
</pre></td></tr>
@@ -1424,14 +1666,24 @@ <h2 id="decl-matchers">Node Matchers</h2>
Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
though.
-Example matches 'a', L'a'
+Given
char ch = 'a';
wchar_t chw = L'a';
+
+
+The matcher characterLiteral() matches 'a' and
+L'a'.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('chooseExpr0')"><a name="chooseExpr0Anchor">chooseExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ChooseExpr.html">ChooseExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="chooseExpr0"><pre>Matches GNU __builtin_choose_expr.
+
+Given
+ void f() { (void)__builtin_choose_expr(1, 2, 3); }
+
+The matcher chooseExpr() matches
+__builtin_choose_expr(1, 2, 3).
</pre></td></tr>
@@ -1439,9 +1691,45 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="coawaitExpr0"><pre>Matches co_await expressions.
Given
- co_await 1;
-coawaitExpr()
- matches 'co_await 1'
+ namespace std {
+ template <typename T = void>
+ struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+ };
+
+ struct always_suspend {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+ };
+
+ template <typename T>
+ struct coroutine_traits {
+ using promise_type = T::promise_type;
+ };
+ } // namespace std
+
+ struct generator {
+ struct promise_type {
+ std::always_suspend yield_value(int&&);
+ std::always_suspend initial_suspend() const noexcept;
+ std::always_suspend final_suspend() const noexcept;
+ void return_void();
+ void unhandled_exception();
+ generator get_return_object();
+ };
+ };
+
+ std::always_suspend h();
+
+ generator g() { co_await h(); }
+
+The matcher
+coawaitExpr(has(callExpr(callee(functionDecl(hasName("h"))))))
+matches co_await h().
</pre></td></tr>
@@ -1449,35 +1737,48 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals
Example match: {1}, (1, 2)
- int array[4] = {1};
- vector int myvec = (vector int)(1, 2);
+ struct vector { int x; int y; };
+ struct vector myvec = (struct vector){ 1, 2 };
+
+The matcher compoundLiteralExpr()
+matches (struct vector){ 1, 2 }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundStmt0')"><a name="compoundStmt0Anchor">compoundStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="compoundStmt0"><pre>Matches compound statements.
-Example matches '{}' and '{{}}' in 'for (;;) {{}}'
- for (;;) {{}}
+Given
+void foo() { for (;;) {{}} }
+
+The matcher compoundStmt() matches
+{ for (;;) {{}} }, {{}} and {}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('conditionalOperator0')"><a name="conditionalOperator0Anchor">conditionalOperator</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="conditionalOperator0"><pre>Matches conditional operator expressions.
-Example matches a ? b : c
- (a ? b : c) + 42
+Given
+ int f(int a, int b, int c) {
+ return (a ? b : c) + 42;
+ }
+
+The matcher conditionalOperator() matches a ? b : c.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('constantExpr0')"><a name="constantExpr0Anchor">constantExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConstantExpr.html">ConstantExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="constantExpr0"><pre>Matches a constant expression wrapper.
-Example matches the constant in the case statement:
- (matcher = constantExpr())
- switch (a) {
- case 37: break;
+Given
+ void f(int a) {
+ switch (a) {
+ case 37: break;
+ }
}
+
+The matcher constantExpr() matches 37.
</pre></td></tr>
@@ -1485,14 +1786,26 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="continueStmt0"><pre>Matches continue statements.
Given
+void foo() {
while (true) { continue; }
-continueStmt()
- matches 'continue'
+}
+
+The matcher continueStmt()
+matches continue
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('convertVectorExpr0')"><a name="convertVectorExpr0Anchor">convertVectorExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConvertVectorExpr.html">ConvertVectorExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="convertVectorExpr0"><pre>Matches builtin function __builtin_convertvector.
+
+Given
+ typedef double vector4double __attribute__((__vector_size__(32)));
+ typedef float vector4float __attribute__((__vector_size__(16)));
+ vector4float vf;
+ void f() { (void)__builtin_convertvector(vf, vector4double); }
+
+The matcher convertVectorExpr() matches
+__builtin_convertvector(vf, vector4double).
</pre></td></tr>
@@ -1500,19 +1813,85 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="coreturnStmt0"><pre>Matches co_return statements.
Given
- while (true) { co_return; }
-coreturnStmt()
- matches 'co_return'
+ namespace std {
+ template <typename T = void>
+ struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+ };
+
+ struct always_suspend {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+ };
+
+ template <typename T>
+ struct coroutine_traits {
+ using promise_type = T::promise_type;
+ };
+ } // namespace std
+
+ struct generator {
+ struct promise_type {
+ void return_value(int v);
+ std::always_suspend yield_value(int&&);
+ std::always_suspend initial_suspend() const noexcept;
+ std::always_suspend final_suspend() const noexcept;
+ void unhandled_exception();
+ generator get_return_object();
+ };
+ };
+
+ generator f() {
+ co_return 10;
+ }
+
+
+The matcher coreturnStmt(has(integerLiteral()))
+matches co_return 10
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('coroutineBodyStmt0')"><a name="coroutineBodyStmt0Anchor">coroutineBodyStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CoroutineBodyStmt.html">CoroutineBodyStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="coroutineBodyStmt0"><pre>Matches coroutine body statements.
-coroutineBodyStmt() matches the coroutine below
- generator<int> gen() {
- co_return;
- }
+Given
+ namespace std {
+ template <typename T = void>
+ struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+ };
+
+ struct suspend_always {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+ };
+
+ template <typename...>
+ struct coroutine_traits {
+ struct promise_type {
+ std::suspend_always initial_suspend() const noexcept;
+ std::suspend_always final_suspend() const noexcept;
+ void return_void();
+ void unhandled_exception();
+ coroutine_traits get_return_object();
+ };
+ };
+ } // namespace std
+
+ void f() { while (true) { co_return; } }
+
+
+
+The matcher coroutineBodyStmt() matches
+{ while (true) { co_return; } }.
</pre></td></tr>
@@ -1520,27 +1899,77 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="coyieldExpr0"><pre>Matches co_yield expressions.
Given
- co_yield 1;
-coyieldExpr()
- matches 'co_yield 1'
+ namespace std {
+ template <typename T = void>
+ struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+ };
+
+ struct always_suspend {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+ };
+
+ template <typename T>
+ struct coroutine_traits {
+ using promise_type = T::promise_type;
+ };
+ } // namespace std
+
+ struct generator {
+ struct promise_type {
+ std::always_suspend yield_value(int&&);
+ std::always_suspend initial_suspend() const noexcept;
+ std::always_suspend final_suspend() const noexcept;
+ void return_void();
+ void unhandled_exception();
+ generator get_return_object();
+ };
+ };
+
+ generator f() {
+ while (true) {
+ co_yield 10;
+ }
+ }
+
+The matcher coyieldExpr()
+matches co_yield 10
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cudaKernelCallExpr0')"><a name="cudaKernelCallExpr0Anchor">cudaKernelCallExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CUDAKernelCallExpr.html">CUDAKernelCallExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cudaKernelCallExpr0"><pre>Matches CUDA kernel call expression.
-Example matches,
- kernel<<<i,j>>>();
+Given
+ __global__ void kernel() {}
+ void f() {
+ kernel<<<32,32>>>();
+ }
+
+The matcher cudaKernelCallExpr()
+matches kernel<<<i, k>>>()
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxBindTemporaryExpr0')"><a name="cxxBindTemporaryExpr0Anchor">cxxBindTemporaryExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxBindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
-Example matches FunctionTakesString(GetStringByValue())
- (matcher = cxxBindTemporaryExpr())
- FunctionTakesString(GetStringByValue());
- FunctionTakesStringByPointer(GetStringPointer());
+Given
+ struct S {
+ S() { } // User defined constructor makes S non-POD.
+ ~S() { } // User defined destructor makes it non-trivial.
+ };
+ void test() {
+ const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
+ }
+
+The matcher cxxBindTemporaryExpr()
+matches the constructor call S().
</pre></td></tr>
@@ -1548,49 +1977,71 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="cxxBoolLiteral0"><pre>Matches bool literals.
Example matches true
- true
+ bool Flag = true;
+
+
+The matcher cxxBoolLiteral() matches true.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxCatchStmt0')"><a name="cxxCatchStmt0Anchor">cxxCatchStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxCatchStmt0"><pre>Matches catch statements.
+void foo() {
try {} catch(int i) {}
-cxxCatchStmt()
- matches 'catch(int i)'
+}
+
+The matcher cxxCatchStmt()
+matches catch(int i) {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstCastExpr0')"><a name="cxxConstCastExpr0Anchor">cxxConstCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxConstCastExpr0"><pre>Matches a const_cast expression.
-Example: Matches const_cast<int*>(&r) in
+Given
int n = 42;
const int &r(n);
int* p = const_cast<int*>(&r);
+
+
+The matcher cxxConstCastExpr()
+matches const_cast<int*>(&r).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstructExpr0')"><a name="cxxConstructExpr0Anchor">cxxConstructExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxConstructExpr0"><pre>Matches constructor call expressions (including implicit ones).
-Example matches string(ptr, n) and ptr within arguments of f
- (matcher = cxxConstructExpr())
+Given
+ struct string {
+ string(const char*);
+ string(const char*s, int n);
+ };
void f(const string &a, const string &b);
- char *ptr;
- int n;
- f(string(ptr, n), ptr);
+ void foo(char *ptr, int n) {
+ f(string(ptr, n), ptr);
+ }
+
+
+The matcher cxxConstructExpr() matches string(ptr, n)
+and ptr within arguments of f .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDefaultArgExpr0')"><a name="cxxDefaultArgExpr0Anchor">cxxDefaultArgExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDefaultArgExpr.html">CXXDefaultArgExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxDefaultArgExpr0"><pre>Matches the value of a default argument at the call site.
-Example matches the CXXDefaultArgExpr placeholder inserted for the
- default value of the second parameter in the call expression f(42)
- (matcher = cxxDefaultArgExpr())
+Given
void f(int x, int y = 0);
- f(42);
+ void g() {
+ f(42);
+ }
+
+
+The matcher callExpr(has(cxxDefaultArgExpr()))
+matches the CXXDefaultArgExpr placeholder inserted for the default value
+of the second parameter in the call expression f(42).
</pre></td></tr>
@@ -1598,9 +2049,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="cxxDeleteExpr0"><pre>Matches delete expressions.
Given
- delete X;
-cxxDeleteExpr()
- matches 'delete X'.
+ void* operator new(decltype(sizeof(void*)));
+ void operator delete(void*);
+ struct X {};
+ void foo() {
+ auto* x = new X;
+ delete x;
+ }
+
+
+The matcher cxxDeleteExpr()
+matches delete x.
</pre></td></tr>
@@ -1610,7 +2069,8 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <class T> void f() { T t; t.g(); }
-cxxDependentScopeMemberExpr()
+
+The matcher cxxDependentScopeMemberExpr()
matches t.g
</pre></td></tr>
@@ -1618,53 +2078,83 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDynamicCastExpr0')"><a name="cxxDynamicCastExpr0Anchor">cxxDynamicCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxDynamicCastExpr0"><pre>Matches a dynamic_cast expression.
-Example:
- cxxDynamicCastExpr()
-matches
- dynamic_cast<D*>(&b);
-in
+Given
struct B { virtual ~B() {} }; struct D : B {};
B b;
D* p = dynamic_cast<D*>(&b);
+
+
+The matcher cxxDynamicCastExpr()
+matches dynamic_cast<D*>(&b).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxFoldExpr0')"><a name="cxxFoldExpr0Anchor">cxxFoldExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxFoldExpr0"><pre>Matches C++17 fold expressions.
-Example matches `(0 + ... + args)`:
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+
+The matcher cxxFoldExpr() matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxForRangeStmt0')"><a name="cxxForRangeStmt0Anchor">cxxForRangeStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxForRangeStmt0"><pre>Matches range-based for statements.
-cxxForRangeStmt() matches 'for (auto a : i)'
- int i[] = {1, 2, 3}; for (auto a : i);
- for(int j = 0; j < 5; ++j);
+Given
+ void foo() {
+ int i[] = {1, 2, 3}; for (auto a : i);
+ for(int j = 0; j < 5; ++j);
+ }
+
+The matcher cxxForRangeStmt()
+matches for (auto a : i);
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxFunctionalCastExpr0')"><a name="cxxFunctionalCastExpr0Anchor">cxxFunctionalCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxFunctionalCastExpr0"><pre>Matches functional cast expressions
-Example: Matches Foo(bar);
- Foo f = bar;
- Foo g = (Foo) bar;
- Foo h = Foo(bar);
+Given
+ struct Foo {
+ Foo(int x);
+ };
+
+ void foo(int bar) {
+ Foo f = bar;
+ Foo g = (Foo) bar;
+ Foo h = Foo(bar);
+ }
+
+
+The matcher cxxFunctionalCastExpr()
+matches Foo(bar).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxMemberCallExpr0')"><a name="cxxMemberCallExpr0Anchor">cxxMemberCallExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxMemberCallExpr0"><pre>Matches member call expressions.
-Example matches x.y()
- X x;
- x.y();
+Given
+ struct X {
+ void y();
+ void m() { y(); }
+ };
+ void f();
+ void g() {
+ X x;
+ x.y();
+ f();
+ }
+
+
+The matcher cxxMemberCallExpr() matches x.y() and
+y(), but not f().
</pre></td></tr>
@@ -1672,9 +2162,15 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="cxxNewExpr0"><pre>Matches new expressions.
Given
- new X;
-cxxNewExpr()
- matches 'new X'.
+ void* operator new(decltype(sizeof(void*)));
+ struct X {};
+ void foo() {
+ auto* x = new X;
+ }
+
+
+The matcher cxxNewExpr()
+matches new X.
</pre></td></tr>
@@ -1687,14 +2183,24 @@ <h2 id="decl-matchers">Node Matchers</h2>
bool c() noexcept(false);
bool d() noexcept(noexcept(a()));
bool e = noexcept(b()) || noexcept(c());
-cxxNoexceptExpr()
- matches `noexcept(a())`, `noexcept(b())` and `noexcept(c())`.
- doesn't match the noexcept specifier in the declarations a, b, c or d.
+
+The matcher cxxNoexceptExpr()
+matches noexcept(a()), noexcept(b()) and
+noexcept(c()), but does not match the noexcept specifier in the
+declarations a, b, c or d.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxNullPtrLiteralExpr0')"><a name="cxxNullPtrLiteralExpr0Anchor">cxxNullPtrLiteralExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNullPtrLiteralExpr.html">CXXNullPtrLiteralExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxNullPtrLiteralExpr0"><pre>Matches nullptr literal.
+
+Given
+ int a = 0;
+ int* b = 0;
+ int *c = nullptr;
+
+
+The matcher cxxNullPtrLiteralExpr() matches nullptr.
</pre></td></tr>
@@ -1706,11 +2212,16 @@ <h2 id="decl-matchers">Node Matchers</h2>
Currently it does not match operators such as new delete.
FIXME: figure out why these do not match?
-Example matches both operator<<((o << b), c) and operator<<(o, b)
- (matcher = cxxOperatorCallExpr())
+Given
+ struct ostream;
ostream &operator<< (ostream &out, int i) { };
- ostream &o; int b = 1, c = 1;
- o << b << c;
+ void f(ostream& o, int b, int c) {
+ o << b << c;
+ }
+
+
+The matcher cxxOperatorCallExpr() matches o << b << c
+and o << b.
See also the binaryOperation() matcher for more-general matching of binary
uses of this AST node.
</pre></td></tr>
@@ -1725,6 +2236,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches reinterpret_cast<char*>(&p) in
void* p = reinterpret_cast<char*>(&p);
+
+
+The matcher cxxReinterpretCastExpr()
+matches reinterpret_cast<char*>(&p).
</pre></td></tr>
@@ -1732,16 +2247,20 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="cxxRewrittenBinaryOperator0"><pre>Matches rewritten binary operators
Example matches use of "<":
- #include <compare>
struct HasSpaceshipMem {
int a;
- constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
+ constexpr bool operator==(const HasSpaceshipMem&) const = default;
};
void compare() {
HasSpaceshipMem hs1, hs2;
- if (hs1 < hs2)
+ if (hs1 != hs2)
return;
}
+
+
+The matcher cxxRewrittenBinaryOperator() matches
+hs1 != hs2.
+
See also the binaryOperation() matcher for more-general matching
of this AST node.
</pre></td></tr>
@@ -1753,12 +2272,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
See also: hasDestinationType
See also: reinterpretCast
-Example:
- cxxStaticCastExpr()
-matches
- static_cast<long>(8)
-in
+Given
long eight(static_cast<long>(8));
+
+
+The matcher cxxStaticCastExpr()
+matches static_cast<long>(8).
</pre></td></tr>
@@ -1766,69 +2285,110 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="cxxStdInitializerListExpr0"><pre>Matches C++ initializer list expressions.
Given
- std::vector<int> a({ 1, 2, 3 });
- std::vector<int> b = { 4, 5 };
+ namespace std {
+ template <typename T>
+ class initializer_list {
+ const T* begin;
+ const T* end;
+ };
+ }
+ template <typename T> class vector {
+ public: vector(std::initializer_list<T>) {}
+ };
+
+ vector<int> a({ 1, 2, 3 });
+ vector<int> b = { 4, 5 };
int c[] = { 6, 7 };
- std::pair<int, int> d = { 8, 9 };
-cxxStdInitializerListExpr()
- matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+ struct pair { int x; int y; };
+ pair d = { 8, 9 };
+
+The matcher cxxStdInitializerListExpr()
+matches { 1, 2, 3 } and { 4, 5 }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
-Example: Matches Foo(bar, bar)
- Foo h = Foo(bar, bar);
+Given
+ struct Foo {
+ Foo(int x, int y);
+ };
+
+ void foo(int bar) {
+ Foo h = Foo(bar, bar);
+ }
+
+
+The matcher cxxTemporaryObjectExpr()
+matches Foo(bar, bar).
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThisExpr0')"><a name="cxxThisExpr0Anchor">cxxThisExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxThisExpr0"><pre>Matches implicit and explicit this expressions.
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThisExpr0')"><a name="cxxThisExpr0Anchor">cxxThisExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxThisExpr0"><pre>Matches implicit and explicit this expressions.
+
+Given
+ struct foo {
+ int i;
+ int f() { return i; }
+ int g() { return this->i; }
+ };
+
-Example matches the implicit this expression in "return i".
- (matcher = cxxThisExpr())
-struct foo {
- int i;
- int f() { return i; }
-};
+The matcher cxxThisExpr()
+matches this of this->i and the implicit this expression
+of i.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThrowExpr0')"><a name="cxxThrowExpr0Anchor">cxxThrowExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXThrowExpr.html">CXXThrowExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxThrowExpr0"><pre>Matches throw expressions.
+void foo() {
try { throw 5; } catch(int i) {}
-cxxThrowExpr()
- matches 'throw 5'
+}
+
+The matcher cxxThrowExpr()
+matches throw 5
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTryStmt0')"><a name="cxxTryStmt0Anchor">cxxTryStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXTryStmt.html">CXXTryStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxTryStmt0"><pre>Matches try statements.
+void foo() {
try {} catch(int i) {}
-cxxTryStmt()
- matches 'try {}'
+}
+
+The matcher cxxTryStmt()
+matches try {} catch(int i) {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxUnresolvedConstructExpr0')"><a name="cxxUnresolvedConstructExpr0Anchor">cxxUnresolvedConstructExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="cxxUnresolvedConstructExpr0"><pre>Matches unresolved constructor call expressions.
-Example matches T(t) in return statement of f
- (matcher = cxxUnresolvedConstructExpr())
+Given
template <typename T>
void f(const T& t) { return T(t); }
+
+
+The matcher cxxUnresolvedConstructExpr() matches
+T(t).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('declRefExpr0')"><a name="declRefExpr0Anchor">declRefExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="declRefExpr0"><pre>Matches expressions that refer to declarations.
-Example matches x in if (x)
- bool x;
- if (x) {}
+Given
+ void f(bool x) {
+ if (x) {}
+ }
+
+
+The matcher declRefExpr() matches x.
</pre></td></tr>
@@ -1836,9 +2396,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="declStmt0"><pre>Matches declaration statements.
Given
- int a;
-declStmt()
- matches 'int a'.
+ void foo() {
+ int a;
+ }
+The matcher declStmt()
+matches int a;.
</pre></td></tr>
@@ -1846,22 +2408,75 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="defaultStmt0"><pre>Matches default statements inside switch statements.
Given
+void foo(int a) {
switch(a) { case 42: break; default: break; }
-defaultStmt()
- matches 'default:'.
+}
+The matcher defaultStmt()
+matches default: break.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('dependentCoawaitExpr0')"><a name="dependentCoawaitExpr0Anchor">dependentCoawaitExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DependentCoawaitExpr.html">DependentCoawaitExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="dependentCoawaitExpr0"><pre>Matches co_await expressions where the type of the promise is dependent
+
+Given
+ namespace std {
+ template <typename T = void>
+ struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+ };
+
+ struct always_suspend {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+ };
+
+ template <typename T>
+ struct coroutine_traits {
+ using promise_type = T::promise_type;
+ };
+ } // namespace std
+
+ template <typename T>
+ struct generator {
+ struct promise_type {
+ std::always_suspend yield_value(int&&);
+ std::always_suspend initial_suspend() const noexcept;
+ std::always_suspend final_suspend() const noexcept;
+ void return_void();
+ void unhandled_exception();
+ generator get_return_object();
+ };
+ };
+
+ template <typename T>
+ std::always_suspend h();
+
+ template <>
+ std::always_suspend h<void>();
+
+ template<typename T>
+ generator<T> g() { co_await h<T>(); }
+
+The matcher dependentCoawaitExpr()
+matches co_await h<T>().
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('designatedInitExpr0')"><a name="designatedInitExpr0Anchor">designatedInitExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DesignatedInitExpr.html">DesignatedInitExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="designatedInitExpr0"><pre>Matches C99 designated initializer expressions [C99 6.7.8].
-Example: Matches { [2].y = 1.0, [0].x = 1.0 }
- point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+Example: Given
+ struct point2 { double x; double y; };
+ struct point2 ptarray[10] = { [0].x = 1.0 };
+ struct point2 pt = { .x = 2.0 };
+
+The matcher designatedInitExpr()
+matches [0].x = 1.0 and .x = 2.0.
</pre></td></tr>
@@ -1869,9 +2484,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="doStmt0"><pre>Matches do statements.
Given
+void foo() {
do {} while (true);
-doStmt()
- matches 'do {} while(true)'
+}
+
+The matcher doStmt()
+matches do {} while (true)
</pre></td></tr>
@@ -1889,18 +2507,36 @@ <h2 id="decl-matchers">Node Matchers</h2>
See also: hasDestinationType.
-Example: matches all five of the casts in
- int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
-but does not match the implicit conversion in
- long ell = 42;
+ struct S {};
+ const S* s;
+ S* s2 = const_cast<S*>(s);
+
+ const int val = 0;
+ char val0 = val;
+ char val1 = (char)val;
+ char val2 = static_cast<char>(val);
+ int* val3 = reinterpret_cast<int*>(val);
+ char val4 = char(val);
+
+
+The matcher explicitCastExpr()
+matches (char)val, static_cast<char>(val),
+reinterpret_cast<int*>(val), const_cast<S*>(s)
+and char(val), but not the initialization of val0 with
+val.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('expr0')"><a name="expr0Anchor">expr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="expr0"><pre>Matches expressions.
-Example matches x()
- void f() { x(); }
+Given
+ int f(int x, int y) { return x + y; }
+
+The matcher expr() matches x + y once,
+x twice and y twice, matching the
+DeclRefExpr , and the ImplicitCastExpr that does an l- to r-value
+cast.
</pre></td></tr>
@@ -1909,12 +2545,33 @@ <h2 id="decl-matchers">Node Matchers</h2>
of the sub-expression's evaluation.
Example matches std::string()
- const std::string str = std::string();
+ struct A { ~A(); };
+ void f(A);
+ void g(A&);
+ void h() {
+ A a = A{};
+ f(A{});
+ f(a);
+ g(a);
+ }
+
+
+The matcher exprWithCleanups() matches A{},
+f(A{}) and f(a),
+but does not match passing g(a).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('fixedPointLiteral0')"><a name="fixedPointLiteral0Anchor">fixedPointLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FixedPointLiteral.html">FixedPointLiteral</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="fixedPointLiteral0"><pre>Matches fixed point literals
+
+Given
+ void f() {
+ 0.0k;
+ }
+
+
+The matcher fixedPointLiteral() matches 0.0k.
</pre></td></tr>
@@ -1922,27 +2579,62 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes / encodings, e.g.
1.0, 1.0f, 1.0L and 1e10.
-Does not match implicit conversions such as
- float a = 10;
+Given
+ int a = 1.0;
+ int b = 1.0F;
+ int c = 1.0L;
+ int d = 1e10;
+ int e = 1;
+
+The matcher floatLiteral() matches
+1.0, 1.0F, 1.0L and 1e10, but does not match
+1.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forStmt0')"><a name="forStmt0Anchor">forStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="forStmt0"><pre>Matches for statements.
-Example matches 'for (;;) {}'
- for (;;) {}
- int i[] = {1, 2, 3}; for (auto a : i);
+Given
+ void foo() {
+ for (;;) {}
+ int i[] = {1, 2, 3}; for (auto a : i);
+ }
+
+
+The matcher forStmt() matches for (;;) {},
+but not for (auto a : i);.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('genericSelectionExpr0')"><a name="genericSelectionExpr0Anchor">genericSelectionExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1GenericSelectionExpr.html">GenericSelectionExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="genericSelectionExpr0"><pre>Matches C11 _Generic expression.
+
+Given
+ double fdouble(double);
+ float ffloat(float);
+ #define GENERIC_MACRO(X) _Generic((X), double: fdouble, float: ffloat)(X)
+
+ void f() {
+ GENERIC_MACRO(0.0);
+ GENERIC_MACRO(0.0F);
+ }
+
+
+The matcher genericSelectionExpr() matches
+the generic selection expression that is expanded in
+GENERIC_MACRO(0.0) and GENERIC_MACRO(0.0F).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('gnuNullExpr0')"><a name="gnuNullExpr0Anchor">gnuNullExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1GNUNullExpr.html">GNUNullExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="gnuNullExpr0"><pre>Matches GNU __null expression.
+
+Given
+ auto val = __null;
+
+
+The matcher gnuNullExpr() matches __null.
</pre></td></tr>
@@ -1950,24 +2642,39 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="gotoStmt0"><pre>Matches goto statements.
Given
+void bar();
+void foo() {
goto FOO;
FOO: bar();
-gotoStmt()
- matches 'goto FOO'
+}
+The matcher gotoStmt()
+matches goto FOO
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('ifStmt0')"><a name="ifStmt0Anchor">ifStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="ifStmt0"><pre>Matches if statements.
-Example matches 'if (x) {}'
- if (x) {}
+Given
+ void foo(int x) {
+ if (x) {}
+ }
+
+The matcher ifStmt() matches if (x) {}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('imaginaryLiteral0')"><a name="imaginaryLiteral0Anchor">imaginaryLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ImaginaryLiteral.html">ImaginaryLiteral</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="imaginaryLiteral0"><pre>Matches imaginary literals, which are based on integer and floating
point literals e.g.: 1i, 1.0i
+
+Given
+ auto a = 1i;
+ auto b = 1.0i;
+
+
+The matcher imaginaryLiteral() matches 1i and
+1.0i.
</pre></td></tr>
@@ -1976,6 +2683,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
This matches many
diff erent places, including function call return value
eliding, as well as any type conversions.
+
+void f(int);
+void g(int val1, int val2) {
+ unsigned int a = val1;
+ f(val2);
+}
+
+The matcher implicitCastExpr()
+matches val1 for the implicit cast from an l- to an r-value
+and for the cast to int}, f for the function pointer
+decay, and val2 for the cast from an l- to an r-value.
</pre></td></tr>
@@ -1983,9 +2701,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="implicitValueInitExpr0"><pre>Matches implicit initializers of init list expressions.
Given
- point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
-implicitValueInitExpr()
- matches "[0].y" (implicitly)
+ struct point { double x; double y; };
+ struct point pt = { .x = 42.0 };
+The matcher
+initListExpr(has(implicitValueInitExpr().bind("implicit")))
+matches { .x = 42.0 }.
</pre></td></tr>
@@ -1995,9 +2715,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
int a[] = { 1, 2 };
struct B { int x, y; };
- B b = { 5, 6 };
-initListExpr()
- matches "{ 1, 2 }" and "{ 5, 6 }"
+ struct B b = { 5, 6 };
+The matcher initListExpr()
+matches { 1, 2 } and { 5, 6 }
</pre></td></tr>
@@ -2006,6 +2726,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
1, 1L, 0x1 and 1U.
Does not match character-encoded integers such as L'a'.
+
+Given
+ int a = 1;
+ int b = 1L;
+ int c = 0x1;
+ int d = 1U;
+ int e = 1.0;
+
+The matcher integerLiteral() matches
+1, 1L, 0x1 and 1U, but does not match
+1.0.
</pre></td></tr>
@@ -2013,18 +2744,26 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="labelStmt0"><pre>Matches label statements.
Given
+void bar();
+void foo() {
goto FOO;
FOO: bar();
-labelStmt()
- matches 'FOO:'
+}
+The matcher labelStmt()
+matches FOO: bar()
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('lambdaExpr0')"><a name="lambdaExpr0Anchor">lambdaExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="lambdaExpr0"><pre>Matches lambda expressions.
-Example matches [&](){return 5;}
- [&](){return 5;}
+Given
+ void f() {
+ []() { return 5; };
+ }
+
+
+The matcher lambdaExpr() matches []() { return 5; }.
</pre></td></tr>
@@ -2035,12 +2774,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
struct T {void func();};
T f();
void g(T);
-materializeTemporaryExpr() matches 'f()' in these statements
- T u(f());
- g(f());
- f().func();
-but does not match
- f();
+ void foo() {
+ T u(f());
+ g(f());
+ f().func();
+ f(); // does not match
+ }
+
+The matcher materializeTemporaryExpr() matches
+f() three times before C++17 and it
+matches f() time with C++17 and later, but
+it does not match the f() in the last line in any version.
</pre></td></tr>
@@ -2052,17 +2796,20 @@ <h2 id="decl-matchers">Node Matchers</h2>
void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
int a; static int b;
};
-memberExpr()
- matches this->x, x, y.x, a, this->b
+
+The matcher memberExpr()
+matches this->x, x, y.x, a, this->b.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('nullStmt0')"><a name="nullStmt0Anchor">nullStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NullStmt.html">NullStmt</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="nullStmt0"><pre>Matches null statements.
+void foo() {
foo();;
-nullStmt()
- matches the second ';'
+}
+The matcher nullStmt()
+matches the second ;
</pre></td></tr>
@@ -2072,6 +2819,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches @catch
@try {}
@catch (...) {}
+
</pre></td></tr>
@@ -2081,19 +2829,23 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches @finally
@try {}
@finally {}
+
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcIvarRefExpr0')"><a name="objcIvarRefExpr0Anchor">objcIvarRefExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCIvarRefExpr.html">ObjCIvarRefExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="objcIvarRefExpr0"><pre>Matches a reference to an ObjCIvar.
-Example: matches "a" in "init" method:
+Given
@implementation A {
NSString *a;
}
- (void) init {
a = @"hello";
}
+
+
+The matcher objcIvarRefExpr() matches a.
</pre></td></tr>
@@ -2105,6 +2857,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
"initWithString" instance method on the object returned from
NSString's "alloc". This matcher should match both message sends.
[[NSString alloc] initWithString:@"Hello"]
+
+
+The matcher objcMessageExpr() matches
+[[NSString alloc] initWithString:@"Hello"]
</pre></td></tr>
@@ -2113,6 +2869,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches @"abcd"
NSString *s = @"abcd";
+
</pre></td></tr>
@@ -2120,6 +2877,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="objcThrowStmt0"><pre>Matches Objective-C statements.
Example matches @throw obj;
+
</pre></td></tr>
@@ -2129,6 +2887,7 @@ <h2 id="decl-matchers">Node Matchers</h2>
Example matches @try
@try {}
@catch (...) {}
+
</pre></td></tr>
@@ -2136,13 +2895,19 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="ompExecutableDirective0"><pre>Matches any ``#pragma omp`` executable directive.
Given
+ void foo() {
+ #pragma omp parallel
+ {}
+ #pragma omp parallel default(none)
+ {
+ #pragma omp taskyield
+ }
+ }
- #pragma omp parallel
- #pragma omp parallel default(none)
- #pragma omp taskyield
-
-``ompExecutableDirective()`` matches ``omp parallel``,
-``omp parallel default(none)`` and ``omp taskyield``.
+The matcher ompExecutableDirective()
+matches #pragma omp parallel,
+#pragma omp parallel default(none)
+and #pragma omp taskyield.
</pre></td></tr>
@@ -2151,17 +2916,27 @@ <h2 id="decl-matchers">Node Matchers</h2>
to reference another expressions and can be met
in BinaryConditionalOperators, for example.
-Example matches 'a'
- (a ?: c) + 42;
+Given
+ int f(int a, int b) {
+ return (a ?: b) + 42;
+ }
+
+
+The matcher opaqueValueExpr() matches a twice,
+once for the check and once for the expression of the true path.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('parenExpr0')"><a name="parenExpr0Anchor">parenExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ParenExpr.html">ParenExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="parenExpr0"><pre>Matches parentheses used in expressions.
-Example matches (foo() + 1)
+Given
int foo() { return 1; }
- int a = (foo() + 1);
+ int bar() {
+ int a = (foo() + 1);
+ }
+
+The matcher parenExpr() matches (foo() + 1).
</pre></td></tr>
@@ -2177,8 +2952,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
int a = 0, b = 1; int i = (a, b);
}
};
-parenListExpr() matches "*this" but NOT matches (a, b) because (a, b)
-has a predefined type and is a ParenExpr, not a ParenListExpr.
+
+The matcher parenListExpr()
+matches (*this),
+but does not match (a, b)
+because (a, b) has a predefined type and is a ParenExpr, not a
+ParenListExpr.
</pre></td></tr>
@@ -2186,7 +2965,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="predefinedExpr0"><pre>Matches predefined identifier expressions [C99 6.4.2.2].
Example: Matches __func__
- printf("%s", __func__);
+ void f() {
+ const char* func_name = __func__;
+ }
+
+The matcher predefinedExpr()
+matches __func__.
</pre></td></tr>
@@ -2194,9 +2978,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="returnStmt0"><pre>Matches return statements.
Given
+int foo() {
return 1;
-returnStmt()
- matches 'return 1'
+}
+The matcher returnStmt()
+matches return 1
</pre></td></tr>
@@ -2204,26 +2990,35 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
Given
- { ++a; }
-stmt()
- matches both the compound statement '{ ++a; }' and '++a'.
+ void foo(int a) { { ++a; } }
+The matcher stmt()
+matches the function body itself { { ++a; } }, the compound
+statement { ++a; }, the expression ++a and a.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stmtExpr0')"><a name="stmtExpr0Anchor">stmtExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StmtExpr.html">StmtExpr</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="stmtExpr0"><pre>Matches statement expression (GNU extension).
-Example match: ({ int X = 4; X; })
- int C = ({ int X = 4; X; });
+Given
+ void f() {
+ int C = ({ int X = 4; X; });
+ }
+
+The matcher stmtExpr() matches ({ int X = 4; X; }).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
-Example matches "abcd", L"abcd"
+Given
char *s = "abcd";
wchar_t *ws = L"abcd";
+
+
+The matcher stringLiteral() matches "abcd" and
+L"abcd".
</pre></td></tr>
@@ -2234,8 +3029,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
template <int N>
struct A { static const int n = N; };
struct B : public A<42> {};
-substNonTypeTemplateParmExpr()
- matches "N" in the right-hand side of "static const int n = N;"
+
+The matcher substNonTypeTemplateParmExpr()
+matches N in the right-hand side of "static const int n = N;"
</pre></td></tr>
@@ -2243,9 +3039,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
Given
+void foo(int a) {
switch(a) { case 42: break; default: break; }
-switchCase()
- matches 'case 42:' and 'default:'.
+}
+The matcher switchCase()
+matches case 42: break and default: break
</pre></td></tr>
@@ -2253,9 +3051,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="switchStmt0"><pre>Matches switch statements.
Given
+void foo(int a) {
switch(a) { case 42: break; default: break; }
-switchStmt()
- matches 'switch(a)'.
+}
+The matcher switchStmt()
+matches switch(a) { case 42: break; default: break; }.
</pre></td></tr>
@@ -2263,10 +3063,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="unaryExprOrTypeTraitExpr0"><pre>Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
Given
- Foo x = bar;
+ int x = 42;
int y = sizeof(x) + alignof(x);
-unaryExprOrTypeTraitExpr()
- matches sizeof(x) and alignof(x)
+
+The matcher unaryExprOrTypeTraitExpr()
+matches sizeof(x) and alignof(x)
</pre></td></tr>
@@ -2274,7 +3075,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="unaryOperator0"><pre>Matches unary operator expressions.
Example matches !a
- !a || b
+ void foo(bool a, bool b) {
+ !a || b;
+ }
+
+
+The matcher unaryOperator() matches !a.
</pre></td></tr>
@@ -2289,8 +3095,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
void bar() {
foo<T>();
}
-unresolvedLookupExpr()
- matches foo<T>() </pre></td></tr>
+
+The matcher unresolvedLookupExpr()
+matches foo<T>.
+</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('unresolvedMemberExpr0')"><a name="unresolvedMemberExpr0Anchor">unresolvedMemberExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnresolvedMemberExpr.html">UnresolvedMemberExpr</a>>...</td></tr>
@@ -2302,8 +3110,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
void g();
};
template <class T> void h() { X x; x.f<T>(); x.g(); }
-unresolvedMemberExpr()
- matches x.f<T>
+
+The matcher unresolvedMemberExpr()
+matches x.f<T>
</pre></td></tr>
@@ -2311,6 +3120,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="userDefinedLiteral0"><pre>Matches user defined literal operator call.
Example match: "foo"_suffix
+Given
+ float operator ""_foo(long double);
+ float a = 1234.5_foo;
+
+
+The matcher userDefinedLiteral() matches 1234.5_foo.
</pre></td></tr>
@@ -2318,9 +3133,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="whileStmt0"><pre>Matches while statements.
Given
+void foo() {
while (true) {}
-whileStmt()
- matches 'while (true) {}'.
+}
+
+The matcher whileStmt()
+matches while (true) {}.
</pre></td></tr>
@@ -2330,8 +3148,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T> struct C {};
C<int> c;
-templateArgumentLoc()
- matches 'int' in C<int>.
+
+The matcher templateArgumentLoc()
+matches int in C<int>.
</pre></td></tr>
@@ -2341,8 +3160,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T> struct C {};
C<int> c;
-templateArgument()
- matches 'int' in C<int>.
+
+The matcher
+templateSpecializationType(hasAnyTemplateArgument(templateArgument()))
+matches C<int>.
</pre></td></tr>
@@ -2350,10 +3171,14 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="templateName0"><pre>Matches template name.
Given
- template <typename T> class X { };
- X<int> xi;
-templateName()
- matches 'X' in X<int>.
+ template<template <typename> class S> class X {};
+ template<typename T> class Y {};
+ X<Y> xi;
+
+The matcher
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToTemplate(templateName())))
+matches the specialization class X<Y>
</pre></td></tr>
@@ -2363,8 +3188,8 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
struct s {};
struct s ss;
-elaboratedTypeLoc()
- matches the `TypeLoc` of the variable declaration of `ss`.
+The matcher elaboratedTypeLoc()
+matches the type struct s of ss.
</pre></td></tr>
@@ -2373,8 +3198,8 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
int* x;
-pointerTypeLoc()
- matches `int*`.
+The matcher pointerTypeLoc()
+ matches int*.
</pre></td></tr>
@@ -2383,8 +3208,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
const int x = 0;
-qualifiedTypeLoc()
- matches `const int`.
+
+The matcher qualifiedTypeLoc()
+matches the type of the variable declaration x . However, the
+current implementation of QualifiedTypeLoc does not store the source
+locations for the qualifiers of the type int.
</pre></td></tr>
@@ -2395,8 +3223,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
int x = 3;
int& l = x;
int&& r = 3;
-referenceTypeLoc()
- matches `int&` and `int&&`.
+
+
+The matcher referenceTypeLoc()
+ matches int& and int&&.
</pre></td></tr>
@@ -2406,13 +3236,25 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T> class C {};
C<char> var;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc())))
- matches `C<char> var`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+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.
+
+That is, information about a type and where it was written.
+
+ void foo(int val);
+
+The matcher declaratorDecl(hasTypeLoc(typeLoc().bind("type")))
+matches void foo(int val) and int val, with
+typeLoc() matching void and
+int respectively.
</pre></td></tr>
@@ -2423,8 +3265,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
int a[] = { 2, 3 };
int b[4];
void f() { int c[a[0]]; }
-arrayType()
- matches "int a[]", "int b[4]" and "int c[a[0]]";
+The matcher arrayType()
+int[4], int[a[0]] and
+int[];
</pre></td></tr>
@@ -2433,20 +3276,25 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
_Atomic(int) i;
-atomicType()
- matches "_Atomic(int) i"
+The matcher atomicType()
+_Atomic(int)
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('autoType0')"><a name="autoType0Anchor">autoType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="autoType0"><pre>Matches types nodes representing C++11 auto types.
-Given:
- auto n = 4;
- int v[] = { 2, 3 }
- for (auto i : v) { }
-autoType()
- matches "auto n" and "auto i"
+Given
+ void foo() {
+ auto n = 4;
+ int v[] = { 2, 3 };
+ for (auto i : v) { };
+ }
+
+The matcher autoType()
+matches the auto of n and i ,
+as well as the auto types for the implicitly generated code of the range-for
+loop (for the range, the begin iterator and the end iterator).
</pre></td></tr>
@@ -2462,13 +3310,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="builtinType0"><pre>Matches builtin Types.
Given
- struct A {};
- A a;
+ enum E { Ok };
+ enum E e;
int b;
float c;
- bool d;
-builtinType()
- matches "int b", "float c" and "bool d"
+The matcher varDecl(hasType(builtinType()))
+matches int b and float c.
</pre></td></tr>
@@ -2477,8 +3324,8 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
_Complex float f;
-complexType()
- matches "_Complex float f"
+The matcher complexType()
+_Complex float
</pre></td></tr>
@@ -2486,37 +3333,38 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="constantArrayType0"><pre>Matches C arrays with a specified constant size.
Given
- void() {
+ void foo() {
int a[2];
int b[] = { 2, 3 };
int c[b[0]];
}
-constantArrayType()
- matches "int a[2]"
+The matcher constantArrayType()
+int[2]
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('decayedType0')"><a name="decayedType0Anchor">decayedType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="decayedType0"><pre>Matches decayed type
-Example matches i[] in declaration of f.
- (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
-Example matches i[1].
- (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
void f(int i[]) {
i[1] = 0;
}
-</pre></td></tr>
+The matcher
+valueDecl(hasType(decayedType(hasDecayedType(pointerType()))))
+matches int i[] in declaration of The matcher
+expr(hasType(decayedType(hasDecayedType(pointerType()))))
+matches i in </pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('decltypeType0')"><a name="decltypeType0Anchor">decltypeType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecltypeType.html">DecltypeType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="decltypeType0"><pre>Matches types nodes representing C++11 decltype(<expr>) types.
-Given:
+Given
short i = 1;
int j = 42;
decltype(i + j) result = i + j;
-decltypeType()
- matches "decltype(i + j)"
+
+The matcher decltypeType()
+decltype(i + j)
</pre></td></tr>
@@ -2529,8 +3377,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
class C { public: C(T); };
C c(123);
-deducedTemplateSpecializationType() matches the type in the declaration
-of the variable c.
+
+The matcher deducedTemplateSpecializationType() matches the type
+C of the declaration of the variable c.
</pre></td></tr>
@@ -2542,8 +3391,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
class array {
T data[Size];
};
-dependentSizedArrayType()
- matches "T data[Size]"
+
+The matcher dependentSizedArrayType()
+T[Size]
</pre></td></tr>
@@ -2556,8 +3406,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
class vector {
typedef T __attribute__((ext_vector_type(Size))) type;
};
-dependentSizedExtVectorType()
- matches "T __attribute__((ext_vector_type(Size)))"
+
+The matcher dependentSizedExtVectorType()
+T __attribute__((ext_vector_type(Size)))
</pre></td></tr>
@@ -2573,11 +3424,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
}
class C {};
- class C c;
+ C c;
N::M::D d;
-elaboratedType() matches the type of the variable declarations of both
-c and d.
+
+The matcher elaboratedType() matches the type
+C three times. Once for the type of the
+variable c, once for the type of the class definition and once for the
+type in the injected class name. For D}, it matches
+N::M::D of variable d and its class definition and
+injected class name
+D one time respectively.
</pre></td></tr>
@@ -2591,8 +3448,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
C c;
S s;
-enumType() matches the type of the variable declarations of both c and
-s.
+
+The matcher enumType() matches the type
+enum C of c ,
+and the type enum S of s .
</pre></td></tr>
@@ -2602,9 +3461,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
int (*f)(int);
void g();
-functionProtoType()
- matches "int (*f)(int)" and the type of "g" in C++ mode.
- In C mode, "g" is not matched because it does not contain a prototype.
+The matcher functionProtoType()
+matches the type int (int) of 'f' and the type
+void (void) of 'g' in C++ mode.
+In C, the type void () of 'g' is not
+matched because it does not contain a prototype.
</pre></td></tr>
@@ -2614,8 +3475,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
int (*f)(int);
void g();
-functionType()
- matches "int (*f)(int)" and the type of "g".
+The matcher functionType()
+int (int) and the type of
+void (void) in C++ and in C23 and
+later. Before C23, the function type for f will be matched the same way,
+but the function type for g will match
+void ().
</pre></td></tr>
@@ -2626,27 +3491,30 @@ <h2 id="decl-matchers">Node Matchers</h2>
int a[] = { 2, 3 };
int b[42];
void f(int c[]) { int d[a[0]]; };
-incompleteArrayType()
- matches "int a[]" and "int c[]"
+The matcher incompleteArrayType()
+int[] and int[]
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('injectedClassNameType0')"><a name="injectedClassNameType0Anchor">injectedClassNameType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="injectedClassNameType0"><pre>Matches injected class name types.
-Example matches S s, but not S<T> s.
- (matcher = parmVarDecl(hasType(injectedClassNameType())))
+Given
template <typename T> struct S {
void f(S s);
void g(S<T> s);
};
+
+The matcher
+parmVarDecl(hasType(elaboratedType(namesType(injectedClassNameType()))))
+matches S s, but not s}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('lValueReferenceType0')"><a name="lValueReferenceType0Anchor">lValueReferenceType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LValueReferenceType.html">LValueReferenceType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="lValueReferenceType0"><pre>Matches lvalue reference types.
-Given:
+Given
int *a;
int &b = *a;
int &&c = 1;
@@ -2655,8 +3523,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
auto &&f = 2;
int g = 5;
-lValueReferenceType() matches the types of b, d, and e. e is
-matched since the type is deduced as int& by reference collapsing rules.
+
+The matcher lValueReferenceType() matches the type
+int & of b and the type auto &
+of d.
+FIXME: figure out why auto changechange matches twice
</pre></td></tr>
@@ -2667,18 +3538,23 @@ <h2 id="decl-matchers">Node Matchers</h2>
#define CDECL __attribute__((cdecl))
typedef void (CDECL *X)();
typedef void (__attribute__((cdecl)) *Y)();
-macroQualifiedType()
- matches the type of the typedef declaration of X but not Y.
+The matcher macroQualifiedType()
+matches the type CDECL void
+(void) of the typedef declaration of X , unless when in C98-C17, there
+CDECL void (),
+but it does not match the type
+__attribute((cdecl)) void () of Y .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('memberPointerType0')"><a name="memberPointerType0Anchor">memberPointerType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="memberPointerType0"><pre>Matches member pointer types.
Given
- struct A { int i; }
- A::* ptr = A::i;
-memberPointerType()
- matches "A::* ptr"
+ struct A { int i; };
+ int A::* ptr = &A::i;
+
+The matcher memberPointerType()
+matches int struct A::*.
</pre></td></tr>
@@ -2692,8 +3568,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
@interface Foo
@end
Foo *f;
-pointerType()
- matches "Foo *f", but does not match "int *a".
+
+The matcher pointerType()
+matches Foo *, but does not match
+int *.
</pre></td></tr>
@@ -2704,8 +3582,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
int (*ptr_to_array)[4];
int *array_of_ptrs[4];
-varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
-array_of_ptrs.
+The matcher varDecl(hasType(pointsTo(parenType())))
+ matches ptr_to_array but not
+ array_of_ptrs.
</pre></td></tr>
@@ -2714,22 +3593,28 @@ <h2 id="decl-matchers">Node Matchers</h2>
types.
Given
- int *a;
- int &b = *a;
- int c = 5;
+ typedef int* int_ptr;
+ void foo(char *str,
+ int val,
+ int *val_ptr,
+ int_ptr not_a_ptr,
+ int_ptr *ptr);
+
+The matcher parmVarDecl(hasType(pointerType()))
+matches char *str, int *val_ptr and
+int_ptr *ptr.
@interface Foo
@end
Foo *f;
-pointerType()
- matches "int *a", but does not match "Foo *f".
+
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('rValueReferenceType0')"><a name="rValueReferenceType0Anchor">rValueReferenceType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1RValueReferenceType.html">RValueReferenceType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="rValueReferenceType0"><pre>Matches rvalue reference types.
-Given:
+Given
int *a;
int &b = *a;
int &&c = 1;
@@ -2738,8 +3623,10 @@ <h2 id="decl-matchers">Node Matchers</h2>
auto &&f = 2;
int g = 5;
-rValueReferenceType() matches the types of c and f. e is not
-matched as it is deduced to int& by reference collapsing rules.
+
+The matcher rValueReferenceType() matches the type
+int && of c and the type
+auto && of f.
</pre></td></tr>
@@ -2753,8 +3640,14 @@ <h2 id="decl-matchers">Node Matchers</h2>
C c;
S s;
-recordType() matches the type of the variable declarations of both c
-and s.
+
+The matcher recordType() matches the type
+class C of the variable declaration of c and
+matches the type struct S of the variable
+declaration of s.
+Both of these types are matched three times, once for the type of the
+variable, once for the definition of the class, and once for the type of the
+injected class name.
</pre></td></tr>
@@ -2770,7 +3663,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
auto &&f = 2;
int g = 5;
-referenceType() matches the types of b, c, d, e, and f.
+
+The matcher referenceType() matches the type
+int & of b , the type int && of
+c, the type
+auto & d, and the type
+auto && of e and f.
</pre></td></tr>
@@ -2781,10 +3679,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
template <typename T>
void F(T t) {
+ T local;
int i = 1 + t;
}
+ void f() {
+ F(0);
+ }
-substTemplateTypeParmType() matches the type of 't' but not '1'
+
+The matcher varDecl(hasType(substTemplateTypeParmType()))
+matches T t and T local for the substituted template type
+int in the instantiation of F .
</pre></td></tr>
@@ -2792,14 +3697,18 @@ <h2 id="decl-matchers">Node Matchers</h2>
<tr><td colspan="4" class="doc" id="tagType0"><pre>Matches tag types (record and enum types).
Given
- enum E {};
+ enum E { Ok };
class C {};
E e;
C c;
-tagType() matches the type of the variable declarations of both e
-and c.
+
+The matcher tagType() matches the type
+enum E of variable e and the type
+class C three times, once for the type
+of the variable c , once for the type of the class definition and once of
+the type in the injected class name.
</pre></td></tr>
@@ -2810,25 +3719,38 @@ <h2 id="decl-matchers">Node Matchers</h2>
template <typename T>
class C { };
- template class C<int>; // A
- C<char> var; // B
+ template class C<int>;
+ C<int> intvar;
+ C<char> charvar;
-templateSpecializationType() matches the type of the explicit
-instantiation in A and the type of the variable declaration in B.
+
+The matcher templateSpecializationType() matches the type
+C<int> of the explicit instantiation in A and the
+type C<char> of the variable declaration in
+B.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('templateTypeParmType0')"><a name="templateTypeParmType0Anchor">templateTypeParmType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="templateTypeParmType0"><pre>Matches template type parameter types.
-Example matches T, but not int.
- (matcher = templateTypeParmType())
+Given
template <typename T> void f(int i);
+
+The matcher templateTypeParmType() matches T,
+but does not match int.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('type0')"><a name="type0Anchor">type</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="type0"><pre>Matches Types in the clang AST.
+
+Given
+ const int b = 1;
+
+The matcher varDecl(hasType(type().bind("type")))
+matches const int b = 1, with type()
+matching int.
</pre></td></tr>
@@ -2837,18 +3759,22 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
typedef int X;
-typedefType()
- matches "typedef int X"
+ X x = 0;
+The matcher typedefType()
+matches X.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('unaryTransformType0')"><a name="unaryTransformType0Anchor">unaryTransformType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryTransformType.html">UnaryTransformType</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="unaryTransformType0"><pre>Matches types nodes representing unary type transformations.
-Given:
- typedef __underlying_type(T) type;
-unaryTransformType()
- matches "__underlying_type(T)"
+Given
+ template <typename T> struct A {
+ typedef __underlying_type(T) type;
+ };
+
+The matcher unaryTransformType()
+matches __underlying_type(T)
</pre></td></tr>
@@ -2860,7 +3786,9 @@ <h2 id="decl-matchers">Node Matchers</h2>
using a::S;
S s;
-usingType() matches the type of the variable declaration of s.
+
+The matcher usingType() matches the type a::S
+of the variable declaration of s.
</pre></td></tr>
@@ -2870,12 +3798,12 @@ <h2 id="decl-matchers">Node Matchers</h2>
Given
void f() {
- int a[] = { 2, 3 }
+ int a[] = { 2, 3 };
int b[42];
int c[a[0]];
}
-variableArrayType()
- matches "int c[a[0]]"
+The matcher variableArrayType()
+int[a[0]]
</pre></td></tr>
<!--END_DECL_MATCHERS -->
@@ -2899,6 +3827,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="allOf0"><pre>Matches if all given matchers match.
Usable as: Any Matcher
+
+ int v0 = 0;
+ int v1 = 1;
+
+The matcher varDecl(allOf(hasName("v0"), hasType(isInteger())))
+matches int v0 = 0.
</pre></td></tr>
@@ -2906,6 +3840,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="anyOf0"><pre>Matches if any of the given matchers matches.
Usable as: Any Matcher
+
+ char v0 = 'a';
+ int v1 = 1;
+ float v2 = 2.0;
+
+The matcher varDecl(anyOf(hasName("v0"), hasType(isInteger())))
+matches char v0 = 'a' and int v1 = 1.
</pre></td></tr>
@@ -2916,11 +3857,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
additional constraint. This will often be used with an explicit conversion
to an internal::Matcher<> type such as TypeMatcher.
-Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
-"int* p" and "void f()" in
+Given
int* p;
void f();
-
+The matcher decl(anything())
+matches int* p and void f().
Usable as: Any Matcher
</pre></td></tr>
@@ -2929,21 +3870,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="mapAnyOf0"><pre>Matches any of the NodeMatchers with InnerMatchers nested within
Given
- if (true);
- for (; true; );
-with the matcher
- mapAnyOf(ifStmt, forStmt).with(
- hasCondition(cxxBoolLiteralExpr(equals(true)))
- ).bind("trueCond")
-matches the if and the for. It is equivalent to:
- auto trueCond = hasCondition(cxxBoolLiteralExpr(equals(true)));
- anyOf(
- ifStmt(trueCond).bind("trueCond"),
- forStmt(trueCond).bind("trueCond")
- );
+ void f() {
+ if (true);
+ for (; true; );
+ }
+
+
+The matcher stmt(mapAnyOf(ifStmt, forStmt).with(
+ hasCondition(cxxBoolLiteral(equals(true)))
+ )),
+which is equivalent to
+stmt(anyOf(
+ ifStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond"),
+ forStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond")
+ )),
+matches if (true); and for (; true; );.
The with() chain-call accepts zero or more matchers which are combined
as-if with allOf() in each of the node matchers.
+
Usable as: Any Matcher
</pre></td></tr>
@@ -2951,10 +3896,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<*></td><td class="name" onclick="toggle('unless0')"><a name="unless0Anchor">unless</a></td><td>Matcher<*></td></tr>
<tr><td colspan="4" class="doc" id="unless0"><pre>Matches if the provided matcher does not match.
-Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
+Given
class X {};
class Y {};
+The matcher cxxRecordDecl(unless(hasName("X")))
+matches Y
+
Usable as: Any Matcher
</pre></td></tr>
@@ -2962,6 +3910,20 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Attr.html">Attr</a>></td><td class="name" onclick="toggle('isImplicit1')"><a name="isImplicit1Anchor">isImplicit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isImplicit1"><pre>Matches an entity that has been implicitly added by the compiler (e.g.
implicit default/copy constructors).
+
+Given
+ struct S {};
+ void f(S obj) {
+ S copy = obj;
+ [&](){ return copy; };
+ }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+ lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
</pre></td></tr>
@@ -2969,9 +3931,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyOperatorName0"><pre>Matches operator expressions (binary or unary) that have any of the
specified names.
- hasAnyOperatorName("+", "-")
- Is equivalent to
- anyOf(hasOperatorName("+"), hasOperatorName("-"))
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
+ hasAnyOperatorName("+", "-")
+Is equivalent to
+ hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+void bar(bool a, bool b) {
+ a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
</pre></td></tr>
@@ -2979,43 +3958,62 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions and fold expressions
(binary or unary).
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
</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('isAssignmentOperator0')"><a name="isAssignmentOperator0Anchor">isAssignmentOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isAssignmentOperator0"><pre>Matches all kinds of assignment operators.
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
-Example 2: matches s1 = s2
- (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
struct S { S& operator=(const S&); };
void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
</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('isComparisonOperator0')"><a name="isComparisonOperator0Anchor">isComparisonOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isComparisonOperator0"><pre>Matches comparison operators.
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
-Example 2: matches s1 < s2
- (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
struct S { bool operator<(const S& other); };
void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
</pre></td></tr>
@@ -3023,16 +4021,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isPrivate1"><pre>Matches private C++ declarations and C++ base specifers that specify private
inheritance.
-Examples:
+Given
class C {
public: int a;
protected: int b;
- private: int c; // fieldDecl(isPrivate()) matches 'c'
+ private: int c;
};
+The matcher fieldDecl(isPrivate())
+matches c.
+
struct Base {};
- struct Derived1 : private Base {}; // matches 'Base'
- class Derived2 : Base {}; // matches 'Base'
+ struct Derived1 : private Base {}; // Base
+ class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
</pre></td></tr>
@@ -3040,15 +4047,24 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isProtected1"><pre>Matches protected C++ declarations and C++ base specifers that specify
protected inheritance.
-Examples:
+Given
class C {
public: int a;
- protected: int b; // fieldDecl(isProtected()) matches 'b'
+ protected: int b;
private: int c;
};
+The matcher fieldDecl(isProtected())
+matches b.
+
class Base {};
- class Derived : protected Base {}; // matches 'Base'
+ class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
</pre></td></tr>
@@ -3056,16 +4072,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isPublic1"><pre>Matches public C++ declarations and C++ base specifers that specify public
inheritance.
-Examples:
+Given
class C {
- public: int a; // fieldDecl(isPublic()) matches 'a'
+ public: int a;
protected: int b;
private: int c;
};
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
class Base {};
- class Derived1 : public Base {}; // matches 'Base'
- struct Derived2 : Base {}; // matches 'Base'
+ class Derived1 : public Base {};
+ struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
</pre></td></tr>
@@ -3073,16 +4099,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isVirtual1"><pre>Matches declarations of virtual methods and C++ base specifers that specify
virtual inheritance.
-Example:
+Given
class A {
public:
virtual void x(); // matches x
};
-Example:
- class Base {};
- class DirectlyDerived : virtual Base {}; // matches Base
- class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+ struct Base {};
+ struct DirectlyDerived : virtual Base {}; // matches Base
+ struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -3096,22 +4129,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value of type ValueT.
Given
+void f(char, bool, double, int);
+void foo() {
f('false, 3.14, 42);
-characterLiteral(equals(0))
- matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
- match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
- match 3.14
-integerLiteral(equals(42))
- matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
Note that you cannot directly match a negative numeric literal because the
minus sign is not part of the literal: It is a unary operator whose operand
is the positive numeric literal. Instead, you must use a unaryOperator()
matcher to match the minus sign:
-unaryOperator(hasOperatorName("-"),
- hasUnaryOperand(integerLiteral(equals(13))))
+Given
+ int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
@@ -3130,14 +4168,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isCatchAll0"><pre>Matches a C++ catch statement that has a catch-all handler.
Given
- try {
- // ...
- } catch (int) {
- // ...
- } catch (...) {
- // ...
+ void foo() {
+ try {}
+ catch (int) {}
+ catch (...) {}
}
-cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
+
+The matcher cxxCatchStmt(isCatchAll())
+matches catch (...) {}
+but does not match catch(int)
</pre></td></tr>
@@ -3145,12 +4184,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountAtLeast1"><pre>Checks that a call expression or a constructor call expression has at least
the specified number of arguments (including absent default arguments).
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
void f(int x, int y);
void g(int x, int y, int z);
- f(0, 0);
- g(0, 0, 0);
+ void foo() {
+ f(0, 0);
+ g(0, 0, 0);
+ }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
</pre></td></tr>
@@ -3158,14 +4200,39 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
void f(int x, int y);
- f(0, 0);
+ void foo() {
+ f(0, 0);
+ }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('isListInitialization0')"><a name="isListInitialization0Anchor">isListInitialization</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isListInitialization0"><pre>Matches a constructor call expression which uses list initialization.
+
+Given
+ namespace std {
+ template <typename T>
+ class initializer_list {
+ const T* begin;
+ const T* end;
+ };
+ }
+ template <typename T> class vector {
+ public: vector(std::initializer_list<T>) {}
+ };
+
+ vector<int> a({ 1, 2, 3 });
+ vector<int> b = { 4, 5 };
+ int c[] = { 6, 7 };
+ struct pair { int x; int y; };
+ pair d = { 8, 9 };
+
+The matcher cxxConstructExpr(isListInitialization())
+matches { 4, 5 }.
</pre></td></tr>
@@ -3175,11 +4242,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
void foo() {
- struct point { double x; double y; };
- point pt[2] = { { 1.0, 2.0 } };
+ struct Foo {
+ double x;
+ };
+ auto Val = Foo();
}
-initListExpr(has(cxxConstructExpr(requiresZeroInitialization()))
-will match the implicit array filler for pt[1].
+
+The matcher
+cxxConstructExpr(requiresZeroInitialization())
+matches Foo() because the x member has to be zero initialized.
</pre></td></tr>
@@ -3192,7 +4263,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S(const S &); // #2
S(S &&); // #3
};
-cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3.
+
+The matcher cxxConstructorDecl(isCopyConstructor())
+matches S(const S &),
+but does not match S() or S(S &&).
</pre></td></tr>
@@ -3205,7 +4279,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S(const S &); // #2
S(S &&); // #3
};
-cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3.
+
+The matcher cxxConstructorDecl(isDefaultConstructor())
+matches S()
+but does not match S(const S &); or S(S &&);.
</pre></td></tr>
@@ -3219,8 +4296,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S(S &&) : S() {} // #3
};
S::S() : S(0) {} // #4
-cxxConstructorDecl(isDelegatingConstructor()) will match #3 and #4, but not
-#1 or #2.
+
+The matcher cxxConstructorDecl(isDelegatingConstructor())
+matches S(S &&) : S() {} and S::S() : S(0) {},
+but does not match S() or S(int).
</pre></td></tr>
@@ -3236,15 +4315,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
explicit S(double); // #2
operator int(); // #3
explicit operator bool(); // #4
- explicit(false) S(bool) // # 7
- explicit(true) S(char) // # 8
- explicit(b) S(S) // # 9
+ explicit(false) S(bool); // # 7
+ explicit(true) S(char); // # 8
+ explicit(b) S(float); // # 9
};
- S(int) -> S<true> // #5
- explicit S(double) -> S<false> // #6
-cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9.
-cxxConversionDecl(isExplicit()) will match #4, but not #3.
-cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+ S(int) -> S<true>; // #5
+ explicit S(double) -> S<false>; // #6
+
+The matcher cxxConstructorDecl(isExplicit())
+matches explicit S(double)
+and explicit(true) S(char)
+but does not match S(int);, explicit(false) S(bool); or
+explicit(b) S(float)
+The matcher cxxConversionDecl(isExplicit())
+matches explicit operator bool()
+but does not match operator int().
+The matcher cxxDeductionGuideDecl(isExplicit())
+matches the deduction guide explicit S(double) -> S<false>,
+the implicit copy deduction candiate
+auto (double) -> S<b> and
+the implicitly generated deduction guide for explicit(true) S(char),
+but does not match S(int) -> S<true>.
</pre></td></tr>
@@ -3261,7 +4352,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S(const S &); // #2
S(S &&); // #3
};
-cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2.
+
+The matcher cxxConstructorDecl(isMoveConstructor())
+matches S(S &&)
+but does not match S(); or S(S &&);
</pre></td></tr>
@@ -3277,15 +4371,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
explicit S(double); // #2
operator int(); // #3
explicit operator bool(); // #4
- explicit(false) S(bool) // # 7
- explicit(true) S(char) // # 8
- explicit(b) S(S) // # 9
+ explicit(false) S(bool); // # 7
+ explicit(true) S(char); // # 8
+ explicit(b) S(float); // # 9
};
- S(int) -> S<true> // #5
- explicit S(double) -> S<false> // #6
-cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9.
-cxxConversionDecl(isExplicit()) will match #4, but not #3.
-cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+ S(int) -> S<true>; // #5
+ explicit S(double) -> S<false>; // #6
+
+The matcher cxxConstructorDecl(isExplicit())
+matches explicit S(double)
+and explicit(true) S(char)
+but does not match S(int);, explicit(false) S(bool); or
+explicit(b) S(float)
+The matcher cxxConversionDecl(isExplicit())
+matches explicit operator bool()
+but does not match operator int().
+The matcher cxxDeductionGuideDecl(isExplicit())
+matches the deduction guide explicit S(double) -> S<false>,
+the implicit copy deduction candiate
+auto (double) -> S<b> and
+the implicitly generated deduction guide for explicit(true) S(char),
+but does not match S(int) -> S<true>.
</pre></td></tr>
@@ -3302,8 +4408,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
struct E : B {
E() : B() {}
};
+
+The matcher
cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer()))
- will match E(), but not match D(int).
+matches E() : B() {} and D(int i) : I(i) {}.
+The constructor of D is matched, because it implicitly has a constructor
+initializer for B .
</pre></td></tr>
@@ -3320,8 +4430,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
struct E : B {
E() : B() {}
};
+
+The matcher
cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer()))
- will match D(int), but not match E().
+ will match D(int i) : I(i) {}, but not match E() : B()
+ {}.
</pre></td></tr>
@@ -3330,13 +4443,16 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
code (as opposed to implicitly added by the compiler).
Given
+ struct Bar { explicit Bar(const char*); };
struct Foo {
Foo() { }
Foo(int) : foo_("A") { }
- string foo_;
+ Bar foo_{""};
};
-cxxConstructorDecl(hasAnyConstructorInitializer(isWritten()))
- will match Foo(int), but not Foo()
+
+The matcher
+cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) will
+match Foo(int) : foo_("A") { }, but not Foo() { }
</pre></td></tr>
@@ -3352,15 +4468,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
explicit S(double); // #2
operator int(); // #3
explicit operator bool(); // #4
- explicit(false) S(bool) // # 7
- explicit(true) S(char) // # 8
- explicit(b) S(S) // # 9
+ explicit(false) S(bool); // # 7
+ explicit(true) S(char); // # 8
+ explicit(b) S(float); // # 9
};
- S(int) -> S<true> // #5
- explicit S(double) -> S<false> // #6
-cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9.
-cxxConversionDecl(isExplicit()) will match #4, but not #3.
-cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+ S(int) -> S<true>; // #5
+ explicit S(double) -> S<false>; // #6
+
+The matcher cxxConstructorDecl(isExplicit())
+matches explicit S(double)
+and explicit(true) S(char)
+but does not match S(int);, explicit(false) S(bool); or
+explicit(b) S(float)
+The matcher cxxConversionDecl(isExplicit())
+matches explicit operator bool()
+but does not match operator int().
+The matcher cxxDeductionGuideDecl(isExplicit())
+matches the deduction guide explicit S(double) -> S<false>,
+the implicit copy deduction candiate
+auto (double) -> S<b> and
+the implicitly generated deduction guide for explicit(true) S(char),
+but does not match S(int) -> S<true>.
</pre></td></tr>
@@ -3382,7 +4510,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S<T> s;
s.mem();
}
-cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()`
+
+The matcher cxxDependentScopeMemberExpr(hasMemberName("mem"))
+matches s.mem.
</pre></td></tr>
@@ -3401,14 +4531,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
};
template <class T>
class Z {
- void x() { this->m; }
+ void x() {
+ this->m;
+ this->t;
+ this->t->m;
+ }
+ int m;
+ T* t;
};
-memberExpr(isArrow())
- matches this->x, x, y.x, a, this->b
-cxxDependentScopeMemberExpr(isArrow())
- matches this->m
-unresolvedMemberExpr(isArrow())
- matches this->f<T>, f<T>
+
+The matcher memberExpr(isArrow())
+matches this->x, x, a,
+this->b, this->m and two times this->t,
+once for the standalone member expression, and once for the member
+expression that later accesses m .
+Additionally, it does not match this->t->t.
+The matcher cxxDependentScopeMemberExpr(isArrow())
+matches this->t->m, but not this->m or this->t.
+The matcher unresolvedMemberExpr(isArrow())
+matches this->f<T>, f<T>
</pre></td></tr>
@@ -3432,19 +4573,20 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S<T> s;
s.mem();
}
-The matcher
- at code
-cxxDependentScopeMemberExpr(
- hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+
+The matcher cxxDependentScopeMemberExpr(
+ hasObjectExpression(declRefExpr(hasType(
+ elaboratedType(namesType(templateSpecializationType(
hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has(
cxxMethodDecl(hasName("mem")).bind("templMem")
)))))
- )))),
+ )))
+ ))),
memberHasSameNameAsBoundNode("templMem")
- )
- at endcode
-first matches and binds the @c mem member of the @c S template, then
-compares its name to the usage in @c s.mem() in the @c x function template
+)
+matches s.mem, with the inner matcher
+cxxMethodDecl(hasName("mem")) matching
+void mem() of the S template.
</pre></td></tr>
@@ -3452,23 +4594,29 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperatorName3"><pre>Matches the operator Name of operator expressions and fold expressions
(binary or unary).
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isBinaryFold0')"><a name="isBinaryFold0Anchor">isBinaryFold</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isBinaryFold0"><pre>Matches binary fold expressions, i.e. fold expressions with an initializer.
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(isBinaryFold()))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -3478,14 +4626,17 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
auto multiply(Args... args) {
return (args * ...);
}
+
+
+The matcher cxxFoldExpr(isBinaryFold())
+matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isLeftFold0')"><a name="isLeftFold0Anchor">isLeftFold</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isLeftFold0"><pre>Matches left-folding fold expressions.
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(isLeftFold()))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -3495,14 +4646,17 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
+
+
+The matcher cxxFoldExpr(isLeftFold())
+matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isRightFold0')"><a name="isRightFold0Anchor">isRightFold</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isRightFold0"><pre>Matches right-folding fold expressions.
-Example matches `(args * ... * 1)`
- (matcher = cxxFoldExpr(isRightFold()))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -3512,6 +4666,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
+
+
+The matcher cxxFoldExpr(isRightFold())
+matches (args * ... * 1).
</pre></td></tr>
@@ -3519,8 +4677,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isUnaryFold0"><pre>Matches unary fold expressions, i.e. fold expressions without an
initializer.
-Example matches `(args * ...)`
- (matcher = cxxFoldExpr(isUnaryFold()))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -3530,6 +4687,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
auto multiply(Args... args) {
return (args * ...);
}
+
+
+The matcher cxxFoldExpr(isUnaryFold())
+matches (args * ...), but not (0 + ... + args).
</pre></td></tr>
@@ -3542,7 +4703,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void bar();
};
-cxxMethodDecl(isConst()) matches A::foo() but not A::bar()
+
+The matcher cxxMethodDecl(isConst())
+matches foo but not bar
</pre></td></tr>
@@ -3556,8 +4719,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
A &operator=(A &&);
};
-cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not
-the second one.
+
+The matcher cxxMethodDecl(isCopyAssignmentOperator())
+matches A &operator=(const A &)
+but does not match A &operator=(A &&)
</pre></td></tr>
@@ -3573,15 +4738,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
int operator+(int);
};
-cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two
-methods but not the last two.
+
+The matcher cxxMethodDecl(isExplicitObjectMemberFunction())
+matches int operator-(this A, int) and
+void fun(this A &&self),
+but not static int operator()(int) or
+int operator+(int).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isFinal1')"><a name="isFinal1Anchor">isFinal</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isFinal1"><pre>Matches if the given method or class declaration is final.
-Given:
+Given
class A final {};
struct B {
@@ -3591,7 +4760,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
struct C : B {
void f() final;
};
-matches A and C::f, but not B, C, or B::f
+
+The matcher cxxRecordDecl(isFinal())
+matches A,
+but does not match B or C.
+The matcher cxxMethodDecl(isFinal())
+matches void f() final in C ,
+but does not match virtual void f() in B .
</pre></td></tr>
@@ -3605,8 +4780,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
A &operator=(A &&);
};
-cxxMethodDecl(isMoveAssignmentOperator()) matches the second method but not
-the first one.
+
+The matcher cxxMethodDecl(isMoveAssignmentOperator())
+matches A &operator=(A &&)
+but does not match A &operator=(const A &)
</pre></td></tr>
@@ -3620,9 +4797,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
};
class B : public A {
public:
- virtual void x();
+ void x() override;
};
- matches B::x
+
+The matcher cxxMethodDecl(isOverride())
+ matches void x() override
</pre></td></tr>
@@ -3634,7 +4813,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
public:
virtual void x() = 0;
};
- matches A::x
+
+The matcher cxxMethodDecl(isPure())
+matches virtual void x() = 0
</pre></td></tr>
@@ -3647,7 +4828,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
S(const S &) = default; // #2
S(S &&) = delete; // #3
};
-cxxConstructorDecl(isUserProvided()) will match #1, but not #2 or #3.
+
+The matcher cxxConstructorDecl(isUserProvided())
+will match S(), but not S &) = default} or
+&&) = delete}
</pre></td></tr>
@@ -3655,16 +4839,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isVirtual0"><pre>Matches declarations of virtual methods and C++ base specifers that specify
virtual inheritance.
-Example:
+Given
class A {
public:
virtual void x(); // matches x
};
-Example:
- class Base {};
- class DirectlyDerived : virtual Base {}; // matches Base
- class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+ struct Base {};
+ struct DirectlyDerived : virtual Base {}; // matches Base
+ struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -3682,17 +4873,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
public:
void x();
};
- matches A::x but not B::x
+
+The matcher cxxMethodDecl(isVirtualAsWritten())
+matches virtual void x() of A,
+but does not match x()} of B .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('isArray0')"><a name="isArray0Anchor">isArray</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isArray0"><pre>Matches array new expressions.
-Given:
+Given
+ struct MyClass { int x; };
MyClass *p1 = new MyClass[10];
-cxxNewExpr(isArray())
- matches the expression 'new MyClass[10]'.
+
+The matcher cxxNewExpr(isArray())
+matches new MyClass[10].
</pre></td></tr>
@@ -3700,9 +4896,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyOperatorName1"><pre>Matches operator expressions (binary or unary) that have any of the
specified names.
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
hasAnyOperatorName("+", "-")
- Is equivalent to
- anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+ hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+void bar(bool a, bool b) {
+ a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
</pre></td></tr>
@@ -3713,6 +4926,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
"operator" prefix: e.g. "<<".
hasAnyOverloadedOperatorName("+", "-")
+
+Given
+ struct Point { double x; double y; };
+ Point operator+(const Point&, const Point&);
+ Point operator-(const Point&, const Point&);
+
+ Point sub(Point a, Point b) {
+ return b - a;
+ }
+
+
+The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")),
+which is equivalent to
+functionDecl(anyOf(hasAnyOverloadedOperatorName("+"),
+hasOverloadedOperatorName("-"))),
+matches Point operator+(const Point&, const Point&) and
+Point operator-(const Point&, const Point&).
+The matcher
+cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")),
+which is equivalent to
+cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"),
+hasOverloadedOperatorName("-"))),
+matches b - a.
+
Is equivalent to
anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-"))
</pre></td></tr>
@@ -3722,15 +4959,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions and fold expressions
(binary or unary).
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
</pre></td></tr>
@@ -3740,16 +4984,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Matches overloaded operator names specified in strings without the
"operator" prefix: e.g. "<<".
-Given:
- class A { int operator*(); };
+Given
+ struct A { int operator*(); };
const A &operator<<(const A &a, const A &b);
- A a;
- a << a; // <-- This matches
+ void f(A a) {
+ a << a; // <-- This matches
+ }
-cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
-specified line and
+
+The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))
+matches a << a.
+The matcher
cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
-matches the declaration of A.
+matches struct A { int operator*(); }.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
</pre></td></tr>
@@ -3758,47 +5005,104 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('isAssignmentOperator1')"><a name="isAssignmentOperator1Anchor">isAssignmentOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isAssignmentOperator1"><pre>Matches all kinds of assignment operators.
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
-Example 2: matches s1 = s2
- (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
struct S { S& operator=(const S&); };
void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('isComparisonOperator1')"><a name="isComparisonOperator1Anchor">isComparisonOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isComparisonOperator1"><pre>Matches comparison operators.
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
-Example 2: matches s1 < s2
- (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
struct S { bool operator<(const S& other); };
void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasDefinition0')"><a name="hasDefinition0Anchor">hasDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDefinition0"><pre>Matches a class declaration that is defined.
-Example matches x (matcher = cxxRecordDecl(hasDefinition()))
+Given
class x {};
class y;
+
+The matcher cxxRecordDecl(hasDefinition())
+matches class x {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom2')"><a name="isDerivedFrom2Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="isDerivedFrom2"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+ class Foo {};
+ typedef Foo Alias;
+ class Bar : public Alias {}; // derived from Alias, which is a
+ // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+ @interface NSObject @end
+ @interface Bar : NSObject @end
+
+
+Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDirectlyDerivedFrom2')"><a name="isDirectlyDerivedFrom2Anchor">isDirectlyDerivedFrom</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="isDirectlyDerivedFrom2"><pre>Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+ struct Base {};
+ struct DirectlyDerived : public Base {};
+ struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
</pre></td></tr>
@@ -3809,8 +5113,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> void A(T t) { }
template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
+
+The matcher functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization template<> void A(int N) { }.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
</pre></td></tr>
@@ -3819,7 +5124,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isFinal0')"><a name="isFinal0Anchor">isFinal</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isFinal0"><pre>Matches if the given method or class declaration is final.
-Given:
+Given
class A final {};
struct B {
@@ -3829,24 +5134,46 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
struct C : B {
void f() final;
};
-matches A and C::f, but not B, C, or B::f
+
+The matcher cxxRecordDecl(isFinal())
+matches A,
+but does not match B or C.
+The matcher cxxMethodDecl(isFinal())
+matches void f() final in C ,
+but does not match virtual void f() in B .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isLambda0')"><a name="isLambda0Anchor">isLambda</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isLambda0"><pre>Matches the generated class of lambda expressions.
-Given:
+Given
auto x = []{};
-cxxRecordDecl(isLambda()) matches the implicit class declaration of
-decltype(x)
+
+The matcher varDecl(hasType(cxxRecordDecl(isLambda())))
+matches auto x = []{}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom2')"><a name="isSameOrDerivedFrom2Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom2"><pre>Overloaded method as shortcut for
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom2"><pre>Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
isSameOrDerivedFrom(hasName(...)).
+
+Given
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
</pre></td></tr>
@@ -3855,18 +5182,36 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
member variable template instantiations.
Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-or
- template <typename T> class X {}; class A {}; extern template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
+ template <typename T> class X {};
+ class A {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches class X<class A>.
+ template <typename T> class X {};
+ class A {};
+ template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches template class X<A>
+ template <typename T> class X {};
+ class A {};
+ extern template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches extern template class X<A>
But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ template <typename T> class X {};
+ class A {};
+ template <> class X<A> {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
does not match, as X<A> is an explicit template specialization.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
@@ -3877,9 +5222,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyOperatorName2"><pre>Matches operator expressions (binary or unary) that have any of the
specified names.
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
hasAnyOperatorName("+", "-")
- Is equivalent to
- anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+ hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+void bar(bool a, bool b) {
+ a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
</pre></td></tr>
@@ -3887,43 +5249,62 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperatorName2"><pre>Matches the operator Name of operator expressions and fold expressions
(binary or unary).
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('isAssignmentOperator2')"><a name="isAssignmentOperator2Anchor">isAssignmentOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isAssignmentOperator2"><pre>Matches all kinds of assignment operators.
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
-Example 2: matches s1 = s2
- (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
struct S { S& operator=(const S&); };
void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('isComparisonOperator2')"><a name="isComparisonOperator2Anchor">isComparisonOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isComparisonOperator2"><pre>Matches comparison operators.
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
if (a == b)
a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
-Example 2: matches s1 < s2
- (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
struct S { bool operator<(const S& other); };
void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
</pre></td></tr>
@@ -3931,12 +5312,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountAtLeast2"><pre>Checks that a call expression or a constructor call expression has at least
the specified number of arguments (including absent default arguments).
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
void f(int x, int y);
void g(int x, int y, int z);
- f(0, 0);
- g(0, 0, 0);
+ void foo() {
+ f(0, 0);
+ g(0, 0, 0);
+ }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
</pre></td></tr>
@@ -3944,9 +5328,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
void f(int x, int y);
- f(0, 0);
+ void foo() {
+ f(0, 0);
+ }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
</pre></td></tr>
@@ -3954,12 +5342,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountAtLeast0"><pre>Checks that a call expression or a constructor call expression has at least
the specified number of arguments (including absent default arguments).
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
void f(int x, int y);
void g(int x, int y, int z);
- f(0, 0);
- g(0, 0, 0);
+ void foo() {
+ f(0, 0);
+ g(0, 0, 0);
+ }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
</pre></td></tr>
@@ -3967,16 +5358,20 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountIs0"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
void f(int x, int y);
- f(0, 0);
+ void foo() {
+ f(0, 0);
+ }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('usesADL0')"><a name="usesADL0Anchor">usesADL</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="usesADL0"><pre>Matches call expressions which were resolved using ADL.
-Example matches y(x) but not y(42) or NS::y(x).
+Given
namespace NS {
struct X {};
void y(X);
@@ -3992,15 +5387,20 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
using NS::y;
y(x); // Found by both unqualified lookup and ADL, doesn't match
}
+
+
+The matcher callExpr(usesADL())
+matches y(x), but not y(42) or NS::y(x).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>></td><td class="name" onclick="toggle('hasCastKind0')"><a name="hasCastKind0Anchor">hasCastKind</a></td><td>CastKind Kind</td></tr>
<tr><td colspan="4" class="doc" id="hasCastKind0"><pre>Matches casts that has a given cast kind.
-Example: matches the implicit cast around 0
-(matcher = castExpr(hasCastKind(CK_NullToPointer)))
+Given
int *p = 0;
+The matcher castExpr(hasCastKind(CK_NullToPointer))
+matches the implicit cast around 0
If the matcher is use from clang-query, CastKind parameter
should be passed as a quoted string. e.g., hasCastKind("CK_NullToPointer").
@@ -4015,22 +5415,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value of type ValueT.
Given
+void f(char, bool, double, int);
+void foo() {
f('false, 3.14, 42);
-characterLiteral(equals(0))
- matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
- match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
- match 3.14
-integerLiteral(equals(42))
- matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
Note that you cannot directly match a negative numeric literal because the
minus sign is not part of the literal: It is a unary operator whose operand
is the positive numeric literal. Instead, you must use a unaryOperator()
matcher to match the minus sign:
-unaryOperator(hasOperatorName("-"),
- hasUnaryOperand(integerLiteral(equals(13))))
+Given
+ int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
@@ -4051,8 +5456,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> struct C {};
C<int> c;
+
+The matcher
classTemplateSpecializationDecl(templateArgumentCountIs(1))
- matches C<int>.
+matches struct C<int>.
</pre></td></tr>
@@ -4061,9 +5468,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
child statements.
Example: Given
+void foo() {
{ for (;;) {} }
-compoundStmt(statementCountIs(0)))
- matches '{}'
+}
+The matcher compoundStmt(statementCountIs(0))
+{}
but does not match the outer compound statement.
</pre></td></tr>
@@ -4078,10 +5487,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
char *s = "abcd";
wchar_t *ws = L"abcd";
char *w = "a";
-constantArrayType(hasSize(42))
- matches "int a[42]" and "int b[2 * 21]"
-stringLiteral(hasSize(4))
- matches "abcd", L"abcd"
+
+The matcher constantArrayType(hasSize(42))
+matches int[42] twice.
+The matcher stringLiteral(hasSize(4))
+matches "abcd" and L"abcd".
</pre></td></tr>
@@ -4089,12 +5499,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="declCountIs0"><pre>Matches declaration statements that contain a specific number of
declarations.
-Example: Given
- int a, b;
- int c;
- int d = 2, e;
-declCountIs(2)
- matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+Given
+ void foo() {
+ int a, b;
+ int c;
+ int d = 2, e;
+ }
+The matcher declStmt(declCountIs(2))
+matches int a, b; and int d = 2, e;,
+but does not match int c;
</pre></td></tr>
@@ -4105,10 +5518,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
class X { int a; int b; };
-cxxRecordDecl(
+
+The matcher cxxRecordDecl(
has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
+ matches X, as a and b have the same type.
Note that when multiple matches are involved via forEach* matchers,
equalsBoundNodes acts as a filter.
@@ -4132,10 +5546,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAttr0"><pre>Matches declaration that has a given attribute.
Given
- __attribute__((device)) void f() { ... }
-decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
-f. If the matcher is used from clang-query, attr::Kind parameter should be
-passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+ __attribute__((device)) void f() {}
+
+The matcher decl(hasAttr(clang::attr::CUDADevice))
+matches f.
+If the matcher is used from clang-query, attr::Kind
+parameter should be passed as a quoted string. e.g.,
+hasAttr("attr::CUDADevice").
</pre></td></tr>
@@ -4144,6 +5561,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Does not match if only part of the statement is expanded from that macro or
if
diff erent parts of the statement are expanded from
diff erent
appearances of the macro.
+
+Given
+ #define A 0
+ #define B A
+ int c = B;
+
+The matcher integerLiteral(isExpandedFromMacro("A"))
+matches the literal expanded at the initializer B of the variable
+c .
</pre></td></tr>
@@ -4151,12 +5577,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isExpansionInFileMatching0"><pre>Matches AST nodes that were expanded within files whose name is
partially matching a given regex.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
+Given the headers Y.h
+ #pragma once
+ typedef int my_y_int;
+and X.h
+ #pragma once
+ typedef int my_x_int;
+and the source code
+ #include "X.h"
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_x_int b = 1;
+ my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
@@ -4169,12 +5608,18 @@ <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('isExpansionInMainFile0')"><a name="isExpansionInMainFile0Anchor">isExpansionInMainFile</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInMainFile0"><pre>Matches AST nodes that were expanded within the main-file.
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
+Given the header Y.h
+ #pragma once
+ typedef int my_header_int;
+and the source file
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -4183,12 +5628,17 @@ <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('isExpansionInSystemHeader0')"><a name="isExpansionInSystemHeader0Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader0"><pre>Matches AST nodes that were expanded within system-header-files.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+ #pragma once
+ int header();
+and the source code
#include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
+ static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -4197,6 +5647,20 @@ <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('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches an entity that has been implicitly added by the compiler (e.g.
implicit default/copy constructors).
+
+Given
+ struct S {};
+ void f(S obj) {
+ S copy = obj;
+ [&](){ return copy; };
+ }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+ lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
</pre></td></tr>
@@ -4214,11 +5678,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
namespace {
class vector {}; // #2
namespace foo {
- class vector{}; // #3
+ class vector {}; // #3
}
}
-cxxRecordDecl(hasName("vector"), isInAnonymousNamespace()) will match
-#1, #2 and #3.
+
+The matcher cxxRecordDecl(hasName("vector"),
+ isInAnonymousNamespace())
+matches vector,
+twice per declaration at #1, #2 and #3.
</pre></td></tr>
@@ -4241,7 +5708,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
}
}
}
-cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1.
+
+The matcher cxxRecordDecl(hasName("vector"), isInStdNamespace())
+matches class vector {} inside of namespace std.
</pre></td></tr>
@@ -4251,10 +5720,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> void A(T t) { T i; }
- A(0);
- A(0U);
-functionDecl(isInstantiated())
- matches 'A(int) {...};' and 'A(unsigned) {...}'.
+ void foo() {
+ A(0);
+ A(0U);
+ }
+
+The matcher functionDecl(isInstantiated())
+matches the two instantiations of void A(T t) { T i; } that
+are generated for int , and for int}.
</pre></td></tr>
@@ -4262,16 +5735,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations and C++ base specifers that specify private
inheritance.
-Examples:
+Given
class C {
public: int a;
protected: int b;
- private: int c; // fieldDecl(isPrivate()) matches 'c'
+ private: int c;
};
+The matcher fieldDecl(isPrivate())
+matches c.
+
struct Base {};
- struct Derived1 : private Base {}; // matches 'Base'
- class Derived2 : Base {}; // matches 'Base'
+ struct Derived1 : private Base {}; // Base
+ class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
</pre></td></tr>
@@ -4279,15 +5761,24 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isProtected0"><pre>Matches protected C++ declarations and C++ base specifers that specify
protected inheritance.
-Examples:
+Given
class C {
public: int a;
- protected: int b; // fieldDecl(isProtected()) matches 'b'
+ protected: int b;
private: int c;
};
+The matcher fieldDecl(isProtected())
+matches b.
+
class Base {};
- class Derived : protected Base {}; // matches 'Base'
+ class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
</pre></td></tr>
@@ -4295,16 +5786,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isPublic0"><pre>Matches public C++ declarations and C++ base specifers that specify public
inheritance.
-Examples:
+Given
class C {
- public: int a; // fieldDecl(isPublic()) matches 'a'
+ public: int a;
protected: int b;
private: int c;
};
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
class Base {};
- class Derived1 : public Base {}; // matches 'Base'
- struct Derived2 : Base {}; // matches 'Base'
+ class Derived1 : public Base {};
+ struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
</pre></td></tr>
@@ -4313,20 +5814,24 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
a specific number of designators.
Example: Given
- point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
- point ptarray2[10] = { [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 };
-designatorCountIs(2)
- matches '{ [2].y = 1.0, [0].x = 1.0 }',
- but not '{ [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }'.
+ struct point2 { double x; double y; };
+ struct point2 ptarray[10] = { [0].x = 1.0 };
+ struct point2 pt = { .x = 2.0 };
+
+The matcher designatedInitExpr(designatorCountIs(2))
+matches [0].x = 1.0, but not .x = 2.0.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1EnumDecl.html">EnumDecl</a>></td><td class="name" onclick="toggle('isScoped0')"><a name="isScoped0Anchor">isScoped</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isScoped0"><pre>Matches C++11 scoped enum declaration.
-Example matches Y (matcher = enumDecl(isScoped()))
+Given
enum X {};
enum class Y {};
+
+The matcher enumDecl(isScoped())
+matches enum class Y {}
</pre></td></tr>
@@ -4340,8 +5845,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
sizeof is known (std::size_t) and therefore the size of the outer
sizeof is known.
template<typename T>
- void f(T x, T y) { sizeof(sizeof(T() + T()); }
-expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T())
+ void f(T x, T y) { sizeof(T() + T()); }
+
+The matcher expr(isInstantiationDependent())
+matches sizeof(T() + T()),
+(T() + T()),
+T() + T() and T().
</pre></td></tr>
@@ -4355,7 +5864,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void add(T x, int y) {
x + y;
}
-expr(isTypeDependent()) matches x + y
+
+The matcher expr(isTypeDependent())
+matches x + y and x.
</pre></td></tr>
@@ -4366,7 +5877,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
For example, the array bound of "Chars" in the following example is
value-dependent.
template<int Size> int f() { return Size; }
-expr(isValueDependent()) matches return Size
+
+The matcher expr(isValueDependent())
+matches the return value Size.
</pre></td></tr>
@@ -4374,16 +5887,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="nullPointerConstant0"><pre>Matches expressions that resolve to a null pointer constant, such as
GNU's __null, C++11's nullptr, or C's NULL macro.
-Given:
+Given
+ #define NULL 0
void *v1 = NULL;
void *v2 = nullptr;
void *v3 = __null; // GNU extension
char *cp = (char *)0;
int *ip = 0;
int i = 0;
-expr(nullPointerConstant())
- matches the initializer for v1, v2, v3, cp, and ip. Does not match the
- initializer for i.
+
+The matcher expr(nullPointerConstant())
+matches the initializer NULL of v1,
+matches the initializer nullptr of v2,
+matches the initializer __null of v3,
+matches the initializer 0 of cp and
+matches the initializer 0 of ip,
+but does not match the initializer i of i.
</pre></td></tr>
@@ -4397,8 +5916,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
int b : 4;
int c : 2;
};
-fieldDecl(hasBitWidth(2))
- matches 'int a;' and 'int c;' but not 'int b;'.
+
+The matcher fieldDecl(hasBitWidth(2))
+matches a and c,
+but not b.
</pre></td></tr>
@@ -4410,8 +5931,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
int a : 2;
int b;
};
-fieldDecl(isBitField())
- matches 'int a;' but not 'int b;'.
+
+The matcher fieldDecl(isBitField())
+matches a,
+but does not match b.
</pre></td></tr>
@@ -4419,22 +5942,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value of type ValueT.
Given
+void f(char, bool, double, int);
+void foo() {
f('false, 3.14, 42);
-characterLiteral(equals(0))
- matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
- match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
- match 3.14
-integerLiteral(equals(42))
- matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
Note that you cannot directly match a negative numeric literal because the
minus sign is not part of the literal: It is a unary operator whose operand
is the positive numeric literal. Instead, you must use a unaryOperator()
matcher to match the minus sign:
-unaryOperator(hasOperatorName("-"),
- hasUnaryOperand(integerLiteral(equals(13))))
+Given
+ int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
@@ -4452,6 +5980,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
"operator" prefix: e.g. "<<".
hasAnyOverloadedOperatorName("+", "-")
+
+Given
+ struct Point { double x; double y; };
+ Point operator+(const Point&, const Point&);
+ Point operator-(const Point&, const Point&);
+
+ Point sub(Point a, Point b) {
+ return b - a;
+ }
+
+
+The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")),
+which is equivalent to
+functionDecl(anyOf(hasAnyOverloadedOperatorName("+"),
+hasOverloadedOperatorName("-"))),
+matches Point operator+(const Point&, const Point&) and
+Point operator-(const Point&, const Point&).
+The matcher
+cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")),
+which is equivalent to
+cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"),
+hasOverloadedOperatorName("-"))),
+matches b - a.
+
Is equivalent to
anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-"))
</pre></td></tr>
@@ -4460,17 +6012,32 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasDynamicExceptionSpec0')"><a name="hasDynamicExceptionSpec0Anchor">hasDynamicExceptionSpec</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDynamicExceptionSpec0"><pre>Matches functions that have a dynamic exception specification.
-Given:
- void f();
- void g() noexcept;
- void h() noexcept(true);
- void i() noexcept(false);
- void j() throw();
- void k() throw(int);
- void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
- functionProtoType(hasDynamicExceptionSpec())
- match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+ void f(int);
+ void g(int) noexcept;
+ void h(int) noexcept(true);
+ void i(int) noexcept(false);
+ void j(int) throw();
+ void k(int) throw(int);
+ void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
</pre></td></tr>
@@ -4480,16 +6047,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Matches overloaded operator names specified in strings without the
"operator" prefix: e.g. "<<".
-Given:
- class A { int operator*(); };
+Given
+ struct A { int operator*(); };
const A &operator<<(const A &a, const A &b);
- A a;
- a << a; // <-- This matches
+ void f(A a) {
+ a << a; // <-- This matches
+ }
+
-cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
-specified line and
+The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))
+matches a << a.
+The matcher
cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
-matches the declaration of A.
+matches struct A { int operator*(); }.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
</pre></td></tr>
@@ -4498,9 +6068,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasTrailingReturn0')"><a name="hasTrailingReturn0Anchor">hasTrailingReturn</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasTrailingReturn0"><pre>Matches a function declared with a trailing return type.
-Example matches Y (matcher = functionDecl(hasTrailingReturn()))
+Given
int X() {}
auto Y() -> int {}
+
+The matcher functionDecl(hasTrailingReturn())
+matches auto Y() -> int {}.
</pre></td></tr>
@@ -4508,15 +6081,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isConsteval0"><pre>Matches consteval function declarations and if consteval/if ! consteval
statements.
-Given:
+Given
consteval int a();
void b() { if consteval {} }
void c() { if ! consteval {} }
void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
- matches the declaration of "int a()".
-ifStmt(isConsteval())
- matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
</pre></td></tr>
@@ -4524,27 +6100,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isConstexpr1"><pre>Matches constexpr variable and function declarations,
and if constexpr.
-Given:
+Given
constexpr int foo = 42;
constexpr int bar();
void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
- matches the declaration of foo.
-functionDecl(isConstexpr())
- matches the declaration of bar.
-ifStmt(isConstexpr())
- matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
</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('isDefaulted0')"><a name="isDefaulted0Anchor">isDefaulted</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDefaulted0"><pre>Matches defaulted function declarations.
-Given:
+Given
class A { ~A(); };
class B { ~B() = default; };
-functionDecl(isDefaulted())
- matches the declaration of ~B, but not ~A.
+
+The matcher functionDecl(isDefaulted())
+ matches ~B() = default,
+but does not match ~A().
</pre></td></tr>
@@ -4558,6 +6137,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
extern int vb; // Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); // Doesn't match, as it has no body.
+
+The matcher tagDecl(isDefinition())
+matches A
+The matcher varDecl(isDefinition())
+matches va
+The matcher functionDecl(isDefinition())
+matches fa
+
@interface X
- (void)ma; // Doesn't match, interface is declaration.
@end
@@ -4565,6 +6152,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
- (void)ma {}
@end
+The matcher objcMethodDecl(isDefinition())
+matches - (void)ma {}
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>>
</pre></td></tr>
@@ -4573,11 +6163,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDeleted0')"><a name="isDeleted0Anchor">isDeleted</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDeleted0"><pre>Matches deleted function declarations.
-Given:
+Given
void Func();
void DeletedFunc() = delete;
-functionDecl(isDeleted())
- matches the declaration of DeletedFunc, but not Func.
+
+The matcher functionDecl(isDeleted())
+matches DeletedFunc,
+but does not match Func.
</pre></td></tr>
@@ -4588,8 +6180,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> void A(T t) { }
template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
+
+The matcher functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization template<> void A(int N) { }.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
</pre></td></tr>
@@ -4598,17 +6191,21 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function or variable declarations.
-Given:
+Given
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
extern "C" int x = 1;
extern "C" int y = 2;
int z = 3;
-functionDecl(isExternC())
- matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
- matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
</pre></td></tr>
@@ -4623,15 +6220,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
inline namespace m {}
}
inline int Foo = 5;
-functionDecl(isInline()) will match ::f().
-namespaceDecl(isInline()) will match n::m.
-varDecl(isInline()) will match Foo;
+
+The matcher functionDecl(isInline()) matches f.
+The matcher namespaceDecl(isInline()) matches m.
+The matcher varDecl(isInline()) matches Foo
</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('isMain0')"><a name="isMain0Anchor">isMain</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isMain0"><pre>Determines whether the function is "main", which is the entry point
into an executable program.
+
+Given
+ void f();
+ int main() {}
+
+The matcher functionDecl(isMain()) matches int main() {}.
</pre></td></tr>
@@ -4643,23 +6247,38 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
[[noreturn]] void a();
__attribute__((noreturn)) void b();
struct c { [[noreturn]] c(); };
-functionDecl(isNoReturn())
- matches all of those except
- void nope();
+
+The matcher functionDecl(isNoReturn())
+match a, b
+and c
+but do not match nope
</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('isNoThrow0')"><a name="isNoThrow0Anchor">isNoThrow</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isNoThrow0"><pre>Matches functions that have a non-throwing exception specification.
-Given:
- void f();
- void g() noexcept;
- void h() throw();
- void i() throw(int);
- void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
- match the declarations of g, and h, but not f, i or j.
+Given
+ void f(int);
+ void g(int) noexcept;
+ void h(int) noexcept(false);
+ void i(int) throw();
+ void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
</pre></td></tr>
@@ -4667,15 +6286,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isStaticStorageClass0"><pre>Matches variable/function declarations that have "static" storage
class specifier ("static" keyword) written in the source.
-Given:
+Given
static void f() {}
static int i = 0;
extern int j;
int k;
-functionDecl(isStaticStorageClass())
- matches the function declaration f.
-varDecl(isStaticStorageClass())
- matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+ matches f
+The matcher varDecl(isStaticStorageClass())
+ matches i
</pre></td></tr>
@@ -4684,18 +6303,36 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
member variable template instantiations.
Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-or
- template <typename T> class X {}; class A {}; extern template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
+ template <typename T> class X {};
+ class A {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches class X<class A>.
+ template <typename T> class X {};
+ class A {};
+ template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches template class X<A>
+ template <typename T> class X {};
+ class A {};
+ extern template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches extern template class X<A>
But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ template <typename T> class X {};
+ class A {};
+ template <> class X<A> {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
does not match, as X<A> is an explicit template specialization.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
@@ -4711,17 +6348,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void g(int);
template <typename... Ts> void h(Ts...);
void i();
+
+The matcher functionDecl(isVariadic())
+matches void f(...),
+but does not match void g(int),
+template <typename... Ts> void h(Ts...),
+or void i().
</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('isWeak0')"><a name="isWeak0Anchor">isWeak</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isWeak0"><pre>Matches weak function declarations.
-Given:
- void foo() __attribute__((__weakref__("__foo")));
- void bar();
-functionDecl(isWeak())
- matches the weak declaration "foo", but not "bar".
+Given
+ static void f();
+ void g() __attribute__((weak));
+The matcher functionDecl(isWeak())
+ matches the weak declaration
+void g() __attribute__((weak)),
+but does not match static void foo_v1().
</pre></td></tr>
@@ -4735,43 +6380,71 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void h(int i, int j);
void j(int i);
void k(int x, int y, int z, ...);
-functionDecl(parameterCountIs(2))
- matches g and h
-functionProtoType(parameterCountIs(2))
- matches g and h
-functionProtoType(parameterCountIs(3))
- matches k
+The matcher functionDecl(parameterCountIs(2))
+matches g and h
+The matcher functionProtoType(parameterCountIs(1))
+matches the type void (int) of f and j.
+The matcher functionProtoType(parameterCountIs(3)) matches the
+type void (int, int, int, ...) of k.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionProtoType.html">FunctionProtoType</a>></td><td class="name" onclick="toggle('hasDynamicExceptionSpec1')"><a name="hasDynamicExceptionSpec1Anchor">hasDynamicExceptionSpec</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDynamicExceptionSpec1"><pre>Matches functions that have a dynamic exception specification.
-Given:
- void f();
- void g() noexcept;
- void h() noexcept(true);
- void i() noexcept(false);
- void j() throw();
- void k() throw(int);
- void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
- functionProtoType(hasDynamicExceptionSpec())
- match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+ void f(int);
+ void g(int) noexcept;
+ void h(int) noexcept(true);
+ void i(int) noexcept(false);
+ void j(int) throw();
+ void k(int) throw(int);
+ void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionProtoType.html">FunctionProtoType</a>></td><td class="name" onclick="toggle('isNoThrow1')"><a name="isNoThrow1Anchor">isNoThrow</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isNoThrow1"><pre>Matches functions that have a non-throwing exception specification.
-Given:
- void f();
- void g() noexcept;
- void h() throw();
- void i() throw(int);
- void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
- match the declarations of g, and h, but not f, i or j.
+Given
+ void f(int);
+ void g(int) noexcept;
+ void h(int) noexcept(false);
+ void i(int) throw();
+ void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
</pre></td></tr>
@@ -4785,12 +6458,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void h(int i, int j);
void j(int i);
void k(int x, int y, int z, ...);
-functionDecl(parameterCountIs(2))
- matches g and h
-functionProtoType(parameterCountIs(2))
- matches g and h
-functionProtoType(parameterCountIs(3))
- matches k
+The matcher functionDecl(parameterCountIs(2))
+matches g and h
+The matcher functionProtoType(parameterCountIs(1))
+matches the type void (int) of f and j.
+The matcher functionProtoType(parameterCountIs(3)) matches the
+type void (int, int, int, ...) of k.
</pre></td></tr>
@@ -4798,15 +6471,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isConsteval1"><pre>Matches consteval function declarations and if consteval/if ! consteval
statements.
-Given:
+Given
consteval int a();
void b() { if consteval {} }
void c() { if ! consteval {} }
void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
- matches the declaration of "int a()".
-ifStmt(isConsteval())
- matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
</pre></td></tr>
@@ -4814,16 +6490,17 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isConstexpr2"><pre>Matches constexpr variable and function declarations,
and if constexpr.
-Given:
+Given
constexpr int foo = 42;
constexpr int bar();
void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
- matches the declaration of foo.
-functionDecl(isConstexpr())
- matches the declaration of bar.
-ifStmt(isConstexpr())
- matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
</pre></td></tr>
@@ -4835,22 +6512,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value of type ValueT.
Given
+void f(char, bool, double, int);
+void foo() {
f('false, 3.14, 42);
-characterLiteral(equals(0))
- matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
- match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
- match 3.14
-integerLiteral(equals(42))
- matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
Note that you cannot directly match a negative numeric literal because the
minus sign is not part of the literal: It is a unary operator whose operand
is the positive numeric literal. Instead, you must use a unaryOperator()
matcher to match the minus sign:
-unaryOperator(hasOperatorName("-"),
- hasUnaryOperand(integerLiteral(equals(13))))
+Given
+ int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
@@ -4876,14 +6558,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
return l();
}
};
+
+The matcher
lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis())))
- matches `[this]() { return cc; }`.
+matches [this]() { return cc; }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('isImplicit2')"><a name="isImplicit2Anchor">isImplicit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isImplicit2"><pre>Matches an entity that has been implicitly added by the compiler (e.g.
implicit default/copy constructors).
+
+Given
+ struct S {};
+ void f(S obj) {
+ S copy = obj;
+ [&](){ return copy; };
+ }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+ lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
</pre></td></tr>
@@ -4902,14 +6600,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
};
template <class T>
class Z {
- void x() { this->m; }
+ void x() {
+ this->m;
+ this->t;
+ this->t->m;
+ }
+ int m;
+ T* t;
};
-memberExpr(isArrow())
- matches this->x, x, y.x, a, this->b
-cxxDependentScopeMemberExpr(isArrow())
- matches this->m
-unresolvedMemberExpr(isArrow())
- matches this->f<T>, f<T>
+
+The matcher memberExpr(isArrow())
+matches this->x, x, a,
+this->b, this->m and two times this->t,
+once for the standalone member expression, and once for the member
+expression that later accesses m .
+Additionally, it does not match this->t->t.
+The matcher cxxDependentScopeMemberExpr(isArrow())
+matches this->t->m, but not this->m or this->t.
+The matcher unresolvedMemberExpr(isArrow())
+matches this->f<T>, f<T>
</pre></td></tr>
@@ -4917,29 +6626,43 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyName0"><pre>Matches NamedDecl nodes that have any of the specified names.
This matcher is only provided as a performance optimization of hasName.
- hasAnyName(a, b, c)
- is equivalent to, but faster than
- anyOf(hasName(a), hasName(b), hasName(c))
+
+Given
+ void f(int a, int b);
+
+The matcher namedDecl(hasAnyName("a", "b")),
+which is equivalent to the matcher
+namedDecl(hasAnyName("a", "b")),
+matches int a and int b, but not
+void f(int a, int b).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('hasExternalFormalLinkage0')"><a name="hasExternalFormalLinkage0Anchor">hasExternalFormalLinkage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasExternalFormalLinkage0"><pre>Matches a declaration that has external formal linkage.
-Example matches only z (matcher = varDecl(hasExternalFormalLinkage()))
+Given
void f() {
- int x;
- static int y;
+ int a;
+ static int b;
}
-int z;
+int c;
+static int d;
+The matcher varDecl(hasExternalFormalLinkage())
+matches int c,
+but not int a, static int b or int d.
-Example matches f() because it has external formal linkage despite being
-unique to the translation unit as though it has internal likage
-(matcher = functionDecl(hasExternalFormalLinkage()))
+Given
+ namespace {
+ void f() {}
+ }
+ void g() {}
+ static void h() {}
-namespace {
-void f() {}
-}
+
+The matcher functionDecl(hasExternalFormalLinkage())
+matches void g() {}, but not void f() {} or
+static void h() {}.
</pre></td></tr>
@@ -4950,11 +6673,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
with '<enclosing>::'.
Does not match typedefs of an underlying type with the given name.
-Example matches X (Name == "X")
+Given
class X;
-Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
+
+The matcher namedDecl(hasName("X"))
+matches class X.
+
+Given
namespace a { namespace b { class X; } }
+
+
+The matchers namedDecl(hasName("::a::b::X")),
+namedDecl(hasName("a::b::X")),
+namedDecl(hasName("b::X")) and
+namedDecl(hasName("X"))
+match class X.
</pre></td></tr>
@@ -4966,12 +6700,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
prefixing the name with '<enclosing>::'. Does not match typedefs
of an underlying type with the given name.
-Example matches X (regexp == "::X")
- class X;
-
-Example matches X (regexp is one of "::X", "^foo::.*X", among others)
+Given
namespace foo { namespace bar { class X; } }
+
+The matcher namedDecl(matchesName("^::foo:.*X"))
+matches class X.
+
If the matcher is used in clang-query, RegexFlags parameter
should be passed as a quoted string. e.g: "NoFlags".
Flags can be combined with '|' example "IgnoreCase | BasicRegex"
@@ -4985,7 +6720,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
namespace n {
namespace {} // #1
}
-namespaceDecl(isAnonymous()) will match #1 but not ::n.
+
+The matcher namespaceDecl(isAnonymous())
+matches namespace {}, but not namespace n.
</pre></td></tr>
@@ -5000,9 +6737,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
inline namespace m {}
}
inline int Foo = 5;
-functionDecl(isInline()) will match ::f().
-namespaceDecl(isInline()) will match n::m.
-varDecl(isInline()) will match Foo;
+
+The matcher functionDecl(isInline()) matches f.
+The matcher namespaceDecl(isInline()) matches m.
+The matcher varDecl(isInline()) matches Foo
</pre></td></tr>
@@ -5011,15 +6749,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
specified.
Given
+ void foo() {
+ #pragma omp parallel
+ ;
+ #pragma omp parallel default(none)
+ ;
+ #pragma omp parallel default(shared)
+ ;
+ #pragma omp parallel default(private)
+ ;
+ #pragma omp parallel default(firstprivate)
+ ;
+ }
- #pragma omp parallel
- #pragma omp parallel default(none)
- #pragma omp parallel default(shared)
- #pragma omp parallel default(private)
- #pragma omp parallel default(firstprivate)
-``ompDefaultClause(isFirstPrivateKind())`` matches only
-``default(firstprivate)``.
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isFirstPrivateKind())))
+matches #pragma omp parallel default(firstprivate).
</pre></td></tr>
@@ -5027,14 +6773,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isNoneKind0"><pre>Matches if the OpenMP ``default`` clause has ``none`` kind specified.
Given
+ void foo() {
+ #pragma omp parallel
+ ;
+ #pragma omp parallel default(none)
+ ;
+ #pragma omp parallel default(shared)
+ ;
+ #pragma omp parallel default(private)
+ ;
+ #pragma omp parallel default(firstprivate)
+ ;
+ }
- #pragma omp parallel
- #pragma omp parallel default(none)
- #pragma omp parallel default(shared)
- #pragma omp parallel default(private)
- #pragma omp parallel default(firstprivate)
-``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isNoneKind())))
+matches only #pragma omp parallel default(none).
</pre></td></tr>
@@ -5043,15 +6798,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
specified.
Given
-
- #pragma omp parallel
+ void foo() {
+ #pragma omp parallel
+ ;
#pragma omp parallel default(none)
+ ;
#pragma omp parallel default(shared)
+ ;
#pragma omp parallel default(private)
+ ;
#pragma omp parallel default(firstprivate)
+ ;
+ }
+
-``ompDefaultClause(isPrivateKind())`` matches only
-``default(private)``.
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isPrivateKind())))
+matches #pragma omp parallel default(private).
</pre></td></tr>
@@ -5059,14 +6822,23 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isSharedKind0"><pre>Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
Given
-
- #pragma omp parallel
- #pragma omp parallel default(none)
+ void foo() {
+ #pragma omp parallel
+ ;
+ #pragma omp parallel default(none)
+ ;
#pragma omp parallel default(shared)
+ ;
#pragma omp parallel default(private)
+ ;
#pragma omp parallel default(firstprivate)
+ ;
+ }
-``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
+
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isSharedKind())))
+matches #pragma omp parallel default(shared).
</pre></td></tr>
@@ -5075,13 +6847,21 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
clause kind.
Given
+ void foo() {
+ #pragma omp parallel
+ ;
+ #pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {}
+ #pragma omp for
+ for (int i = 0; i < 10; ++i) {}
+ }
- #pragma omp parallel
- #pragma omp parallel for
- #pragma omp for
-`ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches
-``omp parallel`` and ``omp parallel for``.
+The matcher
+ompExecutableDirective(isAllowedToContainClauseKind(
+OpenMPClauseKind::OMPC_default))
+matches #pragma omp parallel
+and #pragma omp parallel for.
If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter
should be passed as a quoted string. e.g.,
@@ -5094,29 +6874,89 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
i.e., directives that can't have a structured block.
Given
+ void foo() {
+ #pragma omp parallel
+ {
+ #pragma omp taskyield
+ }
+ }
- #pragma omp parallel
- {}
- #pragma omp taskyield
-``ompExecutableDirective(isStandaloneDirective()))`` matches
-``omp taskyield``.
+The matcher ompExecutableDirective(isStandaloneDirective())
+matches #pragma omp taskyield.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom3')"><a name="isDerivedFrom3Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="isDerivedFrom3"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+ class Foo {};
+ typedef Foo Alias;
+ class Bar : public Alias {}; // derived from Alias, which is a
+ // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+ @interface NSObject @end
+ @interface Bar : NSObject @end
+
+
+Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>></td><td class="name" onclick="toggle('isDirectlyDerivedFrom3')"><a name="isDirectlyDerivedFrom3Anchor">isDirectlyDerivedFrom</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="isDirectlyDerivedFrom3"><pre>Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+ struct Base {};
+ struct DirectlyDerived : public Base {};
+ struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom3')"><a name="isSameOrDerivedFrom3Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom3"><pre>Overloaded method as shortcut for
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom3"><pre>Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
isSameOrDerivedFrom(hasName(...)).
+
+Given
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
</pre></td></tr>
@@ -5124,12 +6964,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountAtLeast3"><pre>Checks that a call expression or a constructor call expression has at least
the specified number of arguments (including absent default arguments).
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
void f(int x, int y);
void g(int x, int y, int z);
- f(0, 0);
- g(0, 0, 0);
+ void foo() {
+ f(0, 0);
+ g(0, 0, 0);
+ }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
</pre></td></tr>
@@ -5137,9 +6980,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="argumentCountIs3"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
void f(int x, int y);
- f(0, 0);
+ void foo() {
+ f(0, 0);
+ }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
</pre></td></tr>
@@ -5147,24 +6994,27 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnySelector0"><pre>Matches when at least one of the supplied string equals to the
Selector.getAsString()
- matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
- matches both of the expressions below:
[myObj methodA:argA];
[myObj methodB:argB];
+
+ The matcher objCMessageExpr(hasSelector("methodA:", "methodB:"));
+ matches [myObj methodA:argA]; and [myObj methodB:argB];
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasKeywordSelector0')"><a name="hasKeywordSelector0Anchor">hasKeywordSelector</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasKeywordSelector0"><pre>Matches when the selector is a keyword selector
-objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
-message expression in
-
+Given
UIWebView *webView = ...;
CGRect bodyFrame = webView.frame;
bodyFrame.size.height = self.bodyContentHeight;
webView.frame = bodyFrame;
// ^---- matches here
+
+
+The matcher objCMessageExpr(hasKeywordSelector()) matches the
+generated setFrame message expression in
</pre></td></tr>
@@ -5179,56 +7029,68 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasSelector0')"><a name="hasSelector0Anchor">hasSelector</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="hasSelector0"><pre>Matches when BaseName == Selector.getAsString()
- matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
- matches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
[self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher
+objCMessageExpr(hasSelector("loadHTMLString:baseURL:")); matches
+the outer message expr in the code below, but NOT the message invocation
+for self.bodyView.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasUnarySelector0')"><a name="hasUnarySelector0Anchor">hasUnarySelector</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasUnarySelector0"><pre>Matches when the selector is a Unary Selector
- matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
- matches self.bodyView in the code below, but NOT the outer message
- invocation of "loadHTMLString:baseURL:".
+Given
[self.bodyView loadHTMLString:html baseURL:NULL];
+
+
+ The matcher objCMessageExpr(matchesSelector(hasUnarySelector());
+ matches self.bodyView, but does not match the outer message
+ invocation of "loadHTMLString:baseURL:".
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('isClassMessage0')"><a name="isClassMessage0Anchor">isClassMessage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isClassMessage0"><pre>Returns true when the Objective-C message is sent to a class.
-Example
-matcher = objcMessageExpr(isClassMessage())
-matches
+Given
[NSString stringWithFormat:@"format"];
-but not
NSString *x = @"hello";
[x containsString:@"h"];
+
+The matcher objcMessageExpr(isClassMessage())
+matches [NSString stringWithFormat:@"format"];
+but does not match [[x containsString:@"h"]
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('isInstanceMessage0')"><a name="isInstanceMessage0Anchor">isInstanceMessage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInstanceMessage0"><pre>Returns true when the Objective-C message is sent to an instance.
-Example
-matcher = objcMessageExpr(isInstanceMessage())
-matches
+Given
NSString *x = @"hello";
[x containsString:@"h"];
-but not
[NSString stringWithFormat:@"format"];
+
+The matcher objcMessageExpr(isInstanceMessage())
+matches [x containsString:@"h"];
+but does not match [NSString stringWithFormat:@"format"];
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr>
<tr><td colspan="4" class="doc" id="matchesSelector0"><pre>Matches ObjC selectors whose name contains
a substring matched by the given RegExp.
- matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
+
+Given
[self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher
+objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
+invocation for self.bodyView.
+
If the matcher is used in clang-query, RegexFlags parameter
should be passed as a quoted string. e.g: "NoFlags".
Flags can be combined with '|' example "IgnoreCase | BasicRegex"
@@ -5238,25 +7100,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('numSelectorArgs0')"><a name="numSelectorArgs0Anchor">numSelectorArgs</a></td><td>unsigned N</td></tr>
<tr><td colspan="4" class="doc" id="numSelectorArgs0"><pre>Matches when the selector has the specified number of arguments
- matcher = objCMessageExpr(numSelectorArgs(0));
- matches self.bodyView in the code below
-
- matcher = objCMessageExpr(numSelectorArgs(2));
- matches the invocation of "loadHTMLString:baseURL:" but not that
- of self.bodyView
[self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher objCMessageExpr(numSelectorArgs(0))
+matches self.bodyView.
+The matcher objCMessageExpr(numSelectorArgs(2))
+matches the invocation of loadHTMLString:baseURL:
+but does not match self.bodyView
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>></td><td class="name" onclick="toggle('isClassMethod0')"><a name="isClassMethod0Anchor">isClassMethod</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isClassMethod0"><pre>Returns true when the Objective-C method declaration is a class method.
-Example
-matcher = objcMethodDecl(isClassMethod())
-matches
+Given
@interface I + (void)foo; @end
-but not
@interface I - (void)bar; @end
+
+The matcher objcMethodDecl(isClassMethod())
+matches @interface I + (void)foo; @end
+but does not match interface I + (void)foo; @end
</pre></td></tr>
@@ -5270,6 +7133,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
extern int vb; // Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); // Doesn't match, as it has no body.
+
+The matcher tagDecl(isDefinition())
+matches A
+The matcher varDecl(isDefinition())
+matches va
+The matcher functionDecl(isDefinition())
+matches fa
+
@interface X
- (void)ma; // Doesn't match, interface is declaration.
@end
@@ -5277,6 +7148,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
- (void)ma {}
@end
+The matcher objcMethodDecl(isDefinition())
+matches - (void)ma {}
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>>
</pre></td></tr>
@@ -5285,33 +7159,39 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>></td><td class="name" onclick="toggle('isInstanceMethod0')"><a name="isInstanceMethod0Anchor">isInstanceMethod</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInstanceMethod0"><pre>Returns true when the Objective-C method declaration is an instance method.
-Example
-matcher = objcMethodDecl(isInstanceMethod())
-matches
+Given
@interface I - (void)bar; @end
-but not
@interface I + (void)foo; @end
+
+The matcher objcMethodDecl(isInstanceMethod())
+matches @interface I - (void)bar; @end
+but does not match @interface I - (void)foo; @end
+
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>></td><td class="name" onclick="toggle('hasDefaultArgument0')"><a name="hasDefaultArgument0Anchor">hasDefaultArgument</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDefaultArgument0"><pre>Matches a declaration that has default arguments.
-Example matches y (matcher = parmVarDecl(hasDefaultArgument()))
-void x(int val) {}
-void y(int val = 0) {}
+Given
+ void x(int val) {}
+ void y(int val = 0) {}
+
+
+The matcher parmVarDecl(hasDefaultArgument())
+matches int val = 0.
Deprecated. Use hasInitializer() instead to be able to
match on the contents of the default argument. For example:
-void x(int val = 7) {}
-void y(int val = 42) {}
-parmVarDecl(hasInitializer(integerLiteral(equals(42))))
- matches the parameter of y
+Given
+ void x(int val = 7) {}
+ void y(int val = 42) {}
+
-A matcher such as
- parmVarDecl(hasInitializer(anything()))
-is equivalent to parmVarDecl(hasDefaultArgument()).
+The matcher
+parmVarDecl(hasInitializer(integerLiteral(equals(42)))),
+matches int val = 42.
</pre></td></tr>
@@ -5326,9 +7206,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void f(int a, int b, int c) {
}
-``parmVarDecl(isAtPosition(0))`` matches ``int a``.
-
-``parmVarDecl(isAtPosition(1))`` matches ``int b``.
+The matcher parmVarDecl(isAtPosition(0)) matches
+a. The matcher parmVarDecl(isAtPosition(1))
+matches b.
</pre></td></tr>
@@ -5338,8 +7218,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
class Y { public: void x(); };
void z() { Y* y; y->x(); }
-cxxMemberCallExpr(on(hasType(asString("class Y *"))))
- matches y->x()
+
+The matcher cxxMemberCallExpr(on(hasType(asString("Y *"))))
+matches y->x()
</pre></td></tr>
@@ -5350,10 +7231,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
class X { int a; int b; };
-cxxRecordDecl(
+
+The matcher cxxRecordDecl(
has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
+ matches X, as a and b have the same type.
Note that when multiple matches are involved via forEach* matchers,
equalsBoundNodes acts as a filter.
@@ -5372,12 +7254,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
typedef const int const_int;
- const_int i;
- int *const j;
+ const_int i = 0;
+ int *const j = nullptr;
int *volatile k;
int m;
-varDecl(hasType(hasLocalQualifiers())) matches only j and k.
-i is const-qualified but the qualifier is not local.
+
+
+The matcher varDecl(hasType(hasLocalQualifiers())) matches only
+j and k. is
+const-qualified but the qualifier is not local.
</pre></td></tr>
@@ -5388,9 +7273,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void a(char);
void b(wchar_t);
void c(double);
+
+
+The matcher
functionDecl(hasAnyParameter(hasType(isAnyCharacter())))
-matches "a(char)", "b(wchar_t)", but not "c(double)".
-</pre></td></tr>
+a, b, but not </pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isAnyPointer0')"><a name="isAnyPointer0Anchor">isAnyPointer</a></td><td></td></tr>
@@ -5406,8 +7293,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Foo *f;
int j;
-varDecl(hasType(isAnyPointer()))
- matches "int *i" and "Foo *f", but not "int j".
+
+The matcher varDecl(hasType(isAnyPointer()))
+int *i and Foo *f, but not int j.
</pre></td></tr>
@@ -5421,9 +7309,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void c(const int);
void d(const int*);
void e(int const) {};
+The matcher
functionDecl(hasAnyParameter(hasType(isConstQualified())))
- matches "void b(int const)", "void c(const int)" and
- "void e(int const) {}". It does not match d as there
+ matches b, c and
+ e.
+ It does not match as there
is no top-level const on the parameter type "const int *".
</pre></td></tr>
@@ -5435,8 +7325,8 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void a(int);
void b(long);
void c(double);
-functionDecl(hasAnyParameter(hasType(isInteger())))
-matches "a(int)", "b(long)", but not "c(double)".
+The matcher functionDecl(hasAnyParameter(hasType(isInteger())))
+a, b, but not c.
</pre></td></tr>
@@ -5447,8 +7337,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void a(int);
void b(unsigned long);
void c(double);
-functionDecl(hasAnyParameter(hasType(isSignedInteger())))
-matches "a(int)", but not "b(unsigned long)" and "c(double)".
+The matcher
+functionDecl(hasAnyParameter(hasType(isSignedInteger()))) matches
+a, but not and not
</pre></td></tr>
@@ -5459,8 +7350,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void a(int);
void b(unsigned long);
void c(double);
+The matcher
functionDecl(hasAnyParameter(hasType(isUnsignedInteger())))
-matches "b(unsigned long)", but not "a(int)" and "c(double)".
+matches b,
+but does not match a and c.
</pre></td></tr>
@@ -5474,9 +7367,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
void c(volatile int);
void d(volatile int*);
void e(int volatile) {};
+The matcher
functionDecl(hasAnyParameter(hasType(isVolatileQualified())))
- matches "void b(int volatile)", "void c(volatile int)" and
- "void e(int volatile) {}". It does not match d as there
+ matches b, c and
+ e.
+ It does not match as there
is no top-level volatile on the parameter type "volatile int *".
</pre></td></tr>
@@ -5488,10 +7383,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
class X { int a; int b; };
-cxxRecordDecl(
+
+The matcher cxxRecordDecl(
has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
+ matches X, as a and b have the same type.
Note that when multiple matches are involved via forEach* matchers,
equalsBoundNodes acts as a filter.
@@ -5516,6 +7412,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Does not match if only part of the statement is expanded from that macro or
if
diff erent parts of the statement are expanded from
diff erent
appearances of the macro.
+
+Given
+ #define A 0
+ #define B A
+ int c = B;
+
+The matcher integerLiteral(isExpandedFromMacro("A"))
+matches the literal expanded at the initializer B of the variable
+c .
</pre></td></tr>
@@ -5523,12 +7428,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isExpansionInFileMatching1"><pre>Matches AST nodes that were expanded within files whose name is
partially matching a given regex.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
+Given the headers Y.h
+ #pragma once
+ typedef int my_y_int;
+and X.h
+ #pragma once
+ typedef int my_x_int;
+and the source code
+ #include "X.h"
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_x_int b = 1;
+ my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
@@ -5541,12 +7459,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInMainFile1')"><a name="isExpansionInMainFile1Anchor">isExpansionInMainFile</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInMainFile1"><pre>Matches AST nodes that were expanded within the main-file.
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
+Given the header Y.h
+ #pragma once
+ typedef int my_header_int;
+and the source file
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -5555,12 +7479,17 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader1')"><a name="isExpansionInSystemHeader1Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader1"><pre>Matches AST nodes that were expanded within system-header-files.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+ #pragma once
+ int header();
+and the source code
#include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
+ static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -5571,14 +7500,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
int j;
- template<typename T> void A(T t) { T i; j += 42;}
- A(0);
- A(0U);
-declStmt(isInTemplateInstantiation())
- matches 'int i;' and 'unsigned i'.
-unless(stmt(isInTemplateInstantiation()))
- will NOT match j += 42; as it's shared between the template definition and
- instantiation.
+ template<typename T> void A(T t) { T i; }
+ void foo() {
+ A(0);
+ A(0U);
+ }
+
+The matcher declStmt(isInTemplateInstantiation())
+matches T i; twice, once for int and once for
+int}.
+The matcher declStmt(unless(isInTemplateInstantiation())) will
+match T i; once inside the template definition, but not for any of
+the instantiated bodies.
</pre></td></tr>
@@ -5592,21 +7525,28 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
char *s = "abcd";
wchar_t *ws = L"abcd";
char *w = "a";
-constantArrayType(hasSize(42))
- matches "int a[42]" and "int b[2 * 21]"
-stringLiteral(hasSize(4))
- matches "abcd", L"abcd"
+
+The matcher constantArrayType(hasSize(42))
+matches int[42] twice.
+The matcher stringLiteral(hasSize(4))
+matches "abcd" and L"abcd".
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isClass0')"><a name="isClass0Anchor">isClass</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isClass0"><pre>Matches TagDecl object that are spelled with "class."
-Example matches C, but not S, U or E.
+Given
struct S {};
class C {};
union U {};
- enum E {};
+ enum E { Ok };
+
+The matcher tagDecl(isClass())
+matches class C,
+but does not match struct S,
+union U
+or enum E.
</pre></td></tr>
@@ -5620,6 +7560,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
extern int vb; // Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); // Doesn't match, as it has no body.
+
+The matcher tagDecl(isDefinition())
+matches A
+The matcher varDecl(isDefinition())
+matches va
+The matcher functionDecl(isDefinition())
+matches fa
+
@interface X
- (void)ma; // Doesn't match, interface is declaration.
@end
@@ -5627,6 +7575,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
- (void)ma {}
@end
+The matcher objcMethodDecl(isDefinition())
+matches - (void)ma {}
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>>
</pre></td></tr>
@@ -5635,11 +7586,16 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isEnum0')"><a name="isEnum0Anchor">isEnum</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isEnum0"><pre>Matches TagDecl object that are spelled with "enum."
-Example matches E, but not C, S or U.
+Given
struct S {};
class C {};
union U {};
- enum E {};
+ enum E { Ok };
+
+The matcher tagDecl(isEnum())
+matches enum E { Ok },
+but does not match struct S {},
+class C {} or union U {}.
</pre></td></tr>
@@ -5650,18 +7606,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
struct S {};
class C {};
union U {};
- enum E {};
+ enum E { Ok };
+
+The matcher tagDecl(isStruct())
+matches struct S,
+but does not match class C,
+union U
+or enum E.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isUnion0')"><a name="isUnion0Anchor">isUnion</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isUnion0"><pre>Matches TagDecl object that are spelled with "union."
-Example matches U, but not C, S or E.
+Given
struct S {};
class C {};
union U {};
- enum E {};
+ enum E { Ok };
+
+The matcher tagDecl(isUnion())
+matches union U,
+does not match struct S,
+class C
+or enum E.
</pre></td></tr>
@@ -5675,9 +7643,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<int T> struct C {};
C<42> c;
-classTemplateSpecializationDecl(
+
+The matcher classTemplateSpecializationDecl(
hasAnyTemplateArgument(equalsIntegralValue("42")))
- matches the implicit instantiation of C in C<42>.
+matches the implicitly declared specialization
+struct C<42> from the instantiation for the type of the
+variable c .
</pre></td></tr>
@@ -5687,10 +7658,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<int T> struct C {};
C<42> c;
-classTemplateSpecializationDecl(
+
+The matcher classTemplateSpecializationDecl(
hasAnyTemplateArgument(isIntegral()))
- matches the implicit instantiation of C in C<42>
- with isIntegral() matching 42.
+matches the implicitly declared specialization
+struct C<42> from the instantiation for the type of the
+variable c .
</pre></td></tr>
@@ -5700,8 +7673,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> struct C {};
C<int> c;
+
+The matcher
classTemplateSpecializationDecl(templateArgumentCountIs(1))
- matches C<int>.
+matches struct C<int>.
</pre></td></tr>
@@ -5710,6 +7685,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Does not match if only part of the statement is expanded from that macro or
if
diff erent parts of the statement are expanded from
diff erent
appearances of the macro.
+
+Given
+ #define A 0
+ #define B A
+ int c = B;
+
+The matcher integerLiteral(isExpandedFromMacro("A"))
+matches the literal expanded at the initializer B of the variable
+c .
</pre></td></tr>
@@ -5717,12 +7701,25 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isExpansionInFileMatching2"><pre>Matches AST nodes that were expanded within files whose name is
partially matching a given regex.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
+Given the headers Y.h
+ #pragma once
+ typedef int my_y_int;
+and X.h
+ #pragma once
+ typedef int my_x_int;
+and the source code
+ #include "X.h"
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_x_int b = 1;
+ my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
@@ -5735,12 +7732,18 @@ <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('isExpansionInMainFile2')"><a name="isExpansionInMainFile2Anchor">isExpansionInMainFile</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInMainFile2"><pre>Matches AST nodes that were expanded within the main-file.
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
+Given the header Y.h
+ #pragma once
+ typedef int my_header_int;
+and the source file
+ #include "Y.h"
+ typedef int my_main_file_int;
+ my_main_file_int a = 0;
+ my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -5749,12 +7752,17 @@ <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('isExpansionInSystemHeader2')"><a name="isExpansionInSystemHeader2Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader2"><pre>Matches AST nodes that were expanded within system-header-files.
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+ #pragma once
+ int header();
+and the source code
#include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
+ static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
</pre></td></tr>
@@ -5765,8 +7773,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
struct S { bool func(); };
-functionDecl(returns(booleanType()))
- matches "bool func();"
+
+The matcher functionDecl(returns(booleanType()))
+func
</pre></td></tr>
@@ -5777,10 +7786,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
class X { int a; int b; };
-cxxRecordDecl(
+
+The matcher cxxRecordDecl(
has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
+ matches X, as a and b have the same type.
Note that when multiple matches are involved via forEach* matchers,
equalsBoundNodes acts as a filter.
@@ -5806,8 +7816,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
int i;
float f;
-realFloatingPointType()
- matches "float f" but not "int i"
+The matcher type(realFloatingPointType())
+matches float
+but does not match int.
</pre></td></tr>
@@ -5816,8 +7827,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
struct S { void func(); };
-functionDecl(returns(voidType()))
- matches "void func();"
+
+
+The matcher functionDecl(returns(voidType()))
+func
</pre></td></tr>
@@ -5826,9 +7839,10 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
int x;
- int s = sizeof(x) + alignof(x)
-unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
- matches sizeof(x)
+ int s = sizeof(x) + alignof(x);
+
+The matcher unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
+matches sizeof(x)
If the matcher is use from clang-query, UnaryExprOrTypeTrait parameter
should be passed as a quoted string. e.g., ofKind("UETT_SizeOf").
@@ -5839,9 +7853,26 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyOperatorName3"><pre>Matches operator expressions (binary or unary) that have any of the
specified names.
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
hasAnyOperatorName("+", "-")
- Is equivalent to
- anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+ hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+void bar(bool a, bool b) {
+ a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
</pre></td></tr>
@@ -5849,15 +7880,22 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperatorName4"><pre>Matches the operator Name of operator expressions and fold expressions
(binary or unary).
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
+Given
+void foo(bool a, bool b) {
+ !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
</pre></td></tr>
@@ -5876,40 +7914,57 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
};
template <class T>
class Z {
- void x() { this->m; }
+ void x() {
+ this->m;
+ this->t;
+ this->t->m;
+ }
+ int m;
+ T* t;
};
-memberExpr(isArrow())
- matches this->x, x, y.x, a, this->b
-cxxDependentScopeMemberExpr(isArrow())
- matches this->m
-unresolvedMemberExpr(isArrow())
- matches this->f<T>, f<T>
+
+The matcher memberExpr(isArrow())
+matches this->x, x, a,
+this->b, this->m and two times this->t,
+once for the standalone member expression, and once for the member
+expression that later accesses m .
+Additionally, it does not match this->t->t.
+The matcher cxxDependentScopeMemberExpr(isArrow())
+matches this->t->m, but not this->m or this->t.
+The matcher unresolvedMemberExpr(isArrow())
+matches this->f<T>, f<T>
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasAutomaticStorageDuration0')"><a name="hasAutomaticStorageDuration0Anchor">hasAutomaticStorageDuration</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasAutomaticStorageDuration0"><pre>Matches a variable declaration that has automatic storage duration.
-Example matches x, but not y, z, or a.
-(matcher = varDecl(hasAutomaticStorageDuration())
+Given
void f() {
int x;
static int y;
thread_local int z;
}
int a;
+
+The matcher varDecl(hasAutomaticStorageDuration())
+matches x
+but does not match y, z or
+a
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasGlobalStorage0')"><a name="hasGlobalStorage0Anchor">hasGlobalStorage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasGlobalStorage0"><pre>Matches a variable declaration that does not have local storage.
-Example matches y and z (matcher = varDecl(hasGlobalStorage())
+Given
void f() {
int x;
static int y;
}
int z;
+The matcher varDecl(hasGlobalStorage())
+matches y and z
</pre></td></tr>
@@ -5917,12 +7972,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="hasLocalStorage0"><pre>Matches a variable declaration that has function scope and is a
non-static local variable.
-Example matches x (matcher = varDecl(hasLocalStorage())
+Given
void f() {
int x;
static int y;
}
int z;
+The matcher varDecl(hasLocalStorage())
+matches x
</pre></td></tr>
@@ -5939,22 +7996,28 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
int a;
static int b;
extern int c;
-varDecl(hasStaticStorageDuration())
- matches the function declaration y, a, b and c.
+
+The matcher varDecl(hasStaticStorageDuration())
+matches y, a, b and
+c
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasThreadStorageDuration0')"><a name="hasThreadStorageDuration0Anchor">hasThreadStorageDuration</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasThreadStorageDuration0"><pre>Matches a variable declaration that has thread storage duration.
-Example matches z, but not x, z, or a.
-(matcher = varDecl(hasThreadStorageDuration())
+Given
void f() {
int x;
static int y;
thread_local int z;
}
int a;
+
+The matcher varDecl(hasThreadStorageDuration())
+matches z
+but does not match x, z or
+a
</pre></td></tr>
@@ -5962,29 +8025,34 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isConstexpr0"><pre>Matches constexpr variable and function declarations,
and if constexpr.
-Given:
+Given
constexpr int foo = 42;
constexpr int bar();
void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
- matches the declaration of foo.
-functionDecl(isConstexpr())
- matches the declaration of bar.
-ifStmt(isConstexpr())
- matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isConstinit0')"><a name="isConstinit0Anchor">isConstinit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isConstinit0"><pre>Matches constinit variable declarations.
-Given:
+Given
constinit int foo = 42;
constinit const char* bar = "bar";
int baz = 42;
[[clang::require_constant_initialization]] int xyz = 42;
-varDecl(isConstinit())
- matches the declaration of `foo` and `bar`, but not `baz` and `xyz`.
+
+The matcher varDecl(isConstinit())
+matches the declaration of foo
+and bar,
+but does not match baz or
+xyz.
</pre></td></tr>
@@ -5998,6 +8066,14 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
extern int vb; // Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); // Doesn't match, as it has no body.
+
+The matcher tagDecl(isDefinition())
+matches A
+The matcher varDecl(isDefinition())
+matches va
+The matcher functionDecl(isDefinition())
+matches fa
+
@interface X
- (void)ma; // Doesn't match, interface is declaration.
@end
@@ -6005,6 +8081,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
- (void)ma {}
@end
+The matcher objcMethodDecl(isDefinition())
+matches - (void)ma {}
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>>
</pre></td></tr>
@@ -6014,12 +8093,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isExceptionVariable0"><pre>Matches a variable declaration that is an exception variable from
a C++ catch block, or an Objective-C statement.
-Example matches x (matcher = varDecl(isExceptionVariable())
+Given
void f(int y) {
try {
} catch (int x) {
}
}
+
+The matcher varDecl(isExceptionVariable())
+matches x
</pre></td></tr>
@@ -6030,8 +8112,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
Given
template<typename T> void A(T t) { }
template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
+
+The matcher functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization template<> void A(int N) { }.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
</pre></td></tr>
@@ -6040,17 +8123,21 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isExternC1')"><a name="isExternC1Anchor">isExternC</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExternC1"><pre>Matches extern "C" function or variable declarations.
-Given:
+Given
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
extern "C" int x = 1;
extern "C" int y = 2;
int z = 3;
-functionDecl(isExternC())
- matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
- matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
</pre></td></tr>
@@ -6058,8 +8145,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isInitCapture0"><pre>Matches a variable serving as the implicit variable for a lambda init-
capture.
-Example matches x (matcher = varDecl(isInitCapture()))
-auto f = [x=3]() { return x; };
+Given
+auto f = [x = 3]() { return x; };
+
+The matcher varDecl(isInitCapture())
+matches x = 3.
</pre></td></tr>
@@ -6074,21 +8164,24 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
inline namespace m {}
}
inline int Foo = 5;
-functionDecl(isInline()) will match ::f().
-namespaceDecl(isInline()) will match n::m.
-varDecl(isInline()) will match Foo;
+
+The matcher functionDecl(isInline()) matches f.
+The matcher namespaceDecl(isInline()) matches m.
+The matcher varDecl(isInline()) matches Foo
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isStaticLocal0')"><a name="isStaticLocal0Anchor">isStaticLocal</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isStaticLocal0"><pre>Matches a static variable with local scope.
-Example matches y (matcher = varDecl(isStaticLocal()))
+Given
void f() {
int x;
static int y;
}
static int z;
+The matcher varDecl(isStaticLocal())
+matches y
</pre></td></tr>
@@ -6096,15 +8189,15 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
<tr><td colspan="4" class="doc" id="isStaticStorageClass1"><pre>Matches variable/function declarations that have "static" storage
class specifier ("static" keyword) written in the source.
-Given:
+Given
static void f() {}
static int i = 0;
extern int j;
int k;
-functionDecl(isStaticStorageClass())
- matches the function declaration f.
-varDecl(isStaticStorageClass())
- matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+ matches f
+The matcher varDecl(isStaticStorageClass())
+ matches i
</pre></td></tr>
@@ -6113,18 +8206,36 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
member variable template instantiations.
Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-or
- template <typename T> class X {}; class A {}; extern template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
+ template <typename T> class X {};
+ class A {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches class X<class A>.
+ template <typename T> class X {};
+ class A {};
+ template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches template class X<A>
+ template <typename T> class X {};
+ class A {};
+ extern template class X<A>;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
+matches extern template class X<A>
But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ template <typename T> class X {};
+ class A {};
+ template <> class X<A> {};
+ X<A> x;
+
+The matcher cxxRecordDecl(hasName("::X"),
+isTemplateInstantiation())
does not match, as X<A> is an explicit template specialization.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
@@ -6151,10 +8262,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<*></td><td class="name" onclick="toggle('binaryOperation0')"><a name="binaryOperation0Anchor">binaryOperation</a></td><td>Matcher<*>...Matcher<*></td></tr>
<tr><td colspan="4" class="doc" id="binaryOperation0"><pre>Matches nodes which can be used with binary operators.
-The code
- var1 != var2;
-might be represented in the clang AST as a binaryOperator, a
-cxxOperatorCallExpr or a cxxRewrittenBinaryOperator, depending on
+A comparison of two expressions might be represented in the clang AST as a
+binaryOperator, a cxxOperatorCallExpr or a
+cxxRewrittenBinaryOperator, depending on
* whether the types of var1 and var2 are fundamental (binaryOperator) or at
least one is a class type (cxxOperatorCallExpr)
@@ -6168,12 +8278,6 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
compatible.
Given
- binaryOperation(
- hasOperatorName("!="),
- hasLHS(expr().bind("lhs")),
- hasRHS(expr().bind("rhs"))
- )
-matches each use of "!=" in:
struct S{
bool operator!=(const S&) const;
};
@@ -6187,25 +8291,28 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<typename T>
void templ()
{
- 1 != 2;
+ 3 != 4;
T() != S();
}
struct HasOpEq
{
- bool operator==(const HasOpEq &) const;
+ friend bool
+ operator==(const HasOpEq &, const HasOpEq&) noexcept = default;
};
void inverse()
{
- HasOpEq s1;
- HasOpEq s2;
- if (s1 != s2)
+ HasOpEq e1;
+ HasOpEq e2;
+ if (e1 != e2)
return;
}
struct HasSpaceship
{
- bool operator<=>(const HasOpEq &) const;
+ friend bool
+ operator<=>(const HasSpaceship &,
+ const HasSpaceship&) noexcept = default;
};
void use_spaceship()
@@ -6215,6 +8322,15 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
if (s1 != s2)
return;
}
+
+
+The matcher binaryOperation(
+ hasOperatorName("!="),
+ hasLHS(expr().bind("lhs")),
+ hasRHS(expr().bind("rhs"))
+ )
+matches 1 != 2, S() != S(), 3 != 4,
+T() != S(), e1 != e2 and s1 != s2.
</pre></td></tr>
@@ -6224,14 +8340,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Unlike anyOf, eachOf will generate a match result for each
matching submatcher.
-For example, in:
- class A { int a; int b; };
-The matcher:
- cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
- has(fieldDecl(hasName("b")).bind("v"))))
-will generate two results binding "v", the first of which binds
-the field declaration of a, the second the field declaration of
-b.
+Given
+ void f(int a, int b);
+
+
+The matcher functionDecl(hasAnyParameter(
+eachOf(parmVarDecl(hasName("a")).bind("v"),
+ parmVarDecl(hasName("b")).bind("v"))))
+matches void f(int a, int b),
+with parmVarDecl(hasName("a")) matching a
+for one match,
+and with parmVarDecl(hasName("b")) matching
+b for the other match.
Usable as: Any Matcher
</pre></td></tr>
@@ -6244,10 +8364,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
For example, in:
class A { class B {}; class C {}; };
-The matcher:
- cxxRecordDecl(hasName("::A"),
+
+The matcher
+cxxRecordDecl(hasName("::A"),
findAll(cxxRecordDecl(isDefinition()).bind("m")))
-will generate results for A, B and C.
+matches A three times,
+with cxxRecordDecl(isDefinition()).bind("m")
+matching A,
+B and C.
Usable as: Any Matcher
</pre></td></tr>
@@ -6257,24 +8381,71 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="forEachDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
provided matcher.
-Example matches X, A, A::X, B, B::C, B::C::X
- (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
+Given
class X {};
class A { class X {}; }; // Matches A, because A::X is a class of name
// X inside A.
class B { class C { class X {}; }; };
+The matcher
+cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X"))))
+matches X, A,
+B, class B::C
+and class B::C::X
+
DescendantT must be an AST base type.
As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
each result that matches instead of only on the first one.
Note: Recursively combined ForEachDescendant can cause many matches:
- cxxRecordDecl(forEachDescendant(cxxRecordDecl(
- forEachDescendant(cxxRecordDecl())
- )))
-will match 10 times (plus injected class name matches) on:
- class A { class B { class C { class D { class E {}; }; }; }; };
+ struct A {
+ struct B {
+ struct C {};
+ struct D {};
+ };
+ };
+
+
+The matcher cxxRecordDecl(forEachDescendant(cxxRecordDecl(
+ forEachDescendant(cxxRecordDecl().bind("inner"))
+ ).bind("middle")))
+will match 9 times:
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the definition of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the definition of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
Usable as: Any Matcher
</pre></td></tr>
@@ -6284,17 +8455,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
provided matcher.
-Example matches X, Y, Y::X, Z::Y, Z::Y::X
- (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
+Given
class X {};
class Y { class X {}; }; // Matches Y, because Y::X is a class of name X
// inside Y.
class Z { class Y { class X {}; }; }; // Does not match Z.
+The matcher cxxRecordDecl(forEach(cxxRecordDecl(hasName("X"))))
+matches class X,
+class Y,
+class Y::X,
+class Z::Y::X and class Z::Y
+
ChildT must be an AST base type.
As opposed to 'has', 'forEach' will cause a match for each result that
-matches instead of only on the first one.
+ matches instead of only on the first one.
Usable as: Any Matcher
</pre></td></tr>
@@ -6307,7 +8483,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f() { if (true) { int x = 42; } }
void g() { for (;;) { int x = 43; } }
-expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43.
+
+The matcher expr(integerLiteral(hasAncestor(ifStmt())))
+matches 42
+but does not match 43
Usable as: Any Matcher
</pre></td></tr>
@@ -6317,12 +8496,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
provided matcher.
-Example matches X, Y, Z
- (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
+Given
class X {}; // Matches X, because X::X is a class of name X inside X.
class Y { class X {}; };
class Z { class Y { class X {}; }; };
+The matcher
+cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X"))))
+matches class X {}, class Y { class X {}; }
+and class Z { class Y { class X {}; }; }.
+
DescendantT must be an AST base type.
Usable as: Any Matcher
@@ -6333,19 +8516,29 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="has0"><pre>Matches AST nodes that have child AST nodes that match the
provided matcher.
-Example matches X, Y
- (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
+Given
class X {}; // Matches X, because X::X is a class of name X inside X.
class Y { class X {}; };
class Z { class Y { class X {}; }; }; // Does not match Z.
+The matcher cxxRecordDecl(has(cxxRecordDecl(hasName("X"))))
+matches class X {} three times,
+and class Y { class X {}; } two times.
+
ChildT must be an AST base type.
Usable as: Any Matcher
Note that has is direct matcher, so it also matches things like implicit
casts and paren casts. If you are matching with expr then you should
-probably consider using ignoringParenImpCasts like:
-has(ignoringParenImpCasts(expr())).
+probably consider using ignoringParenImpCasts:
+
+Given
+ int x =0;
+ double y = static_cast<double>(x);
+
+The matcher
+cxxStaticCastExpr(has(ignoringParenImpCasts(declRefExpr()))).
+matches static_cast<double>(x)
</pre></td></tr>
@@ -6355,7 +8548,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
-compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
+
+The matcher compoundStmt(hasParent(ifStmt()))
+matches { int x = 43; }
Usable as: Any Matcher
</pre></td></tr>
@@ -6369,7 +8564,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
which should match both are typically duplicated. This matcher
removes the need for duplication.
-Given code
+Given
struct ConstructorTakesInt
{
ConstructorTakesInt(int i) {}
@@ -6389,9 +8584,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
ConstructorTakesInt cti(42);
}
+
The matcher
-invocation(hasArgument(0, integerLiteral(equals(42))))
-matches the expression in both doCall and doConstruct
+expr(invocation(hasArgument(0, integerLiteral(equals(42)))))
+matches the expressions callTakesInt(42)
+and cti(42).
</pre></td></tr>
@@ -6402,18 +8599,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Useful when additional information which may or may not present about a main
matching node is desired.
-For example, in:
- class Foo {
- int bar;
- }
-The matcher:
- cxxRecordDecl(
- optionally(has(
- fieldDecl(hasName("bar")).bind("var")
- ))).bind("record")
-will produce a result binding for both "record" and "var".
-The matcher will produce a "record" binding for even if there is no data
-member named "bar" in that class.
+Given
+ int a = 0;
+ int b;
+
+The matcher varDecl(optionally(hasInitializer(expr())))
+matches int a = 0 and int b.
Usable as: Any Matcher
</pre></td></tr>
@@ -6428,10 +8619,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int i = 3.0;
}
The matcher
- traverse(TK_IgnoreUnlessSpelledInSource,
+traverse(TK_IgnoreUnlessSpelledInSource,
varDecl(hasInitializer(floatLiteral().bind("init")))
)
-matches the variable declaration with "init" bound to the "3.0".
+ matches int i = 3.0 with "init" bound to 3.0.
</pre></td></tr>
@@ -6439,8 +8630,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition5"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
@@ -6449,8 +8645,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
(binary or ternary).
Example matches b
- condition ? a : b
- condition ?: b
+ void foo(bool condition, int a, int b) {
+ condition ? a : b;
+ condition ?: b;
+ }
+
+The matcher
+conditionalOperator(hasFalseExpression(expr().bind("false")))
+matches condition ? a : b,
+with expr() matching b.
+The matcher
+binaryConditionalOperator(hasFalseExpression(expr().bind("false")))
+matches condition ?: b,
+with expr() matching b.
</pre></td></tr>
@@ -6458,16 +8665,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasTrueExpression0"><pre>Matches the true branch expression of a conditional operator.
Example 1 (conditional ternary operator): matches a
- condition ? a : b
+Given
+ void foo(bool condition, int a, int b) {
+ condition ? a : b;
+ }
+
+The matcher
+conditionalOperator(hasTrueExpression(expr().bind("true")))
+matches condition ? a : b,
+with expr() matching a.
Example 2 (conditional binary operator): matches opaqueValueExpr(condition)
- condition ?: b
+Given
+ void foo(bool condition, int a, int b) {
+ condition ?: b;
+ }
+
+The matcher binaryConditionalOperator(hasTrueExpression(expr()))
+matches condition ?: b,
+with expr() matching conditoin.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>></td><td class="name" onclick="toggle('hasDeclaration15')"><a name="hasDeclaration15Anchor">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="hasDeclaration15"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -6477,17 +8699,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -6505,7 +8735,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int i[5];
void f() { i[1] = 42; }
-arraySubscriptExpression(hasBase(implicitCastExpr(
+The matcher arraySubscriptExpr(hasBase(implicitCastExpr(
hasSourceExpression(declRefExpr()))))
matches i[1] with the declRefExpr() matching i
</pre></td></tr>
@@ -6517,7 +8747,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int i[5];
void f() { i[1] = 42; }
-arraySubscriptExpression(hasIndex(integerLiteral()))
+The matcher arraySubscriptExpr(hasIndex(integerLiteral()))
matches i[1] with the integerLiteral() matching 1
</pre></td></tr>
@@ -6525,16 +8755,30 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasLHS3')"><a name="hasLHS3Anchor">hasLHS</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="hasLHS3"><pre>Matches the left hand side of binary operator expressions.
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasRHS3')"><a name="hasRHS3Anchor">hasRHS</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="hasRHS3"><pre>Matches the right hand side of binary operator expressions.
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
</pre></td></tr>
@@ -6546,8 +8790,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
struct A {};
A a[7];
int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
+
+
+The matcher arrayType(hasElementType(builtinType()))
+int[7]
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
</pre></td></tr>
@@ -6559,8 +8805,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
_Atomic(int) i;
_Atomic(float) f;
-atomicType(hasValueType(isInteger()))
- matches "_Atomic(int) i"
+The matcher atomicType(hasValueType(isInteger()))
+_Atomic(int).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>
</pre></td></tr>
@@ -6575,8 +8821,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
auto a = 1;
auto b = 2.0;
-autoType(hasDeducedType(isInteger()))
- matches "auto a"
+
+The matcher
+varDecl(hasType(autoType(hasDeducedType(isInteger()))))
+matches auto a = 1, but does not match auto b = 2.0.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>
</pre></td></tr>
@@ -6588,21 +8836,54 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
namespace X { void b(); }
using X::b;
-usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
- matches using X::b </pre></td></tr>
+
+The matcher 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 or fold expression matches.
+
+Given
+ struct S {};
+ bool operator ==(const S&, const S&);
+
+ void f(int a, const S&lhs, const S&rhs) {
+ a + 0;
+ lhs == rhs;
+ lhs != rhs;
+ }
+
+ template <typename ...Ts>
+ auto sum(Ts... args) {
+ return (0 + ... + args);
+ }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
</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('hasLHS0')"><a name="hasLHS0Anchor">hasLHS</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="hasLHS0"><pre>Matches the left hand side of binary operator expressions.
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
</pre></td></tr>
@@ -6610,27 +8891,40 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperands0"><pre>Matches if both matchers match with opposite sides of the binary operator
or fold expression.
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
- integerLiteral(equals(2)))
- 1 + 2 // Match
- 2 + 1 // Match
- 1 + 1 // No match
- 2 + 2 // No match
+Given
+void foo() {
+ 1 + 2; // Match
+ 2 + 1; // Match
+ 1 + 1; // No match
+ 2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+ integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
</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('hasRHS0')"><a name="hasRHS0Anchor">hasRHS</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="hasRHS0"><pre>Matches the right hand side of binary operator expressions.
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>></td><td class="name" onclick="toggle('forDecomposition0')"><a name="forDecomposition0Anchor">forDecomposition</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="forDecomposition0"><pre>Matches the DecompositionDecl the binding belongs to.
-For example, in:
+Given
void foo()
{
int arr[3];
@@ -6638,10 +8932,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
f = 42;
}
-The matcher:
- bindingDecl(hasName("f"),
- forDecomposition(decompositionDecl())
-matches 'f' in 'auto &[f, s, t]'.
+
+The matcher bindingDecl(hasName("f"),
+ forDecomposition(decompositionDecl()))
+matches f in 'auto &[f, s, t]'.
</pre></td></tr>
@@ -6653,23 +8947,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x, int y, int z) {} };
-cxxMethodDecl(hasAnyParameter(hasName("y")))
- matches f(int x, int y, int z) {}
+
+The matcher cxxMethodDecl(hasAnyParameter(hasName("y")))
+ matches f
with hasAnyParameter(...)
matching int y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
+
the matcher objcMethodDecl(hasAnyParameter(hasName("y")))
-matches the declaration of method f with hasParameter
+ matches the declaration of method f with hasParameter
matching y.
For blocks, given
b = ^(int y) { printf("%d", y) };
+
the matcher blockDecl(hasAnyParameter(hasName("y")))
-matches the declaration of the block b with hasParameter
+ matches the declaration of the block b with hasParameter
matching y.
</pre></td></tr>
@@ -6680,15 +8977,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x) {} };
-cxxMethodDecl(hasParameter(0, hasType(varDecl())))
- matches f(int x) {}
+
+The matcher
+cxxMethodDecl(hasParameter(0, hasType(asString("int"))))
+matches f
with hasParameter(...)
- matching int x
+matching int x.
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
-the matcher objcMethodDecl(hasParameter(0, hasName("y")))
+
+The matcher objcMethodDecl(hasParameter(0, hasName("y")))
matches the declaration of method f with hasParameter
matching y.
</pre></td></tr>
@@ -6697,19 +8997,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc0')"><a name="hasTypeLoc0Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc0"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -6728,10 +9035,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
+ const int *b;
+ int * const c = nullptr;
+ const float *f;
+
+The matcher pointerType(pointee(isConstQualified(), isInteger()))
+matches const int *,
+but does not match int * const
+or const float *.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
@@ -6741,19 +9052,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasTypeLoc1')"><a name="hasTypeLoc1Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc1"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -6776,21 +9094,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
declaration of x.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- cxxRecordDecl(hasName("X"))))
class X {};
void y(X &x) { x; X z; }
class Y { friend class X; };
class Z : public virtual X {};
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z.
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X.
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches
+class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
+
+Given
class Base {};
class Derived : Base {};
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))
+matches class Derived : Base {}.
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -6800,17 +9128,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasType4"><pre>Matches if the expression's or declaration's type matches a type
matcher.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and U (matcher = typedefDecl(hasType(asString("int")))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- asString("class X")))
+Exmaple
class X {};
void y(X &x) { x; X z; }
typedef int U;
class Y { friend class X; };
class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
</pre></td></tr>
@@ -6820,8 +9156,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f(int i);
int y;
- f(y);
-callExpr(
+ void foo() {
+ f(y);
+ }
+The matcher callExpr(
forEachArgumentWithParam(
declRefExpr(to(varDecl(hasName("y")))),
parmVarDecl(hasType(isInteger()))
@@ -6844,14 +9182,15 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f(int i);
- int y;
- f(y);
- void (*f_ptr)(int) = f;
- f_ptr(y);
-callExpr(
+ void foo(int y) {
+ f(y);
+ void (*f_ptr)(int) = f;
+ f_ptr(y);
+ }
+The matcher callExpr(
forEachArgumentWithParamType(
declRefExpr(to(varDecl(hasName("y")))),
- qualType(isInteger()).bind("type)
+ qualType(isInteger()).bind("type")
))
matches f(y) and f_ptr(y)
with declRefExpr(...)
@@ -6866,17 +9205,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
expression, or an ObjC-message-send expression.
Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
+ void x(int, int, int) { int y = 42; x(1, y, 42); }
+The matcher
+callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches
+x(1, y, 42) with hasAnyArgument(...)
matching y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
void foo(I *i) { [i f:12]; }
+
+The matcher
objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))
- matches [i f:12]
+matches [i f:12]
</pre></td></tr>
@@ -6884,15 +9225,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasArgument1"><pre>Matches the n'th argument of a call expression or a constructor
call expression.
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasDeclaration13')"><a name="hasDeclaration13Anchor">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="hasDeclaration13"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -6902,17 +9245,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -6929,10 +9280,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class A { A() : i(42), j(42) {} int i; int j; };
-cxxConstructorDecl(forEachConstructorInitializer(
- forField(decl().bind("x"))
-))
- will trigger two matches, binding for 'i' and 'j' respectively.
+
+The matcher cxxConstructorDecl(forEachConstructorInitializer(
+ forField(fieldDecl().bind("x"))))
+matches the constructor of A twice, with
+fieldDecl() matching i and
+j respectively.
</pre></td></tr>
@@ -6944,10 +9297,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Foo() : foo_(1) { }
int foo_;
};
-cxxRecordDecl(has(cxxConstructorDecl(
+
+The matcher cxxRecordDecl(has(cxxConstructorDecl(
hasAnyConstructorInitializer(anything())
)))
- record matches Foo, hasAnyConstructorInitializer matches foo_(1)
+matches Foo, hasAnyConstructorInitializer matches foo_(1)
</pre></td></tr>
@@ -6959,9 +9313,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Foo() : foo_(1) { }
int foo_;
};
+
+The matcher
cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
forField(hasName("foo_"))))))
- matches Foo
+matches Foo
with forField matching foo_
</pre></td></tr>
@@ -6969,19 +9325,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('hasTypeLoc2')"><a name="hasTypeLoc2Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc2"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -7002,9 +9365,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Foo() : foo_(1) { }
int foo_;
};
+
+The matcher
cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
withInitializer(integerLiteral(equals(1)))))))
- matches Foo
+matches Foo
with withInitializer matching (1)
</pre></td></tr>
@@ -7019,11 +9384,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int m;
int f(X x) { x.m; return m; }
};
+
+
+The matcher
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
- matches `x.m`, but not `m`; however,
-memberExpr(hasObjectExpression(hasType(pointsTo(
- cxxRecordDecl(hasName("X"))))))
- matches `m` (aka. `this->m`), but not `x.m`.
+matches x.m, but not m; however,
+The matcher memberExpr(hasObjectExpression(hasType(pointsTo(
+cxxRecordDecl(hasName("X"))))))
+matches m (aka. this->m), but not x.m.
</pre></td></tr>
@@ -7033,12 +9401,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class Y { void x() { this->x(); x(); Y y; y.x(); } };
void f() { f(); }
-callExpr(callee(expr()))
- matches this->x(), x(), y.x(), f()
-with callee(...)
- matching this->x, x, y.x, f respectively
+
+The matcher callExpr(callee(expr().bind("callee")))
+matches this->x(), x(), y.x(), f()
+with expr() inside of callee
+matching this->x, x,
+y.x, f respectively
Given
+ struct Dummy {};
+ // makes sure there is a callee, otherwise there would be no callee,
+ // just a builtin operator
+ Dummy operator+(Dummy, Dummy);
+ // not defining a '*' operator
+
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -7048,10 +9424,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
-cxxFoldExpr(callee(expr()))
- matches (args * ... * 1)
-with callee(...)
- matching *
+
+The matcher cxxFoldExpr(callee(expr().bind("op")))
+matches (0 + ... + args)
+with callee(...) matching *,
+but does not match (args * ... * 1).
+A CXXFoldExpr only has an UnresolvedLookupExpr as a callee.
+When there are no define operators that could be used instead of builtin
+ones, then there will be no callee .
Note: Callee cannot take the more general internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>
because this introduces ambiguous overloads with calls to Callee taking a
@@ -7063,16 +9443,37 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasEitherOperand2')"><a name="hasEitherOperand2Anchor">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="hasEitherOperand2"><pre>Matches if either the left hand side or the right hand side of a
binary operator or fold expression matches.
+
+Given
+ struct S {};
+ bool operator ==(const S&, const S&);
+
+ void f(int a, const S&lhs, const S&rhs) {
+ a + 0;
+ lhs == rhs;
+ lhs != rhs;
+ }
+
+ template <typename ...Ts>
+ auto sum(Ts... args) {
+ return (0 + ... + args);
+ }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasFoldInit0')"><a name="hasFoldInit0Anchor">hasFoldInit</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMacher</td></tr>
<tr><td colspan="4" class="doc" id="hasFoldInit0"><pre>Matches the operand that does not contain the parameter pack.
-Example matches `(0 + ... + args)` and `(args * ... * 1)`
- (matcher = cxxFoldExpr(hasFoldInit(expr())))
- with hasFoldInit(...)
- matching `0` and `1` respectively
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -7082,14 +9483,27 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
+
+
+The matcher cxxFoldExpr(hasFoldInit(expr().bind("init")))
+matches (0 + ... + args) and (args * ... * 1)
+with hasFoldInit(expr().bind("init")) matching
+0 and 1.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasLHS4')"><a name="hasLHS4Anchor">hasLHS</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="hasLHS4"><pre>Matches the left hand side of binary operator expressions.
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
</pre></td></tr>
@@ -7097,22 +9511,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperands2"><pre>Matches if both matchers match with opposite sides of the binary operator
or fold expression.
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
- integerLiteral(equals(2)))
- 1 + 2 // Match
- 2 + 1 // Match
- 1 + 1 // No match
- 2 + 2 // No match
+Given
+void foo() {
+ 1 + 2; // Match
+ 2 + 1; // Match
+ 1 + 1; // No match
+ 2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+ integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasPattern0')"><a name="hasPattern0Anchor">hasPattern</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMacher</td></tr>
<tr><td colspan="4" class="doc" id="hasPattern0"><pre>Matches the operand that contains the parameter pack.
-Example matches `(0 + ... + args)`
- (matcher = cxxFoldExpr(hasPattern(expr())))
- with hasPattern(...)
- matching `args`
+Given
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -7122,14 +9539,27 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
+
+
+The matcher cxxFoldExpr(hasPattern(expr().bind("pattern")))
+matches (0 + ... + args) and (args * ... * 1),
+with hasPattern(expr().bind("pattern")) matching
+args two times.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasRHS4')"><a name="hasRHS4Anchor">hasRHS</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="hasRHS4"><pre>Matches the right hand side of binary operator expressions.
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
</pre></td></tr>
@@ -7140,27 +9570,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasInitStatement2')"><a name="hasInitStatement2Anchor">hasInitStatement</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasInitStatement2"><pre>Matches selection statements with initializer.
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
void foo() {
if (int i = foobar(); i > 0) {}
switch (int i = foobar(); i) {}
@@ -7171,51 +9606,71 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
switch (foobar()) {}
for (auto& x : get_range()) {}
}
-ifStmt(hasInitStatement(anything()))
- matches the if statement in foo but not in bar.
-switchStmt(hasInitStatement(anything()))
- matches the switch statement in foo but not in bar.
-cxxForRangeStmt(hasInitStatement(anything()))
- matches the range for statement in foo but not in bar.
+
+The matcher ifStmt(hasInitStatement(anything()))
+ matches the if statement if (int i = foobar(); i > 0) {}
+ in foo but not if (foobar() > 0) {} in bar.
+The matcher switchStmt(hasInitStatement(anything()))
+ matches the switch statement switch (int i = foobar(); i) {}
+ in foo but not switch (foobar()) {} in bar.
+The matcher cxxForRangeStmt(hasInitStatement(anything()))
+ matches the range for statement
+ for (auto& a = get_range(); auto& x : a) {} in foo
+ but not for (auto& x : get_range()) {} in bar.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasLoopVariable0')"><a name="hasLoopVariable0Anchor">hasLoopVariable</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasLoopVariable0"><pre>Matches the initialization statement of a for loop.
-Example:
- forStmt(hasLoopVariable(anything()))
-matches 'int x' in
+Given
+ void foo() {
+ int a[42] = {};
for (int x : a) { }
+ }
+
+The matcher cxxForRangeStmt(hasLoopVariable(anything()))
+matches for (int x : a) { }
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasRangeInit0')"><a name="hasRangeInit0Anchor">hasRangeInit</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="hasRangeInit0"><pre>Matches the range initialization statement of a for loop.
-Example:
- forStmt(hasRangeInit(anything()))
-matches 'a' in
+Given
+ void foo() {
+ int a[42] = {};
for (int x : a) { }
+ }
+
+The matcher cxxForRangeStmt(hasRangeInit(anything()))
+matches for (int x : a) { }
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc3')"><a name="hasTypeLoc3Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc3"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -7235,13 +9690,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class Y { public: void m(); };
Y g();
- class X : public Y { void g(); };
+ class X : public Y { public: void g(); };
void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); }
-cxxMemberCallExpr(onImplicitObjectArgument(hasType(
+
+The matcher cxxMemberCallExpr(onImplicitObjectArgument(hasType(
cxxRecordDecl(hasName("Y")))))
- matches `y.m()`, `x.m()` and (`g()).m()`, but not `x.g()`).
-cxxMemberCallExpr(on(callExpr()))
- only matches `(g()).m()` (the parens are ignored).
+matches y.m(), x.m() and (g()).m()
+but does not match x.g().
+The matcher cxxMemberCallExpr(on(callExpr()))
+only matches (g()).m(), because the parens are ignored.
+FIXME: should they be ignored? (ignored bc of `on`)
FIXME: Overload to allow directly matching types?
</pre></td></tr>
@@ -7256,12 +9714,15 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Y g();
class X : public Y {};
void z(Y y, X x) { y.m(); (g()).m(); x.m(); }
+
+The matcher
cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))
- matches `y.m()` and `(g()).m()`.
+ matches y.m() and (g()).m().
+The matcher
cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))))
- matches `x.m()`.
-cxxMemberCallExpr(on(callExpr()))
- matches `(g()).m()`.
+ matches x.m().
+The matcher cxxMemberCallExpr(on(callExpr()))
+ matches (g()).m().
FIXME: Overload to allow directly matching types?
</pre></td></tr>
@@ -7269,24 +9730,35 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType1')"><a name="thisPointerType1Anchor">thisPointerType</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="thisPointerType1"><pre>Overloaded to match the type's declaration.
+
+Given
+ class Y { public: void m(); };
+ class X : public Y { public: void g(); };
+ void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher cxxMemberCallExpr(thisPointerType(
+ cxxRecordDecl(hasName("Y"))))
+ matches y.m(), p->m() and x.m().
+The matcher cxxMemberCallExpr(thisPointerType(
+ cxxRecordDecl(hasName("X"))))
+ matches x.g().
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType0')"><a name="thisPointerType0Anchor">thisPointerType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="thisPointerType0"><pre>Matches if the type of the expression's implicit object argument either
-matches the InnerMatcher, or is a pointer to a type that matches the
+ matches the InnerMatcher, or is a pointer to a type that matches the
InnerMatcher.
Given
- class Y { public: void m(); };
- class X : public Y { void g(); };
- void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
- cxxRecordDecl(hasName("Y")))))
- matches `y.m()`, `p->m()` and `x.m()`.
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
- cxxRecordDecl(hasName("X")))))
- matches `x.g()`.
+ class Y { public: void m() const; };
+ class X : public Y { public: void g(); };
+ void z() { const Y y; y.m(); const Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher
+cxxMemberCallExpr(thisPointerType(isConstQualified()))
+matches y.m(), x.m() and p->m(),
+but not x.g().
</pre></td></tr>
@@ -7298,19 +9770,27 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
class A { virtual void f(); };
class B : public A { void f(); };
class C : public B { void f(); };
-cxxMethodDecl(ofClass(hasName("C")),
- forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
- matches once, with "b" binding "A::f" and "d" binding "C::f" (Note
- that B::f is not overridden by C::f).
+
+The matcher cxxMethodDecl(ofClass(hasName("C")),
+ forEachOverridden(cxxMethodDecl().bind("b")))
+matches void f() of C ,
+with cxxMethodDecl() matching
+virtual void f() of A ,
+but the matcher does not match void f() of B because
+it is not overridden by C::f.
The check can produce multiple matches in case of multiple inheritance, e.g.
class A1 { virtual void f(); };
class A2 { virtual void f(); };
class C : public A1, public A2 { void f(); };
-cxxMethodDecl(ofClass(hasName("C")),
- forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
- matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and
- once with "b" binding "A2::f" and "d" binding "C::f".
+
+The matcher cxxMethodDecl(ofClass(hasName("C")),
+ forEachOverridden(cxxMethodDecl().bind("b")))
+matches void f() of C with the inner
+cxxMethodDecl() matching virtual void f()
+inside of A1 , and void f() of C with the inner
+cxxMethodDecl() matching virtual void f()
+inside of A2.
</pre></td></tr>
@@ -7322,40 +9802,52 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
FIXME: What other kind of declarations would we need to generalize
this to?
-Example matches A() in the last line
- (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl(
- ofClass(hasName("A"))))))
+Given
class A {
public:
A();
+ void foo();
};
- A a = A();
+
+The matcher cxxMethodDecl(ofClass(hasName("A")))
+matches A() and void foo().
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasAnyPlacementArg0')"><a name="hasAnyPlacementArg0Anchor">hasAnyPlacementArg</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="hasAnyPlacementArg0"><pre>Matches any placement new expression arguments.
-Given:
+Given
+ void* operator new(decltype(sizeof(void*)), void*);
+ struct MyClass { int x; };
+ unsigned char Storage[sizeof(MyClass) * 10];
MyClass *p1 = new (Storage) MyClass();
-cxxNewExpr(hasAnyPlacementArg(anything()))
- matches the expression 'new (Storage, 16) MyClass()'.
+
+
+The matcher cxxNewExpr(hasAnyPlacementArg(anything()))
+matches new (Storage) MyClass().
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasArraySize0')"><a name="hasArraySize0Anchor">hasArraySize</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="hasArraySize0"><pre>Matches array new expressions with a given array size.
-Given:
+Given
+ void* operator new(decltype(sizeof(void*)));
+ struct MyClass { int x; };
MyClass *p1 = new MyClass[10];
-cxxNewExpr(hasArraySize(integerLiteral(equals(10))))
- matches the expression 'new MyClass[10]'.
+
+
+The matcher
+cxxNewExpr(hasArraySize(
+ ignoringImplicit(integerLiteral(equals(10)))))
+matches new MyClass[10].
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasDeclaration12')"><a name="hasDeclaration12Anchor">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="hasDeclaration12"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -7365,17 +9857,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -7390,29 +9890,42 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasPlacementArg0')"><a name="hasPlacementArg0Anchor">hasPlacementArg</a></td><td>unsigned Index, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasPlacementArg0"><pre>Matches placement new expression arguments.
-Given:
- MyClass *p1 = new (Storage, 16) MyClass();
-cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
- matches the expression 'new (Storage, 16) MyClass()'.
+Given
+ void *operator new(decltype(sizeof(void*)), int, void*);
+ struct MyClass { int x; };
+ unsigned char Storage[sizeof(MyClass) * 10];
+ MyClass *p1 = new (16, Storage) MyClass();
+
+
+The matcher cxxNewExpr(hasPlacementArg(0,
+ integerLiteral(equals(16))))
+matches new (16, Storage) MyClass().
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc4')"><a name="hasTypeLoc4Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc4"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -7428,14 +9941,45 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasEitherOperand1')"><a name="hasEitherOperand1Anchor">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="hasEitherOperand1"><pre>Matches if either the left hand side or the right hand side of a
binary operator or fold expression matches.
+
+Given
+ struct S {};
+ bool operator ==(const S&, const S&);
+
+ void f(int a, const S&lhs, const S&rhs) {
+ a + 0;
+ lhs == rhs;
+ lhs != rhs;
+ }
+
+ template <typename ...Ts>
+ auto sum(Ts... args) {
+ return (0 + ... + args);
+ }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasLHS1')"><a name="hasLHS1Anchor">hasLHS</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="hasLHS1"><pre>Matches the left hand side of binary operator expressions.
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
</pre></td></tr>
@@ -7443,44 +9987,64 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperands1"><pre>Matches if both matchers match with opposite sides of the binary operator
or fold expression.
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
- integerLiteral(equals(2)))
- 1 + 2 // Match
- 2 + 1 // Match
- 1 + 1 // No match
- 2 + 2 // No match
+Given
+void foo() {
+ 1 + 2; // Match
+ 2 + 1; // Match
+ 1 + 1; // No match
+ 2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+ integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasRHS1')"><a name="hasRHS1Anchor">hasRHS</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="hasRHS1"><pre>Matches the right hand side of binary operator expressions.
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasUnaryOperand1')"><a name="hasUnaryOperand1Anchor">hasUnaryOperand</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="hasUnaryOperand1"><pre>Matches if the operand of a unary operator matches.
-Example matches true (matcher = hasUnaryOperand(
- cxxBoolLiteral(equals(true))))
- !true
+void foo() {
+ !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasAnyBase0')"><a name="hasAnyBase0Anchor">hasAnyBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> BaseSpecMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyBase0"><pre>Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
-Example:
-matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
- class Foo;
+Given
+ class Foo {};
class Bar : Foo {};
class Baz : Bar {};
- class SpecialBase;
+ class SpecialBase {};
class Proxy : SpecialBase {}; // matches Proxy
class IndirectlyDerived : Proxy {}; //matches IndirectlyDerived
+
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy and IndirectlyDerived
FIXME: Refactor this and isDerivedFrom to reuse implementation.
</pre></td></tr>
@@ -7488,26 +10052,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasDirectBase0')"><a name="hasDirectBase0Anchor">hasDirectBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> BaseSpecMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDirectBase0"><pre>Matches C++ classes that have a direct base matching BaseSpecMatcher.
-Example:
-matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
- class Foo;
+Given
+ class Foo {};
class Bar : Foo {};
class Baz : Bar {};
- class SpecialBase;
+ class SpecialBase {};
class Proxy : SpecialBase {}; // matches Proxy
class IndirectlyDerived : Proxy {}; // doesn't match
+
+The matcher
+cxxRecordDecl(hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
-Given:
+Given
class A { void func(); };
class B { void member(); };
-cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
-A but not B.
+
+The matcher cxxRecordDecl(hasMethod(hasName("func")))
+matches the declaration of class A { void func(); }
+but does not match class B { void member(); }
</pre></td></tr>
@@ -7519,22 +10088,29 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Note that a class is not considered to be derived from itself.
Example matches Y, Z, C (Base == hasName("X"))
- class X;
+ class X {};
class Y : public X {}; // directly derived
class Z : public Y {}; // indirectly derived
typedef X A;
typedef A B;
class C : public B {}; // derived from a typedef of X
-In the following example, Bar matches isDerivedFrom(hasName("X")):
- class Foo;
- typedef Foo X;
- class Bar : public Foo {}; // derived from a type that X is a typedef of
+ class Foo {};
+ typedef Foo Alias;
+ class Bar : public Alias {};
+ // derived from a type that Alias is a typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom(hasName("X")))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo")))
+matches Bar.
In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
@interface NSObject @end
@interface Bar : NSObject @end
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>
</pre></td></tr>
@@ -7545,38 +10121,90 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Note that a class is not considered to be derived from itself.
-Example matches Y, C (Base == hasName("X"))
- class X;
+Given
+ class X {};
class Y : public X {}; // directly derived
class Z : public Y {}; // indirectly derived
typedef X A;
typedef A B;
class C : public B {}; // derived from a typedef of X
+The matcher
+cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X"))))
+matches Y and C (Base == hasName("X")
+
In the following example, Bar matches isDerivedFrom(hasName("X")):
- class Foo;
+ class Foo {};
typedef Foo X;
class Bar : public Foo {}; // derived from a type that X is a typedef of
+
+The matcher cxxRecordDecl(isDerivedFrom(hasName("X")))
+matches Bar
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
match Base.
+
+Given
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand3')"><a name="hasEitherOperand3Anchor">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="hasEitherOperand3"><pre>Matches if either the left hand side or the right hand side of a
binary operator or fold expression matches.
+
+Given
+ struct S {};
+ bool operator ==(const S&, const S&);
+
+ void f(int a, const S&lhs, const S&rhs) {
+ a + 0;
+ lhs == rhs;
+ lhs != rhs;
+ }
+
+ template <typename ...Ts>
+ auto sum(Ts... args) {
+ return (0 + ... + args);
+ }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasLHS2')"><a name="hasLHS2Anchor">hasLHS</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="hasLHS2"><pre>Matches the left hand side of binary operator expressions.
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
</pre></td></tr>
@@ -7584,39 +10212,59 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasOperands3"><pre>Matches if both matchers match with opposite sides of the binary operator
or fold expression.
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
- integerLiteral(equals(2)))
- 1 + 2 // Match
- 2 + 1 // Match
- 1 + 1 // No match
- 2 + 2 // No match
+Given
+void foo() {
+ 1 + 2; // Match
+ 2 + 1; // Match
+ 1 + 1; // No match
+ 2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+ integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasRHS2')"><a name="hasRHS2Anchor">hasRHS</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="hasRHS2"><pre>Matches the right hand side of binary operator expressions.
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
+Given
+void foo(bool a, bool b) {
+ a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc5')"><a name="hasTypeLoc5Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc5"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -7634,17 +10282,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
expression, or an ObjC-message-send expression.
Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
+ void x(int, int, int) { int y = 42; x(1, y, 42); }
+The matcher
+callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches
+x(1, y, 42) with hasAnyArgument(...)
matching y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
void foo(I *i) { [i f:12]; }
+
+The matcher
objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))
- matches [i f:12]
+matches [i f:12]
</pre></td></tr>
@@ -7652,28 +10302,37 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasArgument2"><pre>Matches the n'th argument of a call expression or a constructor
call expression.
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc6')"><a name="hasTypeLoc6Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc6"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -7691,19 +10350,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
given matcher; or 2) if the Obj-C message expression's callee's method
declaration matches the given matcher.
-Example matches y.x() (matcher = callExpr(callee(
- cxxMethodDecl(hasName("x")))))
+Example 1
class Y { public: void x(); };
void z() { Y y; y.x(); }
-Example 2. Matches [I foo] with
-objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+The matcher callExpr(callee(cxxMethodDecl(hasName("x"))))
+matches y.x()
+Example 2
@interface I: NSObject
+(void)foo;
@end
...
[I foo]
+
+The matcher
+objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+matches [I foo]
</pre></td></tr>
@@ -7713,12 +10376,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class Y { void x() { this->x(); x(); Y y; y.x(); } };
void f() { f(); }
-callExpr(callee(expr()))
- matches this->x(), x(), y.x(), f()
-with callee(...)
- matching this->x, x, y.x, f respectively
+
+The matcher callExpr(callee(expr().bind("callee")))
+matches this->x(), x(), y.x(), f()
+with expr() inside of callee
+matching this->x, x,
+y.x, f respectively
Given
+ struct Dummy {};
+ // makes sure there is a callee, otherwise there would be no callee,
+ // just a builtin operator
+ Dummy operator+(Dummy, Dummy);
+ // not defining a '*' operator
+
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
@@ -7728,10 +10399,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
auto multiply(Args... args) {
return (args * ... * 1);
}
-cxxFoldExpr(callee(expr()))
- matches (args * ... * 1)
-with callee(...)
- matching *
+
+The matcher cxxFoldExpr(callee(expr().bind("op")))
+matches (0 + ... + args)
+with callee(...) matching *,
+but does not match (args * ... * 1).
+A CXXFoldExpr only has an UnresolvedLookupExpr as a callee.
+When there are no define operators that could be used instead of builtin
+ones, then there will be no callee .
Note: Callee cannot take the more general internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>
because this introduces ambiguous overloads with calls to Callee taking a
@@ -7746,8 +10421,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f(int i);
int y;
- f(y);
-callExpr(
+ void foo() {
+ f(y);
+ }
+The matcher callExpr(
forEachArgumentWithParam(
declRefExpr(to(varDecl(hasName("y")))),
parmVarDecl(hasType(isInteger()))
@@ -7770,14 +10447,15 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void f(int i);
- int y;
- f(y);
- void (*f_ptr)(int) = f;
- f_ptr(y);
-callExpr(
+ void foo(int y) {
+ f(y);
+ void (*f_ptr)(int) = f;
+ f_ptr(y);
+ }
+The matcher callExpr(
forEachArgumentWithParamType(
declRefExpr(to(varDecl(hasName("y")))),
- qualType(isInteger()).bind("type)
+ qualType(isInteger()).bind("type")
))
matches f(y) and f_ptr(y)
with declRefExpr(...)
@@ -7792,17 +10470,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
expression, or an ObjC-message-send expression.
Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
+ void x(int, int, int) { int y = 42; x(1, y, 42); }
+The matcher
+callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches
+x(1, y, 42) with hasAnyArgument(...)
matching y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
void foo(I *i) { [i f:12]; }
+
+The matcher
objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))
- matches [i f:12]
+matches [i f:12]
</pre></td></tr>
@@ -7810,15 +10490,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasArgument0"><pre>Matches the n'th argument of a call expression or a constructor
call expression.
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasDeclaration14')"><a name="hasDeclaration14Anchor">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="hasDeclaration14"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -7828,17 +10510,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -7855,9 +10545,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
extension, matches the constant given in the statement.
Given
- switch (1) { case 1: case 1+1: case 3 ... 4: ; }
-caseStmt(hasCaseConstant(integerLiteral()))
- matches "case 1:"
+ void foo() {
+ switch (1) { case 1: break; case 1+1: break; case 3 ... 4: break; }
+ }
+The matcher
+caseStmt(hasCaseConstant(constantExpr(has(integerLiteral()))))
+matches case 1: break.
</pre></td></tr>
@@ -7865,14 +10558,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasSourceExpression0"><pre>Matches if the cast's source expression
or opaque value's source expression matches the given matcher.
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
+
+Given
+void foo(bool b) {
+ int a = b ?: 1;
+}
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+The matcher
+opaqueValueExpr(hasSourceExpression(
+ implicitCastExpr(has(
+ implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
</pre></td></tr>
@@ -7892,13 +10594,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template <typename T, typename U>
void f(T&& t, U&& u) {}
- bool B = false;
- f(R, B);
-templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
- matches twice, with expr() matching 'R * 2' and 'R * 4'
-functionDecl(forEachTemplateArgument(refersToType(builtinType())))
- matches the specialization f<unsigned, bool> twice, for 'unsigned'
- and 'bool'
+ void foo() {
+ bool B = false;
+ f(R, B);
+ }
+
+The matcher
+templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg"))))
+matches Matrix<int, R * 2, R * 4> twice, with
+expr() matching R * 2 and
+R * 4.
+The matcher
+functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type"))))
+matches the specialization of f twice,
+with qualType() matching
+unsigned and
+bool.
</pre></td></tr>
@@ -7911,9 +10622,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T> class A {};
A<int> a;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
- hasTypeLoc(loc(asString("int")))))))
- matches `A<int> a`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+hasTypeLoc(loc(asString("int"))))))))) matches A<int> a.
</pre></td></tr>
@@ -7927,15 +10640,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<> class A<double> {};
A<int> a;
- template<typename T> f() {};
+ template<typename T> void f() {};
void func() { f<int>(); };
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches class A<int>.
+
+The matcher
+functionDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches the instantiation of f.
</pre></td></tr>
@@ -7943,11 +10660,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasSpecializedTemplate0"><pre>Matches the specialized template of a specialization declaration.
Given
- template<typename T> class A {}; #1
- template<> class A<int> {}; #2
-classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
- matches '#2' with classTemplateDecl() matching the class template
- declaration of 'A' at #1.
+ template<typename T> class A {}; // #1
+ template<> class A<int> {}; // #2
+
+The matcher
+classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl().bind("ctd")))
+matches template<> class A<int> {},
+with classTemplateDecl() matching the class template
+declaration template <typename T> class A {}.
</pre></td></tr>
@@ -7960,9 +10680,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
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`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+hasTypeLoc(loc(asString("double")))))))))
+matches A<double, int> b, but not double> c}.
</pre></td></tr>
@@ -7973,17 +10696,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
+ A<double, int> b;
+ A<int, double> c;
template<typename T> void f() {}
void func() { f<int>(); };
+
+The matcher
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
+matches the specialization class A<double, int>.
-functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher functionDecl(hasTemplateArgument(0,
+ refersToType(asString("int"))))
+matches the specialization of f.
</pre></td></tr>
@@ -7995,8 +10721,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
struct A {};
A a[7];
int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
+
+
+The matcher arrayType(hasElementType(builtinType()))
+int[7]
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
</pre></td></tr>
@@ -8005,19 +10733,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc7')"><a name="hasTypeLoc7Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc7"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -8035,11 +10770,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
a given matcher. Also matches StmtExprs that have CompoundStmt as children.
Given
- { {}; 1+2; }
-hasAnySubstatement(compoundStmt())
- matches '{ {}; 1+2; }'
+void foo() { { {}; 1+2; } }
+The matcher
+compoundStmt(hasAnySubstatement(compoundStmt().bind("compound")))
+{ {}; 1+2; } and { { {}; 1+2; } }
with compoundStmt()
- matching '{}'
+matching {} and { {}; 1+2; }.
</pre></td></tr>
@@ -8050,25 +10786,35 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>></td><td class="name" onclick="toggle('hasDecayedType0')"><a name="hasDecayedType0Anchor">hasDecayedType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerType</td></tr>
<tr><td colspan="4" class="doc" id="hasDecayedType0"><pre>Matches the decayed type, whoes decayed type matches InnerMatcher
+
+Given
+ void f(int i[]) {
+ i[1] = 0;
+ }
+
+The matcher parmVarDecl(hasType(decayedType()))
+matches int i[].
</pre></td></tr>
@@ -8081,15 +10827,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T> class A {};
A<int> a;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
- hasTypeLoc(loc(asString("int")))))))
- matches `A<int> a`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+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_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('hasDeclaration11')"><a name="hasDeclaration11Anchor">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="hasDeclaration11"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -8099,17 +10847,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -8130,9 +10886,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
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`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+hasTypeLoc(loc(asString("double")))))))))
+matches A<double, int> b, but not double> c}.
</pre></td></tr>
@@ -8140,18 +10899,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="throughUsingDecl0"><pre>Matches if a node refers to a declaration through a specific
using shadow declaration.
-Examples:
+Given
namespace a { int f(); }
using a::f;
int x = f();
-declRefExpr(throughUsingDecl(anything()))
- matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
namespace a { class X{}; }
using a::X;
X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
- matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingType.html">UsingType</a>>
</pre></td></tr>
@@ -8161,10 +10922,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="to0"><pre>Matches a DeclRefExpr that refers to a declaration that matches the
specified matcher.
-Example matches x in if(x)
- (matcher = declRefExpr(to(varDecl(hasName("x")))))
- bool x;
- if (x) {}
+Given
+ void foo() {
+ bool x;
+ if (x) {}
+ }
+
+The matcher declRefExpr(to(varDecl(hasName("x"))))
+matches x inside the condition of the if-stmt.
</pre></td></tr>
@@ -8174,16 +10939,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Note that this does not work for global declarations because the AST
breaks up multiple-declaration DeclStmt's into multiple single-declaration
DeclStmt's.
-Example: Given non-global declarations
- int a, b = 0;
- int c;
- int d = 2, e;
-declStmt(containsDeclaration(
+
+Given non-global declarations
+ void foo() {
+ int a, b = 0;
+ int c;
+ int d = 2, e;
+ }
+The matcher declStmt(containsDeclaration(
0, varDecl(hasInitializer(anything()))))
- matches only 'int d = 2, e;', and
-declStmt(containsDeclaration(1, varDecl()))
- matches 'int a, b = 0' as well as 'int d = 2, e;'
- but 'int c;' is not matched.
+matches int d = 2, e;.
+The matcher declStmt(containsDeclaration(1, varDecl()))
+matches int a, b = 0; and int d = 2, e;
+but does not match int c;.
</pre></td></tr>
@@ -8191,29 +10959,39 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasSingleDecl0"><pre>Matches the Decl of a DeclStmt which has a single declaration.
Given
- int a, b;
- int c;
-declStmt(hasSingleDecl(anything()))
- matches 'int c;' but not 'int a, b;'.
+ void foo() {
+ int a, b;
+ int c;
+ }
+The matcher declStmt(hasSingleDecl(anything()))
+matches int c;
+but does not match int a, b;
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc8')"><a name="hasTypeLoc8Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc8"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -8237,8 +11015,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
}
}
-cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
-declaration of class D.
+
+The matcher cxxRecordDecl(hasDeclContext(namedDecl(hasName("M"))))
+ matches the declaration of D.
</pre></td></tr>
@@ -8248,8 +11027,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
decltype(1) a = 1;
decltype(2.0) b = 2.0;
-decltypeType(hasUnderlyingType(isInteger()))
- matches the type of "a"
+
+
+The matcher decltypeType(hasUnderlyingType(isInteger()))
+matches the type decltype(1) of the variable
+declaration of a .
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecltypeType.html">DecltypeType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingType.html">UsingType</a>>
</pre></td></tr>
@@ -8266,16 +11048,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
f = 42;
}
-The matcher:
- decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
-matches the decomposition decl with 'f' bound to "fBinding".
+
+The matcher
+ decompositionDecl(hasAnyBinding(bindingDecl(hasName("f")).bind("fBinding")))
+matches auto &[f, s, t] = arr with 'f' bound to "fBinding".
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecompositionDecl.html">DecompositionDecl</a>></td><td class="name" onclick="toggle('hasBinding0')"><a name="hasBinding0Anchor">hasBinding</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasBinding0"><pre>Matches the Nth binding of a DecompositionDecl.
-For example, in:
+Given
void foo()
{
int arr[3];
@@ -8283,10 +11066,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
f = 42;
}
-The matcher:
- decompositionDecl(hasBinding(0,
- bindingDecl(hasName("f").bind("fBinding"))))
-matches the decomposition decl with 'f' bound to "fBinding".
+
+The matcher decompositionDecl(hasBinding(0,
+ bindingDecl(hasName("f")).bind("fBinding")))
+matches auto &[f, s, t] = arr with 'f' bound to "fBinding".
</pre></td></tr>
@@ -8297,20 +11080,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
@@ -8318,8 +11103,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition3"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
@@ -8334,14 +11124,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
class D {};
class D d;
-elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc()));
- matches the `TypeLoc` of the variable declaration of `c`, but not `d`.
+
+The matcher
+elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc()))
+ matches class C<int>, 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.
+ matches InnerMatcher if the qualifier exists.
Given
namespace N {
@@ -8351,8 +11143,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
}
N::M::D d;
-elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
-matches the type of the variable declaration of d.
+
+The matcher
+elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))))
+ matches the type N::M::D of the variable declaration
+ of d.
</pre></td></tr>
@@ -8362,20 +11157,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
namespace N {
namespace M {
- class D {};
+ enum E { Ok };
}
}
- N::M::D d;
+ N::M::E e = N::M::Ok;
-elaboratedType(namesType(recordType(
-hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
-declaration of d.
+
+The matcher elaboratedType(namesType(enumType()))
+matches the type N::M::E of the declaration of e .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>></td><td class="name" onclick="toggle('hasDeclaration10')"><a name="hasDeclaration10Anchor">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="hasDeclaration10"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -8385,17 +11180,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -8412,25 +11215,37 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
(Note: Clang's AST refers to other conversions as "casts" too, and calls
actual casts "explicit" casts.)
+
+ unsigned int a = (unsigned int)0;
+
+The matcher explicitCastExpr(hasDestinationType(
+qualType(isUnsignedInteger()))) matches (unsigned int)0.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>></td><td class="name" onclick="toggle('hasTypeLoc9')"><a name="hasTypeLoc9Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc9"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -8453,21 +11268,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
declaration of x.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- cxxRecordDecl(hasName("X"))))
class X {};
void y(X &x) { x; X z; }
class Y { friend class X; };
class Z : public virtual X {};
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z.
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X.
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches
+class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
+
+Given
class Base {};
class Derived : Base {};
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))
+matches class Derived : Base {}.
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -8477,17 +11302,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasType0"><pre>Matches if the expression's or declaration's type matches a type
matcher.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and U (matcher = typedefDecl(hasType(asString("int")))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- asString("class X")))
+Exmaple
class X {};
void y(X &x) { x; X z; }
typedef int U;
class Y { friend class X; };
class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
</pre></td></tr>
@@ -8504,15 +11337,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
appear in the C++17 AST.
Given
-
struct H {};
H G();
void f() {
H D = G();
}
-``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
-matches ``H D = G()`` in C++11 through C++17 (and beyond).
+
+The matcher
+varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))
+matches H D = G().
</pre></td></tr>
@@ -8523,19 +11357,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Parentheses and explicit casts are not discarded.
Given
int arr[5];
- int a = 0;
+ const int a = 0;
char b = 0;
const int c = a;
int *d = arr;
long e = (long) 0l;
-The matchers
- varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
- varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
-would match the declarations for a, b, c, and d, but not e.
-While
- varDecl(hasInitializer(integerLiteral()))
- varDecl(hasInitializer(declRefExpr()))
-only match the declarations for a.
+The matcher
+varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
+matches a and b,
+but does not match e.
+The matcher
+varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
+matches c and d.
+
+The matcher
+varDecl(hasInitializer(integerLiteral()))
+matches a,
+but does not match b or e.
+The matcher varDecl(hasInitializer(declRefExpr()))
+does not match c or d.
</pre></td></tr>
@@ -8544,17 +11384,34 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
nodes are stripped off.
Parentheses and explicit casts are not discarded.
+
Given
- class C {};
- C a = C();
- C b;
- C c = b;
-The matchers
- varDecl(hasInitializer(ignoringImplicit(cxxConstructExpr())))
-would match the declarations for a, b, and c.
-While
- varDecl(hasInitializer(cxxConstructExpr()))
-only match the declarations for b and c.
+ void f(int param) {
+ int a = 0;
+ int b = param;
+ const int c = 0;
+ const int d = param;
+ int e = (0U);
+ int f = (int)0.0;
+ const int g = ((int)(((0))));
+ }
+
+The matcher
+varDecl(hasInitializer(ignoringImplicit(integerLiteral())))
+matches int a = 0 and const int c = 0,
+but not int e = (0U) and ((int)(((0))).
+The matcher
+varDecl(hasInitializer(integerLiteral()))
+matches int a = 0 and const int c = 0,
+but not int e = (0U) and ((int)(((0))).
+
+The matcher
+varDecl(hasInitializer(ignoringImplicit(declRefExpr())))
+matches int b = param and const int d = param.
+The matcher
+varDecl(hasInitializer(declRefExpr()))
+matches neither int b = param nor const int d = param,
+because an l-to-r-value cast happens.
</pre></td></tr>
@@ -8568,12 +11425,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
char b = (0);
void* c = reinterpret_cast<char*>(0);
char d = char(0);
+
The matcher
- varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
-would match the declarations for a, b, c, and d.
-while
- varDecl(hasInitializer(integerLiteral()))
-only match the declaration for a.
+varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
+matches a, b, c
+and d.
+The matcher
+varDecl(hasInitializer(integerLiteral()))
+matches a.
</pre></td></tr>
@@ -8589,14 +11448,21 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
const int c = a;
int *d = (arr);
long e = ((long) 0l);
-The matchers
- varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
- varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
-would match the declarations for a, b, c, and d, but not e.
-while
- varDecl(hasInitializer(integerLiteral()))
- varDecl(hasInitializer(declRefExpr()))
-would only match the declaration for a.
+
+The matcher
+varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
+matches a and b,
+but does not match e.
+The matcher
+varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
+matches c and d.
+
+The matcher
+varDecl(hasInitializer(integerLiteral()))
+matches a,
+but does not match b or e.
+The matcher varDecl(hasInitializer(declRefExpr()))
+does not match c, or d.
</pre></td></tr>
@@ -8606,8 +11472,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
const char* str = ("my-string");
The matcher
- implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral())))
-would match the implicit cast resulting from the assignment.
+implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral())))
+would match the implicit cast resulting from the assignment
+("my-string").
</pre></td></tr>
@@ -8620,10 +11487,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int b = 3;
int c;
};
+
+The matcher
fieldDecl(hasInClassInitializer(integerLiteral(equals(2))))
- matches 'int a;' but not 'int b;'.
-fieldDecl(hasInClassInitializer(anything()))
- matches 'int a;' and 'int b;' but not 'int c;'.
+matches a,
+but does not match b.
+The matcher fieldDecl(hasInClassInitializer(anything()))
+matches a and b,
+but does not match c.
</pre></td></tr>
@@ -8634,20 +11505,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
@@ -8655,28 +11528,38 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition1"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasIncrement0')"><a name="hasIncrement0Anchor">hasIncrement</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasIncrement0"><pre>Matches the increment statement of a for loop.
-Example:
- forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
-matches '++x' in
- for (x; x < N; ++x) { }
+Given
+void foo(int N) {
+ for (int x = 0; x < N; ++x) { }
+}
+The matcher
+forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
+matches for (int x = 0; x < N; ++x) { }
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasLoopInit0')"><a name="hasLoopInit0Anchor">hasLoopInit</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasLoopInit0"><pre>Matches the initialization statement of a for loop.
-Example:
- forStmt(hasLoopInit(declStmt()))
-matches 'int x = 0' in
+Given
+void foo(int N) {
for (int x = 0; x < N; ++x) { }
+}
+The matcher forStmt(hasLoopInit(declStmt()))
+matches for (int x = 0; x < N; ++x) { }
</pre></td></tr>
@@ -8690,21 +11573,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
declaration of x.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- cxxRecordDecl(hasName("X"))))
class X {};
void y(X &x) { x; X z; }
class Y { friend class X; };
class Z : public virtual X {};
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z.
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X.
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches
+class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
+
+Given
class Base {};
class Derived : Base {};
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))
+matches class Derived : Base {}.
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -8714,17 +11607,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasType1"><pre>Matches if the expression's or declaration's type matches a type
matcher.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and U (matcher = typedefDecl(hasType(asString("int")))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- asString("class X")))
+Exmaple
class X {};
void y(X &x) { x; X z; }
typedef int U;
class Y { friend class X; };
class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
</pre></td></tr>
@@ -8744,13 +11645,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template <typename T, typename U>
void f(T&& t, U&& u) {}
- bool B = false;
- f(R, B);
-templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
- matches twice, with expr() matching 'R * 2' and 'R * 4'
-functionDecl(forEachTemplateArgument(refersToType(builtinType())))
- matches the specialization f<unsigned, bool> twice, for 'unsigned'
- and 'bool'
+ void foo() {
+ bool B = false;
+ f(R, B);
+ }
+
+The matcher
+templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg"))))
+matches Matrix<int, R * 2, R * 4> twice, with
+expr() matching R * 2 and
+R * 4.
+The matcher
+functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type"))))
+matches the specialization of f twice,
+with qualType() matching
+unsigned and
+bool.
</pre></td></tr>
@@ -8763,12 +11673,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
void f();
void f() {}
void g();
-functionDecl(hasAnyBody(compoundStmt()))
- matches both 'void f();'
- and 'void f() {}'
+The matcher functionDecl(hasAnyBody(compoundStmt()))
+ matches f
+ and f
with compoundStmt()
- matching '{}'
- but does not match 'void g();'
+ matching {}
+ but does not match void g();
</pre></td></tr>
@@ -8780,23 +11690,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x, int y, int z) {} };
-cxxMethodDecl(hasAnyParameter(hasName("y")))
- matches f(int x, int y, int z) {}
+
+The matcher cxxMethodDecl(hasAnyParameter(hasName("y")))
+ matches f
with hasAnyParameter(...)
matching int y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
+
the matcher objcMethodDecl(hasAnyParameter(hasName("y")))
-matches the declaration of method f with hasParameter
+ matches the declaration of method f with hasParameter
matching y.
For blocks, given
b = ^(int y) { printf("%d", y) };
+
the matcher blockDecl(hasAnyParameter(hasName("y")))
-matches the declaration of the block b with hasParameter
+ matches the declaration of the block b with hasParameter
matching y.
</pre></td></tr>
@@ -8810,9 +11723,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T> class A {};
A<int> a;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
- hasTypeLoc(loc(asString("int")))))))
- matches `A<int> a`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+hasTypeLoc(loc(asString("int"))))))))) matches A<int> a.
</pre></td></tr>
@@ -8826,15 +11741,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<> class A<double> {};
A<int> a;
- template<typename T> f() {};
+ template<typename T> void f() {};
void func() { f<int>(); };
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches class A<int>.
+
+The matcher
+functionDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches the instantiation of f.
</pre></td></tr>
@@ -8845,20 +11764,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
@@ -8873,15 +11794,27 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
explicit S(double); // #2
operator int(); // #3
explicit operator bool(); // #4
- explicit(false) S(bool) // # 7
- explicit(true) S(char) // # 8
- explicit(b) S(S) // # 9
+ explicit(false) S(bool); // # 7
+ explicit(true) S(char); // # 8
+ explicit(b) S(float); // # 9
};
- S(int) -> S<true> // #5
- explicit S(double) -> S<false> // #6
-cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2.
-cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4.
-cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6.
+ S(int) -> S<true>; // #5
+ explicit S(double) -> S<false>; // #6
+
+The matcher
+cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) matches
+explicit(false) S(bool) and explicit(true) S(char),
+but does not match explicit(b) S(float), S(int) or
+explicit S(double).
+The matcher
+cxxConversionDecl(hasExplicitSpecifier(constantExpr())) does not
+match operator int() or explicit operator bool().
+Matcher
+The matcher
+cxxDeductionGuideDecl(hasExplicitSpecifier(declRefExpr()))
+matches the implicitly generated deduction guide
+auto (float) -> S<b> of the constructor
+S(float)}.
</pre></td></tr>
@@ -8891,15 +11824,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x) {} };
-cxxMethodDecl(hasParameter(0, hasType(varDecl())))
- matches f(int x) {}
+
+The matcher
+cxxMethodDecl(hasParameter(0, hasType(asString("int"))))
+matches f
with hasParameter(...)
- matching int x
+matching int x.
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
-the matcher objcMethodDecl(hasParameter(0, hasName("y")))
+
+The matcher objcMethodDecl(hasParameter(0, hasName("y")))
matches the declaration of method f with hasParameter
matching y.
</pre></td></tr>
@@ -8911,9 +11847,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int f() { return 5; }
void g() {}
-functionDecl(hasReturnTypeLoc(loc(asString("int"))))
- matches the declaration of `f`, but not `g`.
-</pre></td></tr>
+The matcher functionDecl(hasReturnTypeLoc(loc(asString("int"))))
+ matches the declaration of f, but not
+ </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('hasTemplateArgumentLoc2')"><a name="hasTemplateArgumentLoc2Anchor">hasTemplateArgumentLoc</a></td><td>unsigned Index, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>> InnerMatcher</td></tr>
@@ -8925,9 +11861,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
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`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+hasTypeLoc(loc(asString("double")))))))))
+matches A<double, int> b, but not double> c}.
</pre></td></tr>
@@ -8938,27 +11877,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
+ A<double, int> b;
+ A<int, double> c;
template<typename T> void f() {}
void func() { f<int>(); };
+
+The matcher
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
+matches the specialization class A<double, int>.
-functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher functionDecl(hasTemplateArgument(0,
+ refersToType(asString("int"))))
+matches the specialization of f.
</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('returns0')"><a name="returns0Anchor">returns</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="returns0"><pre>Matches the return type of a function declaration.
-Given:
+Given
class X { int f() { return 1; } };
-cxxMethodDecl(returns(asString("int")))
- matches int f() { return 1; }
+
+The matcher cxxMethodDecl(returns(asString("int")))
+ matches f
</pre></td></tr>
@@ -8966,8 +11909,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition0"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
@@ -8975,25 +11923,37 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasConditionVariableStatement0"><pre>Matches the condition variable statement in an if statement.
Given
+struct A {};
+A* GetAPointer();
+void foo() {
if (A* a = GetAPointer()) {}
-hasConditionVariableStatement(...)
- matches 'A* a = GetAPointer()'.
+}
+
+The matcher ifStmt(hasConditionVariableStatement(declStmt()))
+if (A* a = GetAPointer()) {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasElse0')"><a name="hasElse0Anchor">hasElse</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasElse0"><pre>Matches the else-statement of an if statement.
-Examples matches the if statement
- (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
if (false) false; else true;
+}
+
+The matcher ifStmt(hasElse(cxxBoolLiteral(equals(true))))
+if (false) false; else true
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasInitStatement0')"><a name="hasInitStatement0Anchor">hasInitStatement</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasInitStatement0"><pre>Matches selection statements with initializer.
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
void foo() {
if (int i = foobar(); i > 0) {}
switch (int i = foobar(); i) {}
@@ -9004,48 +11964,77 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
switch (foobar()) {}
for (auto& x : get_range()) {}
}
-ifStmt(hasInitStatement(anything()))
- matches the if statement in foo but not in bar.
-switchStmt(hasInitStatement(anything()))
- matches the switch statement in foo but not in bar.
-cxxForRangeStmt(hasInitStatement(anything()))
- matches the range for statement in foo but not in bar.
+
+The matcher ifStmt(hasInitStatement(anything()))
+ matches the if statement if (int i = foobar(); i > 0) {}
+ in foo but not if (foobar() > 0) {} in bar.
+The matcher switchStmt(hasInitStatement(anything()))
+ matches the switch statement switch (int i = foobar(); i) {}
+ in foo but not switch (foobar()) {} in bar.
+The matcher cxxForRangeStmt(hasInitStatement(anything()))
+ matches the range for statement
+ for (auto& a = get_range(); auto& x : a) {} in foo
+ but not for (auto& x : get_range()) {} in bar.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasThen0')"><a name="hasThen0Anchor">hasThen</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasThen0"><pre>Matches the then-statement of an if statement.
-Examples matches the if statement
- (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
if (false) true; else false;
+}
+
+The matcher ifStmt(hasThen(cxxBoolLiteral(equals(true))))
+if (false) true; else false
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>></td><td class="name" onclick="toggle('hasImplicitDestinationType0')"><a name="hasImplicitDestinationType0Anchor">hasImplicitDestinationType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasImplicitDestinationType0"><pre>Matches implicit casts whose destination type matches a given
matcher.
+
+Given
+ unsigned int a = 0;
+
+The matcher
+implicitCastExpr(hasImplicitDestinationType(
+qualType(isUnsignedInteger()))) matches 0.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>></td><td class="name" onclick="toggle('hasInit0')"><a name="hasInit0Anchor">hasInit</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasInit0"><pre>Matches the n'th item of an initializer list expression.
-Example matches y.
- (matcher = initListExpr(hasInit(0, expr())))
- int x{y}.
+Given
+ int y = 42;
+ int x{y};
+
+The matcher initListExpr(hasInit(0, expr()))
+matches {y}.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>></td><td class="name" onclick="toggle('hasSyntacticForm0')"><a name="hasSyntacticForm0Anchor">hasSyntacticForm</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="hasSyntacticForm0"><pre>Matches the syntactic form of init list expressions
(if expression have it).
+
+Given
+ int a[] = { 1, 2 };
+ struct B { int x, y; };
+ struct B b = { 5, 6 };
+
+
+The matcher
+initListExpr(hasSyntacticForm(expr().bind("syntactic")))
+matches { 1, 2 } and { 5, 6 }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>></td><td class="name" onclick="toggle('hasDeclaration9')"><a name="hasDeclaration9Anchor">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="hasDeclaration9"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9055,17 +12044,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9079,7 +12076,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>></td><td class="name" onclick="toggle('hasDeclaration8')"><a name="hasDeclaration8Anchor">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="hasDeclaration8"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9089,17 +12086,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9122,9 +12127,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
auto f = [x](){};
auto g = [x = 1](){};
}
-In the matcher
-lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))),
-capturesVar(hasName("x")) matches `x` and `x = 1`.
+
+The matcher
+lambdaExpr(hasAnyCapture(
+ lambdaCapture(capturesVar(hasName("x"))).bind("capture")))
+matches [x](){} and [x = 1](){}, with
+lambdaCapture(capturesVar(hasName("x"))).bind("capture")
+matching x and x = 1.
</pre></td></tr>
@@ -9133,13 +12142,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int main() {
- int x, y;
+ int x;
+ int y;
float z;
auto f = [=]() { return x + y + z; };
}
-lambdaExpr(forEachLambdaCapture(
- lambdaCapture(capturesVar(varDecl(hasType(isInteger()))))))
-will trigger two matches, binding for 'x' and 'y' respectively.
+
+The matcher lambdaExpr(forEachLambdaCapture(
+ lambdaCapture(capturesVar(
+ varDecl(hasType(isInteger())).bind("captured")))))
+matches [=]() { return x + y + z; } two times,
+with varDecl(hasType(isInteger())) matching
+int x and int y.
</pre></td></tr>
@@ -9151,15 +12165,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int t = 5;
auto f = [=](){ return t; };
}
-lambdaExpr(hasAnyCapture(lambdaCapture())) and
-lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t")))))
- both match `[=](){ return t; }`.
+
+The matcher lambdaExpr(hasAnyCapture(lambdaCapture())) and
+lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("t")))))
+ both match [=](){ return t; }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasDeclaration7')"><a name="hasDeclaration7Anchor">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="hasDeclaration7"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9169,17 +12184,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9201,11 +12224,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int m;
int f(X x) { x.m; return m; }
};
+
+
+The matcher
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
- matches `x.m`, but not `m`; however,
-memberExpr(hasObjectExpression(hasType(pointsTo(
- cxxRecordDecl(hasName("X"))))))
- matches `m` (aka. `this->m`), but not `x.m`.
+matches x.m, but not m; however,
+The matcher memberExpr(hasObjectExpression(hasType(pointsTo(
+cxxRecordDecl(hasName("X"))))))
+matches m (aka. this->m), but not x.m.
</pre></td></tr>
@@ -9214,13 +12240,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
given matcher.
Given
- struct { int first, second; } first, second;
- int i(second.first);
- int j(first.second);
-memberExpr(member(hasName("first")))
- matches second.first
- but not first.second (because the member name there is "second").
-</pre></td></tr>
+ struct { int first = 0, second = 1; } first, second;
+ int i = second.first;
+ int j = first.second;
+
+
+The matcher memberExpr(member(hasName("first")))
+matches second.first
+but not </pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>></td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
@@ -9229,10 +12256,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
+ const int *b;
+ int * const c = nullptr;
+ const float *f;
+
+The matcher pointerType(pointee(isConstQualified(), isInteger()))
+matches const int *,
+but does not match int * const
+or const float *.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
@@ -9246,9 +12277,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
namespace N { template<class T> void f(T t); }
template <class T> void g() { using N::f; f(T()); }
-unresolvedLookupExpr(hasAnyDeclaration(
+
+The matcher unresolvedLookupExpr(hasAnyDeclaration(
namedDecl(hasUnderlyingDecl(hasName("::N::f")))))
- matches the use of f in g() .
+ matches f in g().
</pre></td></tr>
@@ -9258,14 +12290,29 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
struct A { struct B { struct C {}; }; };
A::B::C c;
-nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
- matches "A::"
+
+The matcher
+nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString(
+"struct A"))))) matches A::B::.
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</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="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</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="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+
+Given
+ namespace ns {
+ struct A { static void f(); };
+ void A::f() {}
+ void g() { A::f(); }
+ }
+ ns::A a;
+
+
+The matcher nestedNameSpecifierLoc(loc(specifiesType(
+hasDeclaration(namedDecl(hasName("A")))))) matches A::
+twice.
</pre></td></tr>
@@ -9276,9 +12323,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
struct A { struct B { struct C {}; }; };
A::B::C c;
-nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
+
+The matcher nestedNameSpecifierLoc(specifiesTypeLoc(loc(qualType(
hasDeclaration(cxxRecordDecl(hasName("A")))))))
- matches "A::"
+matches A::
</pre></td></tr>
@@ -9288,8 +12336,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
struct A { struct B { struct C {}; }; };
A::B::C c;
-nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
- matches "A::"
+
+The matcher
+nestedNameSpecifier(hasPrefix(specifiesType(asString(
+"struct A")))) matches struct A::B
</pre></td></tr>
@@ -9300,8 +12350,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
namespace ns { struct A {}; }
ns::A a;
-nestedNameSpecifier(specifiesNamespace(hasName("ns")))
- matches "ns::"
+
+The matcher
+nestedNameSpecifier(specifiesNamespace(hasName("ns"))) matches
+ns.
</pre></td></tr>
@@ -9312,10 +12364,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
struct A { struct B { struct C {}; }; };
A::B::C c;
-nestedNameSpecifier(specifiesType(
+
+The matcher nestedNameSpecifier(specifiesType(
hasDeclaration(cxxRecordDecl(hasName("A")))
))
- matches "A::"
+matches A.
</pre></td></tr>
@@ -9323,12 +12376,16 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyClause0"><pre>Matches any clause in an OpenMP directive.
Given
-
+ void foo() {
#pragma omp parallel
+ ;
#pragma omp parallel default(none)
+ ;
+ }
-``ompExecutableDirective(hasAnyClause(anything()))`` matches
-``omp parallel default(none)``.
+
+The matcher ompExecutableDirective(hasAnyClause(anything()))
+matches #pragma omp parallel default(none).
</pre></td></tr>
@@ -9339,13 +12396,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
If it is, it will never match.
Given
+ void foo() {
+ #pragma omp parallel
+ ;
+ #pragma omp parallel
+ {}
+ }
- #pragma omp parallel
- ;
- #pragma omp parallel
- {}
-``ompExecutableDirective(hasStructuredBlock(nullStmt()))`` will match ``;``
+The matcher
+ompExecutableDirective(hasStructuredBlock(nullStmt().bind("stmt")))
+matches #pragma omp parallel,
+with stmtt() matching {}.
</pre></td></tr>
@@ -9357,22 +12419,29 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Note that a class is not considered to be derived from itself.
Example matches Y, Z, C (Base == hasName("X"))
- class X;
+ class X {};
class Y : public X {}; // directly derived
class Z : public Y {}; // indirectly derived
typedef X A;
typedef A B;
class C : public B {}; // derived from a typedef of X
-In the following example, Bar matches isDerivedFrom(hasName("X")):
- class Foo;
- typedef Foo X;
- class Bar : public Foo {}; // derived from a type that X is a typedef of
+ class Foo {};
+ typedef Foo Alias;
+ class Bar : public Alias {};
+ // derived from a type that Alias is a typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom(hasName("X")))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo")))
+matches Bar.
In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
@interface NSObject @end
@interface Bar : NSObject @end
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>
</pre></td></tr>
@@ -9383,24 +12452,45 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Note that a class is not considered to be derived from itself.
-Example matches Y, C (Base == hasName("X"))
- class X;
+Given
+ class X {};
class Y : public X {}; // directly derived
class Z : public Y {}; // indirectly derived
typedef X A;
typedef A B;
class C : public B {}; // derived from a typedef of X
+The matcher
+cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X"))))
+matches Y and C (Base == hasName("X")
+
In the following example, Bar matches isDerivedFrom(hasName("X")):
- class Foo;
+ class Foo {};
typedef Foo X;
class Bar : public Foo {}; // derived from a type that X is a typedef of
+
+The matcher cxxRecordDecl(isDerivedFrom(hasName("X")))
+matches Bar
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Similar to isDerivedFrom(), but also matches classes that directly
match Base.
+
+Given
+ class X {};
+ class Y : public X {}; // directly derived
+ class Z : public Y {}; // indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
</pre></td></tr>
@@ -9409,19 +12499,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
given matcher; or 2) if the Obj-C message expression's callee's method
declaration matches the given matcher.
-Example matches y.x() (matcher = callExpr(callee(
- cxxMethodDecl(hasName("x")))))
+Example 1
class Y { public: void x(); };
void z() { Y y; y.x(); }
-Example 2. Matches [I foo] with
-objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+The matcher callExpr(callee(cxxMethodDecl(hasName("x"))))
+matches y.x()
+Example 2
@interface I: NSObject
+(void)foo;
@end
...
[I foo]
+
+The matcher
+objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+matches [I foo]
</pre></td></tr>
@@ -9430,17 +12524,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
expression, or an ObjC-message-send expression.
Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
+ void x(int, int, int) { int y = 42; x(1, y, 42); }
+The matcher
+callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches
+x(1, y, 42) with hasAnyArgument(...)
matching y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
void foo(I *i) { [i f:12]; }
+
+The matcher
objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))
- matches [i f:12]
+matches [i f:12]
</pre></td></tr>
@@ -9448,9 +12544,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasArgument3"><pre>Matches the n'th argument of a call expression or a constructor
call expression.
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
</pre></td></tr>
@@ -9458,23 +12556,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasReceiver0"><pre>Matches if the Objective-C message is sent to an instance,
and the inner matcher matches on that instance.
-For example the method call in
+Given
NSString *x = @"hello";
[x containsString:@"h"];
-is matched by
+
+The matcher
objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))
+matches [x containsString:@"h"];
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasReceiverType0')"><a name="hasReceiverType0Anchor">hasReceiverType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>Matches on the receiver of an ObjectiveC Message expression.
-Example
-matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
-matches the [webView ...] message invocation.
NSString *webViewJavaScript = ...
UIWebView *webView = ...
[webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
+
+The matcher objCMessageExpr(hasReceiverType(asString("UIWebView
+*"))) matches
+[webViewstringByEvaluatingJavaScriptFromString:webViewJavascript];
</pre></td></tr>
@@ -9486,23 +12587,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x, int y, int z) {} };
-cxxMethodDecl(hasAnyParameter(hasName("y")))
- matches f(int x, int y, int z) {}
+
+The matcher cxxMethodDecl(hasAnyParameter(hasName("y")))
+ matches f
with hasAnyParameter(...)
matching int y
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
+
the matcher objcMethodDecl(hasAnyParameter(hasName("y")))
-matches the declaration of method f with hasParameter
+ matches the declaration of method f with hasParameter
matching y.
For blocks, given
b = ^(int y) { printf("%d", y) };
+
the matcher blockDecl(hasAnyParameter(hasName("y")))
-matches the declaration of the block b with hasParameter
+ matches the declaration of the block b with hasParameter
matching y.
</pre></td></tr>
@@ -9513,15 +12617,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
class X { void f(int x) {} };
-cxxMethodDecl(hasParameter(0, hasType(varDecl())))
- matches f(int x) {}
+
+The matcher
+cxxMethodDecl(hasParameter(0, hasType(asString("int"))))
+matches f
with hasParameter(...)
- matching int x
+matching int x.
For ObjectiveC, given
@interface I - (void) f:(int) y; @end
-the matcher objcMethodDecl(hasParameter(0, hasName("y")))
+
+The matcher objcMethodDecl(hasParameter(0, hasName("y")))
matches the declaration of method f with hasParameter
matching y.
</pre></td></tr>
@@ -9530,19 +12637,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCPropertyDecl.html">ObjCPropertyDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc10')"><a name="hasTypeLoc10Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc10"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -9559,14 +12673,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasSourceExpression1"><pre>Matches if the cast's source expression
or opaque value's source expression matches the given matcher.
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+Given
+void foo(bool b) {
+ int a = b ?: 1;
+}
+
+The matcher
+opaqueValueExpr(hasSourceExpression(
+ implicitCastExpr(has(
+ implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
</pre></td></tr>
@@ -9581,9 +12704,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
foo(t);
bar(t);
}
-unresolvedLookupExpr(hasAnyDeclaration(
+
+The matcher unresolvedLookupExpr(hasAnyDeclaration(
functionTemplateDecl(hasName("foo"))))
- matches foo in foo(t); but not bar in bar(t);
+matches foo in foo(t);
+but does not match bar in bar(t);
</pre></td></tr>
@@ -9594,8 +12719,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int (*ptr_to_array)[4];
int (*ptr_to_func)(int);
-varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
-ptr_to_func but not ptr_to_array.
+The matcher
+varDecl(hasType(pointsTo(parenType(innerType(functionType())))))
+ matches ptr_to_func but not
+ ptr_to_array.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>>
</pre></td></tr>
@@ -9607,8 +12734,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int* x;
-pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))
- matches `int*`.
+The matcher pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))
+ matches int*.
</pre></td></tr>
@@ -9618,10 +12745,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
+ const int *b;
+ int * const c = nullptr;
+ const float *f;
+
+The matcher pointerType(pointee(isConstQualified(), isInteger()))
+matches const int *,
+but does not match int * const
+or const float *.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
@@ -9631,19 +12762,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
-Given:
+Given
typedef int &int_ref;
int a;
int_ref b = a;
-varDecl(hasType(qualType(referenceType()))))) will not match the
-declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+The matcher varDecl(hasType(qualType(referenceType())))
+does not match int_ref b = a,
+but the matcher
+varDecl(hasType(qualType(hasCanonicalType(referenceType()))))
+does match int_ref b = a.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasDeclaration6')"><a name="hasDeclaration6Anchor">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="hasDeclaration6"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9653,17 +12787,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9681,30 +12823,56 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
void (*fp)(void);
The matcher
- varDecl(hasType(pointerType(pointee(ignoringParens(functionType())))))
-would match the declaration for fp.
+varDecl(hasType(pointerType(pointee(ignoringParens(functionType())))))
+matches fp.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo1')"><a name="pointsTo1Anchor">pointsTo</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="pointsTo1"><pre>Overloaded to match the pointee type's declaration.
+<tr><td colspan="4" class="doc" id="pointsTo1"><pre>Matches if the matched type is a pointer type and the pointee type
+ matches the specified matcher.
+Overloaded to match the pointee type's declaration.
+
+Given
+ class Y { public: void x(); };
+ void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+ cxxRecordDecl(hasName("Y"))))))
+matches y->x()
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo0')"><a name="pointsTo0Anchor">pointsTo</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="pointsTo0"><pre>Matches if the matched type is a pointer type and the pointee type
-matches the specified matcher.
+ matches the specified matcher.
-Example matches y->x()
- (matcher = cxxMemberCallExpr(on(hasType(pointsTo
- cxxRecordDecl(hasName("Y")))))))
+Given
class Y { public: void x(); };
void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+ qualType()))))
+matches y->x()
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('references1')"><a name="references1Anchor">references</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="references1"><pre>Overloaded to match the referenced type's declaration.
+<tr><td colspan="4" class="doc" id="references1"><pre>Matches if the matched type is a reference type and the referenced
+type matches the specified matcher.
+Overloaded to match the referenced type's declaration.
+
+Given
+ class X {
+ void a(X b) {
+ X &x = b;
+ const X &y = b;
+ }
+ };
+
+The matcher
+varDecl(hasType(references(cxxRecordDecl(hasName("X"))))) matches
+X &x = b and const X &y = b.
</pre></td></tr>
@@ -9712,14 +12880,17 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="references0"><pre>Matches if the matched type is a reference type and the referenced
type matches the specified matcher.
-Example matches X &x and const X &y
- (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
+Given
class X {
void a(X b) {
X &x = b;
const X &y = b;
}
};
+
+The matcher
+varDecl(hasType(references(qualType()))) matches
+X &x = b and const X &y = b.
</pre></td></tr>
@@ -9728,16 +12899,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
`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>
+ int* const x = nullptr;
+ const int y = 0;
+
+
+The matcher qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc()))
+matches the type int* of the variable declaration but
+not </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.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9747,17 +12920,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9776,8 +12957,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int x = 3;
int& xx = x;
-referenceTypeLoc(hasReferentLoc(loc(asString("int"))))
- matches `int&`.
+
+
+The matcher referenceTypeLoc(hasReferentLoc(loc(asString("int"))))
+ matches int&.
</pre></td></tr>
@@ -9787,10 +12970,14 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
+ const int *b;
+ int * const c = nullptr;
+ const float *f;
+
+The matcher pointerType(pointee(isConstQualified(), isInteger()))
+matches const int *,
+but does not match int * const
+or const float *.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
@@ -9801,11 +12988,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasReturnValue0"><pre>Matches the return value expression of a return statement
Given
- return a + b;
-hasReturnValue(binaryOperator())
- matches 'return a + b'
-with binaryOperator()
- matching 'a + b'
+ int foo(int a, int b) {
+ return a + b;
+ }
+The matcher
+returnStmt(hasReturnValue(binaryOperator().bind("op"))) matches
+return a + b, with binaryOperator() matching
+a + b.
</pre></td></tr>
@@ -9814,17 +13003,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
a given matcher. Also matches StmtExprs that have CompoundStmt as children.
Given
- { {}; 1+2; }
-hasAnySubstatement(compoundStmt())
- matches '{ {}; 1+2; }'
+void foo() { { {}; 1+2; } }
+The matcher
+compoundStmt(hasAnySubstatement(compoundStmt().bind("compound")))
+{ {}; 1+2; } and { { {}; 1+2; } }
with compoundStmt()
- matching '{}'
+matching {} and { {}; 1+2; }.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('alignOfExpr0')"><a name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
alignof.
+
+Given
+ int align = alignof(int);
+
+
+The matcher alignOfExpr(expr())
+matches alignof(int).
</pre></td></tr>
@@ -9832,26 +13029,30 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="forCallable0"><pre>Matches declaration of the function, method, or block the statement
belongs to.
-Given:
-F& operator=(const F& o) {
- std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
- return *this;
-}
-returnStmt(forCallable(functionDecl(hasName("operator="))))
- matches 'return *this'
- but does not match 'return v > 0'
+Given
+struct F {
+ F& operator=(const F& other) {
+ []() { return 42 == 42; };
+ return *this;
+ }
+};
-Given:
--(void) foo {
+The matcher returnStmt(forFunction(hasName("operator=")))
+matches return *this
+but does not match return 42 == 42.
+
+Given
+void foo {
int x = 1;
dispatch_sync(queue, ^{ int y = 2; });
}
-declStmt(forCallable(objcMethodDecl()))
- matches 'int x = 1'
- but does not match 'int y = 2'.
-whereas declStmt(forCallable(blockDecl()))
- matches 'int y = 2'
- but does not match 'int x = 1'.
+
+The matcher declStmt(forCallable(objcMethodDecl()))
+matches int x = 1
+but does not match int y = 2.
+The matcher declStmt(forCallable(blockDecl()))
+matches int y = 2
+but does not match int x = 1.
</pre></td></tr>
@@ -9860,23 +13061,34 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Deprecated. Use forCallable() to correctly handle the situation when
the declaration is not a function (but a block or an Objective-C method).
-forFunction() not only fails to take non-functions into account but also
-may match the wrong declaration in their presence.
+The matcher forFunction() not only fails to take non-functions
+into account but also may match the wrong declaration in their presence.
-Given:
-F& operator=(const F& o) {
- std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
- return *this;
-}
-returnStmt(forFunction(hasName("operator=")))
- matches 'return *this'
- but does not match 'return v > 0'
+Given
+ struct F {
+ F& operator=(const F& other) {
+ []() { return 42 == 42; };
+ return *this;
+ }
+ };
+
+
+The matcher returnStmt(forFunction(hasName("operator=")))
+matches return *this
+but does not match return 42 == 42.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="sizeOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
sizeof.
+
+Given
+ struct S { double x; double y; };
+ int size = sizeof(struct S);
+
+The matcher sizeOfExpr(expr())
+matches sizeof(struct S).
</pre></td></tr>
@@ -9890,7 +13102,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int i;
double j = F(i);
-substTemplateTypeParmType(hasReplacementType(type())) matches int
+
+The matcher substTemplateTypeParmType(hasReplacementType(type()))
+matches int.
</pre></td></tr>
@@ -9899,11 +13113,18 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
statement. This matcher may produce multiple matches.
Given
- switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
-switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
- matches four times, with "c" binding each of "case 1:", "case 2:",
-"case 3:" and "case 4:", and "s" respectively binding "switch (1)",
-"switch (1)", "switch (2)" and "switch (2)".
+ void foo() {
+ switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+ }
+The matcher
+switchStmt(forEachSwitchCase(caseStmt().bind("c")))
+matches four times, matching
+switch (1) { case 1: case 2: default: switch (2) { case 3:
+case 4: ; } } and
+switch (2) { case 3: case 4: ; }, with
+caseStmt() matching each of case 1:,
+case 2:, case 3:
+and case 4:.
</pre></td></tr>
@@ -9911,15 +13132,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition4"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>></td><td class="name" onclick="toggle('hasInitStatement1')"><a name="hasInitStatement1Anchor">hasInitStatement</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasInitStatement1"><pre>Matches selection statements with initializer.
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
void foo() {
if (int i = foobar(); i > 0) {}
switch (int i = foobar(); i) {}
@@ -9930,18 +13159,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
switch (foobar()) {}
for (auto& x : get_range()) {}
}
-ifStmt(hasInitStatement(anything()))
- matches the if statement in foo but not in bar.
-switchStmt(hasInitStatement(anything()))
- matches the switch statement in foo but not in bar.
-cxxForRangeStmt(hasInitStatement(anything()))
- matches the range for statement in foo but not in bar.
+
+The matcher ifStmt(hasInitStatement(anything()))
+ matches the if statement if (int i = foobar(); i > 0) {}
+ in foo but not if (foobar() > 0) {} in bar.
+The matcher switchStmt(hasInitStatement(anything()))
+ matches the switch statement switch (int i = foobar(); i) {}
+ in foo but not switch (foobar()) {} in bar.
+The matcher cxxForRangeStmt(hasInitStatement(anything()))
+ matches the range for statement
+ for (auto& a = get_range(); auto& x : a) {} in foo
+ but not for (auto& x : get_range()) {} in bar.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>></td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">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="hasDeclaration4"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -9951,17 +13185,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -9976,19 +13218,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>></td><td class="name" onclick="toggle('hasTypeLoc11')"><a name="hasTypeLoc11Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc11"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -10008,10 +13257,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
struct B { int next; };
template<int(B::*next_ptr)> struct A {};
A<&B::next> a;
+
+The matcher
templateSpecializationType(hasAnyTemplateArgument(
- isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
- matches the specialization A<&B::next> with fieldDecl(...) matching
- B::next
+ isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")).bind("next")))))))
+matches the specialization A<&struct B::next>
+with fieldDecl(hasName("next")) matching
+B::next.
</pre></td></tr>
@@ -10023,10 +13275,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
struct B { int next; };
template<int(B::*next_ptr)> struct A {};
A<&B::next> a;
+
+The matcher
classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToDeclaration(fieldDecl(hasName("next")))))
- matches the specialization A<&B::next> with fieldDecl(...) matching
- B::next
+ refersToDeclaration(fieldDecl(hasName("next")).bind("next"))))
+matches the specialization struct A<&B::next>
+with fieldDecl(hasName("next")) matching
+B::next.
</pre></td></tr>
@@ -10036,9 +13291,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<int T> struct C {};
C<42> c;
-classTemplateSpecializationDecl(
+
+The matcher classTemplateSpecializationDecl(
hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
- matches the implicit instantiation of C in C<42>.
+matches the implicitly declared specialization
+struct C<42> from the instantiation for the type of the
+variable c .
</pre></td></tr>
@@ -10049,9 +13307,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<template <typename> class S> class X {};
template<typename T> class Y {};
X<Y> xi;
+
+The matcher
classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToTemplate(templateName())))
- matches the specialization X<Y>
+ refersToTemplate(templateName())))
+matches the specialization class X<Y>
</pre></td></tr>
@@ -10062,9 +13322,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
struct X {};
template<typename T> struct A {};
A<X> a;
+
+The matcher
classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
- recordType(hasDeclaration(recordDecl(hasName("X")))))))
-matches the specialization of struct A generated by A<X>.
+ recordType(hasDeclaration(recordDecl(hasName("X")))))))
+matches the specialization struct A<struct X>.
</pre></td></tr>
@@ -10077,9 +13339,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T> class A {};
A<int> a;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
- hasTypeLoc(loc(asString("int")))))))
- matches `A<int> a`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+hasTypeLoc(loc(asString("int"))))))))) matches A<int> a.
</pre></td></tr>
@@ -10092,9 +13356,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
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`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+hasTypeLoc(loc(asString("double")))))))))
+matches A<double, int> b, but not double> c}.
</pre></td></tr>
@@ -10114,13 +13381,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template <typename T, typename U>
void f(T&& t, U&& u) {}
- bool B = false;
- f(R, B);
-templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
- matches twice, with expr() matching 'R * 2' and 'R * 4'
-functionDecl(forEachTemplateArgument(refersToType(builtinType())))
- matches the specialization f<unsigned, bool> twice, for 'unsigned'
- and 'bool'
+ void foo() {
+ bool B = false;
+ f(R, B);
+ }
+
+The matcher
+templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg"))))
+matches Matrix<int, R * 2, R * 4> twice, with
+expr() matching R * 2 and
+R * 4.
+The matcher
+functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type"))))
+matches the specialization of f twice,
+with qualType() matching
+unsigned and
+bool.
</pre></td></tr>
@@ -10134,21 +13410,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<> class A<double> {};
A<int> a;
- template<typename T> f() {};
+ template<typename T> void f() {};
void func() { f<int>(); };
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches class A<int>.
+
+The matcher
+functionDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches the instantiation of f.
</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('hasDeclaration3')"><a name="hasDeclaration3Anchor">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="hasDeclaration3"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -10158,17 +13438,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -10187,23 +13475,26 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
+ A<double, int> b;
+ A<int, double> c;
template<typename T> void f() {}
void func() { f<int>(); };
+
+The matcher
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
+matches the specialization class A<double, int>.
-functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher functionDecl(hasTemplateArgument(0,
+ refersToType(asString("int"))))
+matches the specialization of f.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>></td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">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="hasDeclaration2"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -10213,17 +13504,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -10238,25 +13537,37 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
QualType-matcher matches.
+
+ int a = 10;
+
+The matcher typeLoc(loc(qualType(isInteger())))
+matches the int of a .
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypedefNameDecl.html">TypedefNameDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc12')"><a name="hasTypeLoc12Anchor">hasTypeLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
<tr><td colspan="4" class="doc" id="hasTypeLoc12"><pre>Matches if the type location of a node matches the inner matcher.
-Examples:
+Given
int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
- matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
+Given
struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
- matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+ loc(asString("Foo"))))
+matches Foo(1, 2).
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>,
@@ -10273,23 +13584,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasType2"><pre>Matches if the expression's or declaration's type matches a type
matcher.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and U (matcher = typedefDecl(hasType(asString("int")))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- asString("class X")))
+Exmaple
class X {};
void y(X &x) { x; X z; }
typedef int U;
class Y { friend class X; };
class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>></td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">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="hasDeclaration1"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -10299,17 +13618,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -10328,8 +13655,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
For example, in:
class A {};
using B = A;
-The matcher type(hasUnqualifiedDesugaredType(recordType())) matches
-both B and A.
+ B b;
+
+The matcher
+varDecl(hasType(hasUnqualifiedDesugaredType(recordType())))
+matches B b.
</pre></td></tr>
@@ -10338,17 +13668,23 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
-unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
- matches sizeof(a) and alignof(c)
+
+The matcher
+unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")))
+matches sizeof(a) and alignof(c)
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasUnaryOperand0')"><a name="hasUnaryOperand0Anchor">hasUnaryOperand</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="hasUnaryOperand0"><pre>Matches if the operand of a unary operator matches.
-Example matches true (matcher = hasUnaryOperand(
- cxxBoolLiteral(equals(true))))
- !true
+void foo() {
+ !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
</pre></td></tr>
@@ -10362,17 +13698,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
int m;
int f(X x) { x.m; return m; }
};
+
+
+The matcher
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
- matches `x.m`, but not `m`; however,
-memberExpr(hasObjectExpression(hasType(pointsTo(
- cxxRecordDecl(hasName("X"))))))
- matches `m` (aka. `this->m`), but not `x.m`.
+matches x.m, but not m; however,
+The matcher memberExpr(hasObjectExpression(hasType(pointsTo(
+cxxRecordDecl(hasName("X"))))))
+matches m (aka. this->m), but not x.m.
</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>></td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">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="hasDeclaration0"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
+ matches the given matcher.
The associated declaration is:
- for type nodes, the declaration of the underlying type
@@ -10382,17 +13721,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
- for CXXNewExpr, the declaration of the operator new
- for ObjCIvarExpr, the declaration of the ivar
-For type nodes, hasDeclaration will generally match the declaration of the
-sugared type. Given
+Given
class X {};
typedef X Y;
Y y;
-in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-typedefDecl. A common use case is to match the underlying, desugared type.
+
+For type nodes, hasDeclaration will generally match the declaration of the
+sugared type, i.e., the matcher
+varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))),
+matches Y y, with
+the matcher decl() matching
+typedef X Y;.
+A common use case is to match the underlying, desugared type.
This can be achieved by using the hasUnqualifiedDesugaredType matcher:
- varDecl(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(decl())))))
-In this matcher, the decl will match the CXXRecordDecl of class X.
+varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(decl().bind("d"))))))
+matches Y y.
+In this matcher, the matcher decl() will match the
+CXXRecordDecl
+class X {};.
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AddrLabelExpr.html">AddrLabelExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>,
@@ -10412,8 +13759,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
namespace X { int a; void b(); }
using X::a;
using X::b;
+
+The matcher
usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
- matches using X::b but not using X::a </pre></td></tr>
+ matches using X::b
+ but not X::a}
+</pre></td></tr>
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingType.html">UsingType</a>></td><td class="name" onclick="toggle('hasUnderlyingType1')"><a name="hasUnderlyingType1Anchor">hasUnderlyingType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
@@ -10422,8 +13773,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
decltype(1) a = 1;
decltype(2.0) b = 2.0;
-decltypeType(hasUnderlyingType(isInteger()))
- matches the type of "a"
+
+
+The matcher decltypeType(hasUnderlyingType(isInteger()))
+matches the type decltype(1) of the variable
+declaration of a .
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DecltypeType.html">DecltypeType</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingType.html">UsingType</a>>
</pre></td></tr>
@@ -10433,18 +13787,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="throughUsingDecl1"><pre>Matches if a node refers to a declaration through a specific
using shadow declaration.
-Examples:
+Given
namespace a { int f(); }
using a::f;
int x = f();
-declRefExpr(throughUsingDecl(anything()))
- matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
namespace a { class X{}; }
using a::X;
X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
- matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UsingType.html">UsingType</a>>
</pre></td></tr>
@@ -10460,21 +13816,31 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
declaration of x.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- cxxRecordDecl(hasName("X"))))
class X {};
void y(X &x) { x; X z; }
class Y { friend class X; };
class Z : public virtual X {};
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z.
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X.
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches
+class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
+
+Given
class Base {};
class Derived : Base {};
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))
+matches class Derived : Base {}.
+
Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -10484,17 +13850,25 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasType3"><pre>Matches if the expression's or declaration's type matches a type
matcher.
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and U (matcher = typedefDecl(hasType(asString("int")))
- and friend class X (matcher = friendDecl(hasType("X"))
- and public virtual X (matcher = cxxBaseSpecifier(hasType(
- asString("class X")))
+Exmaple
class X {};
void y(X &x) { x; X z; }
typedef int U;
class Y { friend class X; };
class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
</pre></td></tr>
@@ -10502,9 +13876,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasInitializer0"><pre>Matches a variable declaration that has an initializer expression
that matches the given matcher.
-Example matches x (matcher = varDecl(hasInitializer(callExpr())))
- bool y() { return true; }
- bool x = y();
+Given
+ int y() { return 0; }
+ void foo() {
+ int x = y();
+ }
+The matcher varDecl(hasInitializer(callExpr()))
+matches x
</pre></td></tr>
@@ -10524,13 +13902,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template <typename T, typename U>
void f(T&& t, U&& u) {}
- bool B = false;
- f(R, B);
-templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
- matches twice, with expr() matching 'R * 2' and 'R * 4'
-functionDecl(forEachTemplateArgument(refersToType(builtinType())))
- matches the specialization f<unsigned, bool> twice, for 'unsigned'
- and 'bool'
+ void foo() {
+ bool B = false;
+ f(R, B);
+ }
+
+The matcher
+templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg"))))
+matches Matrix<int, R * 2, R * 4> twice, with
+expr() matching R * 2 and
+R * 4.
+The matcher
+functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type"))))
+matches the specialization of f twice,
+with qualType() matching
+unsigned and
+bool.
</pre></td></tr>
@@ -10543,9 +13930,11 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T> class A {};
A<int> a;
-varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
- hasTypeLoc(loc(asString("int")))))))
- matches `A<int> a`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+hasTypeLoc(loc(asString("int"))))))))) matches A<int> a.
</pre></td></tr>
@@ -10559,15 +13948,19 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
template<> class A<double> {};
A<int> a;
- template<typename T> f() {};
+ template<typename T> void f() {};
void func() { f<int>(); };
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches class A<int>.
+
+The matcher
+functionDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+matches the instantiation of f.
</pre></td></tr>
@@ -10580,9 +13973,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
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`.
+
+The matcher
+varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+hasTypeLoc(loc(asString("double")))))))))
+matches A<double, int> b, but not double> c}.
</pre></td></tr>
@@ -10593,17 +13989,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
Given
template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
+ A<double, int> b;
+ A<int, double> c;
template<typename T> void f() {}
void func() { f<int>(); };
+
+The matcher
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
+matches the specialization class A<double, int>.
-functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
- matches the specialization f<int>
+The matcher functionDecl(hasTemplateArgument(0,
+ refersToType(asString("int"))))
+matches the specialization of f.
</pre></td></tr>
@@ -10615,9 +14014,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
void f(int b) {
int a[b];
}
+The matcher
variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
varDecl(hasName("b")))))))
- matches "int a[b]"
+matches int[b]
</pre></td></tr>
@@ -10628,20 +14028,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
other declarations of the same function or coroutine.
Given
+void foo() {
for (;;) {}
-forStmt(hasBody(compoundStmt()))
- matches 'for (;;) {}'
+}
+The matcher forStmt(hasBody(compoundStmt().bind("body")))
+matches for (;;) {}
with compoundStmt()
- matching '{}'
+ matching {}
Given
void f();
void f() {}
-functionDecl(hasBody(compoundStmt()))
- matches 'void f() {}'
+The matcher functionDecl(hasBody(compoundStmt().bind("compound")))
+f
with compoundStmt()
- matching '{}'
- but does not match 'void f();'
+matching {}
+but does not match void f();
</pre></td></tr>
@@ -10649,8 +14051,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasCondition2"><pre>Matches the condition expression of an if statement, for loop,
switch statement or conditional operator.
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
</pre></td></tr>
<!--END_TRAVERSAL_MATCHERS -->
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 681728d36952c1..ba582160cf9920 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -847,6 +847,9 @@ AST Matchers
- Ensure ``hasName`` matches template specializations across inline namespaces,
making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.
+- The examples in the AST matcher reference are now tested and additional
+ examples and descriptions were added.
+
clang-format
------------
diff --git a/clang/docs/doxygen.cfg.in b/clang/docs/doxygen.cfg.in
index 251afb179b2055..1d1deb0fcfb07b 100644
--- a/clang/docs/doxygen.cfg.in
+++ b/clang/docs/doxygen.cfg.in
@@ -220,7 +220,14 @@ TAB_SIZE = 2
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
-ALIASES =
+ALIASES += compile_args{1}="Compiled with <tt>\1</tt>.\n"
+ALIASES += matcher{1}="<tt>\1</tt>"
+ALIASES += matcher{2$}="<tt>\2</tt>"
+ALIASES += match{1}="<tt>\1</tt>"
+ALIASES += match{2$}="<tt>\2</tt>"
+ALIASES += nomatch{1}="<tt>\1</tt>"
+ALIASES += header{1}="\code"
+ALIASES += endheader="\endcode"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py
index 705ff0d4d40985..a3feac8728c653 100755
--- a/clang/docs/tools/dump_ast_matchers.py
+++ b/clang/docs/tools/dump_ast_matchers.py
@@ -100,15 +100,72 @@ def extract_result_types(comment):
comment = m.group(1)
+def find_next_closing_rbrace(
+ data: str, start_pos: int, braces_to_be_matched: int
+) -> int:
+ """Finds the location of the closing rbrace '}' inside of data."""
+ """'start_pos' should be one past the opening lbrace and braces_to_be_matched is initialized with 0"""
+ next_lbrace = data.find("{", start_pos)
+ next_rbrace = data.find("}", start_pos)
+ if next_lbrace != -1:
+ if next_lbrace < next_rbrace:
+ return find_next_closing_rbrace(
+ data, next_lbrace + 1, braces_to_be_matched + 1
+ )
+ if braces_to_be_matched == 0:
+ return next_rbrace
+ return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1)
+
+ if braces_to_be_matched > 0:
+ return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1)
+
+ return next_rbrace
+
+
def strip_doxygen(comment):
"""Returns the given comment without \-escaped words."""
- # If there is only a doxygen keyword in the line, delete the whole line.
- comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M)
-
# If there is a doxygen \see command, change the \see prefix into "See also:".
# FIXME: it would be better to turn this into a link to the target instead.
comment = re.sub(r"\\see", r"See also:", comment)
+ commands: list[str] = [
+ "\\compile_args{",
+ "\\matcher{",
+ "\\match{",
+ "\\nomatch{",
+ ]
+
+ for command in commands:
+ delete_command = command == "\\compile_args{"
+ command_begin_loc = comment.find(command)
+ while command_begin_loc != -1:
+ command_end_loc = command_begin_loc + len(command)
+ end_brace_loc = find_next_closing_rbrace(comment, command_end_loc + 1, 0)
+ if end_brace_loc == -1:
+ print("found unmatched {")
+ command_begin_loc = comment.find(command, command_end_loc)
+ continue
+
+ if delete_command:
+ comment = comment[0:command_begin_loc] + comment[end_brace_loc + 1 :]
+ command_begin_loc = comment.find(command, command_begin_loc)
+ continue
+
+ tag_seperator_loc = comment.find("$", command_end_loc)
+ if tag_seperator_loc != -1 and tag_seperator_loc < end_brace_loc:
+ command_end_loc = tag_seperator_loc + 1
+
+ comment = (
+ comment[0:command_begin_loc]
+ + comment[command_end_loc:end_brace_loc]
+ + comment[end_brace_loc + 1 :]
+ )
+
+ command_begin_loc = comment.find(command, command_begin_loc)
+
+ # If there is only a doxygen keyword in the line, delete the whole line.
+ comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M)
+
# Delete the doxygen command and the following whitespace.
comment = re.sub(r"\\[^\s]+\s+", r"", comment)
return comment
@@ -191,8 +248,9 @@ def act_on_decl(declaration, comment, allowed_types):
definition.
"""
if declaration.strip():
-
- if re.match(r"^\s?(#|namespace|using|template <typename NodeType> using|})", declaration):
+ if re.match(
+ r"^\s?(#|namespace|using|template <typename NodeType> using|})", declaration
+ ):
return
# Node matchers are defined by writing:
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 4bcaa953a61af2..1898d53a503283 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -39,6 +39,158 @@
// See ASTMatchFinder.h for how to use the generated matchers to run over
// an AST.
//
+// The doxygen comments on matchers are used to:
+// - create the doxygen documentation
+// - get information in the editor via signature help and goto definition
+// - generate the AST matcher reference html file
+// - test the documentation using a special syntax
+//
+// Test Annotations:
+//
+// The automatic testing uses doxygen commands (aliases) to extract the
+// relevant information about an example of using a matcher from the
+// documentation.
+//
+// \header{a.h}
+// \endheader <- zero or more header
+//
+// \code
+// int a = 42;
+// \endcode
+// \compile_args{-std=c++,c23-or-later} <- optional, the std flag supports
+// std ranges and
+// whole languages
+//
+// \matcher{expr()} <- one or more matchers in succession
+// \matcher{integerLiteral()} <- one or more matchers in succession
+// both matcher will have to match the
+// following matches
+// \match{42} <- one or more matches in succession
+//
+// \matcher{varDecl()} <- new matcher resets the context, the above
+// \match will not count for this new
+// matcher(-group)
+// \match{int a = 42} <- only applies to the previous matcher (not to the
+// previous case)
+//
+//
+// The above block can be repeated inside a doxygen command for multiple code
+// examples for a single matcher. The test generation script will only look for
+// these annotations and ignore anything else like `\c` or the sentences where
+// these annotations are embedded into: `The matcher \matcher{expr()} matches
+// the number \match{42}.`.
+//
+// Language Grammar:
+//
+// [] denotes an optional, and <> denotes user-input
+//
+// compile_args j:= \compile_args{[<compile_arg>;]<compile_arg>}
+// matcher_tag_key ::= type
+// match_tag_key ::= type || std || count || sub
+// matcher_tags ::= [matcher_tag_key=<value>;]matcher_tag_key=<value>
+// match_tags ::= [match_tag_key=<value>;]match_tag_key=<value>
+// matcher ::= \matcher{[matcher_tags$]<matcher>}
+// matchers ::= [matcher] matcher
+// match ::= \match{[match_tags$]<match>}
+// matches ::= [match] match
+// case ::= matchers matches
+// cases ::= [case] case
+// header-block ::= \header{<name>} <code> \endheader
+// code-block ::= \code <code> \endcode
+// testcase ::= code-block [compile_args] cases
+//
+// Language Standard Versions:
+//
+// The 'std' tag and '\compile_args' support specifying a specific language
+// version, a whole language and all of its versions, and thresholds (implies
+// ranges). Multiple arguments are passed with a ',' separator. For a language
+// and version to execute a tested matcher, it has to match the specified
+// '\compile_args' for the code, and the 'std' tag for the matcher. Predicates
+// for the 'std' compiler flag are used with disjunction between languages
+// (e.g. 'c || c++') and conjunction for all predicates specific to each
+// language (e.g. 'c++11-or-later && c++23-or-earlier').
+//
+// Examples:
+// - `c` all available versions of C
+// - `c++11` only C++11
+// - `c++11-or-later` C++11 or later
+// - `c++11-or-earlier` C++11 or earlier
+// - `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and
+// 23 (inclusive)
+// - `c++11-23,c` same as above
+//
+// Tags
+//
+// `type`:
+// **Match types** are used to select where the string that is used to check if
+// a node matches comes from. Available: `code`, `name`, `typestr`,
+// `typeofstr`. The default is `code`.
+//
+// - `code`: Forwards to `tooling::fixit::getText(...)` and should be the
+// preferred way to show what matches.
+// - `name`: Casts the match to a `NamedDecl` and returns the result of
+// `getNameAsString`. Useful when the matched AST node is not easy to spell
+// out (`code` type), e.g., namespaces or classes with many members.
+// - `typestr`: Returns the result of `QualType::getAsString` for the type
+// derived from `Type` (otherwise, if it is derived from `Decl`, recurses with
+// `Node->getTypeForDecl()`)
+//
+// **Matcher types** are used to mark matchers as sub-matcher with 'sub' or as
+// deactivated using 'none'. Testing sub-matcher is not implemented.
+//
+// `count`:
+// Specifying a 'count=n' on a match will result in a test that requires that
+// the specified match will be matched n times. Default is 1.
+//
+// `std`:
+// A match allows specifying if it matches only in specific language versions.
+// This may be needed when the AST
diff ers between language versions.
+//
+// `sub`:
+// The `sub` tag on a `\match` will indicate that the match is for a node of a
+// bound sub-matcher. E.g., `\matcher{expr(expr().bind("inner"))}` has a
+// sub-matcher that binds to `inner`, which is the value for the `sub` tag of
+// the expected match for the sub-matcher `\match{sub=inner$...}`. Currently,
+// sub-matchers are not tested in any way.
+//
+//
+// What if ...?
+//
+// ... I want to add a matcher?
+//
+// Add a doxygen comment to the matcher with a code example, corresponding
+// matchers and matches, that shows what the matcher is supposed to do. Specify
+// the compile arguments/supported languages if required, and run `ninja
+// check-clang-unit` to test the documentation.
+//
+// ... the example I wrote is wrong?
+//
+// The test-failure output of the generated test file will provide information
+// about
+// - where the generated test file is located
+// - which line in `ASTMatcher.h` the example is from
+// - which matches were: found, not-(yet)-found, expected
+// - in case of an unexpected match: what the node looks like using the
+//
diff erent `type`s
+// - the language version and if the test ran with a windows `-target` flag
+// (also in failure summary)
+//
+// ... I don't adhere to the required order of the syntax?
+//
+// The script will diagnose any found issues, such as `matcher is missing an
+// example` with a `file:line:` prefix, which should provide enough information
+// about the issue.
+//
+// ... the script diagnoses a false-positive issue with a doxygen comment?
+//
+// It hopefully shouldn't, but if you, e.g., added some non-matcher code and
+// documented it with doxygen, then the script will consider that as a matcher
+// documentation. As a result, the script will print that it detected a
+// mismatch between the actual and the expected number of failures. If the
+// diagnostic truly is a false-positive, change the
+// `expected_failure_statistics` at the top of the
+// `generate_ast_matcher_doc_tests.py` file.
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
@@ -160,13 +312,13 @@ using AttrMatcher = internal::Matcher<Attr>;
/// additional constraint. This will often be used with an explicit conversion
/// to an \c internal::Matcher<> type such as \c TypeMatcher.
///
-/// Example: \c DeclarationMatcher(anything()) matches all declarations, e.g.,
+/// Given
/// \code
-/// "int* p" and "void f()" in
/// int* p;
/// void f();
/// \endcode
-///
+/// The matcher \matcher{decl(anything())}
+/// matches \match{int* p} and \match{void f()}.
/// Usable as: Any Matcher
inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
@@ -175,12 +327,13 @@ inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
/// Given
/// \code
/// int X;
-/// namespace NS {
-/// int Y;
-/// } // namespace NS
+/// namespace NS { int Y; }
/// \endcode
-/// decl(hasDeclContext(translationUnitDecl()))
-/// matches "int X", but not "int Y".
+/// \compile_args{-std=c++}
+/// The matcher \matcher{namedDecl(hasDeclContext(translationUnitDecl()))}
+/// matches \match{int X} and \match{namespace NS { int Y; }},
+/// but does not match \nomatch{int Y} because its decl-context is the
+/// namespace \c NS .
extern const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl>
translationUnitDecl;
@@ -191,8 +344,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl>
/// typedef int X;
/// using Y = int;
/// \endcode
-/// typedefDecl()
-/// matches "typedef int X", but not "using Y = int"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{typedefDecl()}
+/// matches \match{typedef int X},
+/// but does not match \nomatch{using Y = int}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl>
typedefDecl;
@@ -203,8 +358,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl>
/// typedef int X;
/// using Y = int;
/// \endcode
-/// typedefNameDecl()
-/// matches "typedef int X" and "using Y = int"
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{typedefNameDecl()}
+/// matches \match{typedef int X} and \match{using Y = int}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
typedefNameDecl;
@@ -215,34 +371,45 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
/// typedef int X;
/// using Y = int;
/// \endcode
-/// typeAliasDecl()
-/// matches "using Y = int", but not "typedef int X"
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{typeAliasDecl()}
+/// matches \match{using Y = int},
+/// but does not match \nomatch{typedef int X}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl>
typeAliasDecl;
/// Matches type alias template declarations.
///
-/// typeAliasTemplateDecl() matches
+/// Given
/// \code
-/// template <typename T>
-/// using Y = X<T>;
+/// template <typename T> struct X {};
+/// template <typename T> using Y = X<T>;
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{typeAliasTemplateDecl()}
+/// matches \match{template <typename T> using Y = X<T>}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl>
typeAliasTemplateDecl;
/// Matches AST nodes that were expanded within the main-file.
///
-/// Example matches X but not Y
-/// (matcher = cxxRecordDecl(isExpansionInMainFile())
-/// \code
-/// #include <Y.h>
-/// class X {};
-/// \endcode
-/// Y.h:
+/// Given the header \c Y.h
+/// \header{Y.h}
+/// #pragma once
+/// typedef int my_header_int;
+/// \endheader
+/// and the source file
/// \code
-/// class Y {};
+/// #include "Y.h"
+/// typedef int my_main_file_int;
+/// my_main_file_int a = 0;
+/// my_header_int b = 1;
/// \endcode
///
+/// The matcher \matcher{typedefDecl(isExpansionInMainFile())}
+/// matches \match{typedef int my_main_file_int},
+/// but does not match \nomatch{typedef int my_header_int}.
+///
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
AST_POLYMORPHIC_MATCHER(isExpansionInMainFile,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) {
@@ -253,16 +420,21 @@ AST_POLYMORPHIC_MATCHER(isExpansionInMainFile,
/// Matches AST nodes that were expanded within system-header-files.
///
-/// Example matches Y but not X
-/// (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+/// Given the header \c SystemHeader.h
+/// \header{system_include/SystemHeader.h}
+/// #pragma once
+/// int header();
+/// \endheader
+/// and the source code
/// \code
/// #include <SystemHeader.h>
-/// class X {};
-/// \endcode
-/// SystemHeader.h:
-/// \code
-/// class Y {};
+/// static int main_file();
/// \endcode
+/// \compile_args{-isystemsystem_include/}
+///
+/// The matcher \matcher{type=none$functionDecl(isExpansionInSystemHeader())}
+/// matches \match{int header()},
+/// but does not match \nomatch{static int main_file()}.
///
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader,
@@ -278,17 +450,32 @@ AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader,
/// Matches AST nodes that were expanded within files whose name is
/// partially matching a given regex.
///
-/// Example matches Y but not X
-/// (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-/// \code
-/// #include "ASTMatcher.h"
-/// class X {};
-/// \endcode
-/// ASTMatcher.h:
-/// \code
-/// class Y {};
+/// Given the headers \c Y.h
+/// \header{Y.h}
+/// #pragma once
+/// typedef int my_y_int;
+/// \endheader
+/// and \c X.h
+/// \header{X.h}
+/// #pragma once
+/// typedef int my_x_int;
+/// \endheader
+/// and the source code
+/// \code
+/// #include "X.h"
+/// #include "Y.h"
+/// typedef int my_main_file_int;
+/// my_main_file_int a = 0;
+/// my_x_int b = 1;
+/// my_y_int c = 2;
/// \endcode
///
+/// The matcher
+/// \matcher{type=none$typedefDecl(isExpansionInFileMatching("Y.h"))}
+/// matches \match{typedef int my_y_int},
+/// but does not match \nomatch{typedef int my_main_file_int} or
+/// \nomatch{typedef int my_x_int}.
+///
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt,
@@ -313,6 +500,17 @@ AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching,
/// Does not match if only part of the statement is expanded from that macro or
/// if
diff erent parts of the statement are expanded from
diff erent
/// appearances of the macro.
+///
+/// Given
+/// \code
+/// #define A 0
+/// #define B A
+/// int c = B;
+/// \endcode
+///
+/// The matcher \matcher{integerLiteral(isExpandedFromMacro("A"))}
+/// matches the literal expanded at the initializer \match{B} of the variable
+/// \c c .
AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
std::string, MacroName) {
@@ -330,35 +528,50 @@ AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro,
/// Matches declarations.
///
-/// Examples matches \c X, \c C, and the friend declaration inside \c C;
+/// Given
/// \code
/// void X();
/// class C {
-/// friend X;
+/// friend void X();
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{decl()}
+/// matches \match{void X()} once, \match{type=name;count=2$C}
+/// twice, once for the definition and once for the implicit class declaration,
+/// and \match{count=2$friend void X()} twice, once for the declaration of the
+/// friend, and once for the redeclaration of the function itself.
extern const internal::VariadicAllOfMatcher<Decl> decl;
/// Matches decomposition-declarations.
///
-/// Examples matches the declaration node with \c foo and \c bar, but not
-/// \c number.
-/// (matcher = declStmt(has(decompositionDecl())))
-///
+/// Given
/// \code
+/// struct pair { int x; int y; };
+/// pair make(int, int);
/// int number = 42;
-/// auto [foo, bar] = std::make_pair{42, 42};
+/// auto [foo, bar] = make(42, 42);
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+/// The matcher \matcher{decompositionDecl()}
+/// matches \match{auto [foo, bar] = make(42, 42)},
+/// but does not match \nomatch{type=name$number}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, DecompositionDecl>
decompositionDecl;
/// Matches binding declarations
-/// Example matches \c foo and \c bar
-/// (matcher = bindingDecl()
///
+/// Given
/// \code
-/// auto [foo, bar] = std::make_pair{42, 42};
+/// struct pair { int x; int y; };
+/// pair make(int, int);
+/// void f() {
+/// auto [foo, bar] = make(42, 42);
+/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+/// The matcher \matcher{bindingDecl()}
+/// matches \match{type=name$foo} and \match{type=name$bar}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, BindingDecl>
bindingDecl;
@@ -368,33 +581,41 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, BindingDecl>
/// \code
/// extern "C" {}
/// \endcode
-/// linkageSpecDecl()
-/// matches "extern "C" {}"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{linkageSpecDecl()}
+/// matches \match{extern "C" {}}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl>
linkageSpecDecl;
/// Matches a declaration of anything that could have a name.
///
/// Example matches \c X, \c S, the anonymous union type, \c i, and \c U;
+/// Given
/// \code
/// typedef int X;
-/// struct S {
-/// union {
-/// int i;
-/// } U;
-/// };
-/// \endcode
+/// struct S { union { int i; } U; };
+/// \endcode
+/// The matcher \matcher{namedDecl()}
+/// matches \match{typedef int X},
+/// \match{std=c$struct S { union { int i; } U; }}, \match{int i},
+/// the unnamed union\match{type=name$} and the variable
+/// \match{union { int i; } U},
+/// with \match{type=name;count=2;std=c++$S} matching twice in C++.
+/// Once for the implicit class declaration and once for the declaration itself.
extern const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl;
/// Matches a declaration of label.
///
/// Given
/// \code
-/// goto FOO;
-/// FOO: bar();
+/// void bar();
+/// void foo() {
+/// goto FOO;
+/// FOO: bar();
+/// }
/// \endcode
-/// labelDecl()
-/// matches 'FOO:'
+/// The matcher \matcher{type=none$labelDecl()}
+/// matches \match{FOO: bar()}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl;
/// Matches a declaration of a namespace.
@@ -404,8 +625,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl;
/// namespace {}
/// namespace test {}
/// \endcode
-/// namespaceDecl()
-/// matches "namespace {}" and "namespace test {}"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{namespaceDecl()}
+/// matches \match{namespace {}} and \match{namespace test {}}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl>
namespaceDecl;
@@ -416,38 +638,53 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl>
/// namespace test {}
/// namespace alias = ::test;
/// \endcode
-/// namespaceAliasDecl()
-/// matches "namespace alias" but not "namespace test"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{namespaceAliasDecl()}
+/// matches \match{namespace alias = ::test},
+/// but does not match \nomatch{namespace test {}}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl>
namespaceAliasDecl;
/// Matches class, struct, and union declarations.
///
-/// Example matches \c X, \c Z, \c U, and \c S
+/// Given
/// \code
/// class X;
/// template<class T> class Z {};
/// struct S {};
/// union U {};
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{recordDecl()}
+/// matches \match{class X} once, and the rest of the declared records twice,
+/// once for their written definition and once for their implicit declaration:
+/// \match{type=name;count=2$Z}, \match{type=name;count=2$S} and
+/// \match{type=name;count=2$U}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, RecordDecl> recordDecl;
/// Matches C++ class declarations.
///
-/// Example matches \c X, \c Z
+/// Given
/// \code
/// class X;
/// template<class T> class Z {};
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxRecordDecl()}
+/// matches \match{class X} once, and \match{type=name;count=2$Z} twice,
+/// once for the written definition and once for the implicit declaration.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXRecordDecl>
cxxRecordDecl;
/// Matches C++ class template declarations.
///
-/// Example matches \c Z
+/// Given
/// \code
/// template<class T> class Z {};
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplateDecl()}
+/// matches \match{template<class T> class Z {}}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, ClassTemplateDecl>
classTemplateDecl;
@@ -459,8 +696,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ClassTemplateDecl>
/// template<> class A<double> {};
/// A<int> a;
/// \endcode
-/// classTemplateSpecializationDecl()
-/// matches the specializations \c A<int> and \c A<double>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplateSpecializationDecl()}
+/// matches \match{type=typestr$class A<int>}
+/// and \match{type=typestr$class A<double>}.
extern const internal::VariadicDynCastAllOfMatcher<
Decl, ClassTemplateSpecializationDecl>
classTemplateSpecializationDecl;
@@ -472,14 +711,15 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// template<class T1, class T2, int I>
/// class A {};
///
-/// template<class T, int I>
-/// class A<T, T*, I> {};
+/// template<class T, int I> class A<T, T*, I> {};
///
/// template<>
/// class A<int, int, 1> {};
/// \endcode
-/// classTemplatePartialSpecializationDecl()
-/// matches the specialization \c A<T,T*,I> but not \c A<int,int,1>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplatePartialSpecializationDecl()}
+/// matches \match{template<class T, int I> class A<T, T*, I> {}},
+/// but does not match \nomatch{A<int, int, 1>}.
extern const internal::VariadicDynCastAllOfMatcher<
Decl, ClassTemplatePartialSpecializationDecl>
classTemplatePartialSpecializationDecl;
@@ -491,8 +731,9 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// \code
/// class X { int y; };
/// \endcode
-/// declaratorDecl()
-/// matches \c int y.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{declaratorDecl()}
+/// matches \match{int y}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl>
declaratorDecl;
@@ -502,8 +743,8 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl>
/// \code
/// void f(int x);
/// \endcode
-/// parmVarDecl()
-/// matches \c int x.
+/// The matcher \matcher{parmVarDecl()}
+/// matches \match{int x}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl>
parmVarDecl;
@@ -516,29 +757,36 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl>
/// int a;
/// };
/// \endcode
-/// accessSpecDecl()
-/// matches 'public:'
+/// \compile_args{-std=c++}
+/// The matcher \matcher{accessSpecDecl()}
+/// matches \match{public:}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl>
accessSpecDecl;
/// Matches class bases.
///
-/// Examples matches \c public virtual B.
+/// Given
/// \code
/// class B {};
-/// class C : public virtual B {};
+/// class C : public B {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))}
+/// matches \match{class C : public B {}}.
extern const internal::VariadicAllOfMatcher<CXXBaseSpecifier> cxxBaseSpecifier;
/// Matches constructor initializers.
///
-/// Examples matches \c i(42).
+/// Given
/// \code
/// class C {
/// C() : i(42) {}
/// int i;
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxCtorInitializer()}
+/// matches \match{i(42)}.
extern const internal::VariadicAllOfMatcher<CXXCtorInitializer>
cxxCtorInitializer;
@@ -549,8 +797,10 @@ extern const internal::VariadicAllOfMatcher<CXXCtorInitializer>
/// template <typename T> struct C {};
/// C<int> c;
/// \endcode
-/// templateArgument()
-/// matches 'int' in C<int>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{templateSpecializationType(hasAnyTemplateArgument(templateArgument()))}
+/// matches \match{type=typestr$C<int>}.
extern const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument;
/// Matches template arguments (with location info).
@@ -560,8 +810,9 @@ extern const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument;
/// template <typename T> struct C {};
/// C<int> c;
/// \endcode
-/// templateArgumentLoc()
-/// matches 'int' in C<int>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{templateArgumentLoc()}
+/// matches \match{int} in C<int>.
extern const internal::VariadicAllOfMatcher<TemplateArgumentLoc>
templateArgumentLoc;
@@ -569,11 +820,15 @@ extern const internal::VariadicAllOfMatcher<TemplateArgumentLoc>
///
/// Given
/// \code
-/// template <typename T> class X { };
-/// X<int> xi;
+/// template<template <typename> class S> class X {};
+/// template<typename T> class Y {};
+/// X<Y> xi;
/// \endcode
-/// templateName()
-/// matches 'X' in X<int>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasAnyTemplateArgument(
+/// refersToTemplate(templateName())))}
+/// matches the specialization \match{type=typestr$class X<Y>}
extern const internal::VariadicAllOfMatcher<TemplateName> templateName;
/// Matches non-type template parameter declarations.
@@ -582,8 +837,10 @@ extern const internal::VariadicAllOfMatcher<TemplateName> templateName;
/// \code
/// template <typename T, int N> struct C {};
/// \endcode
-/// nonTypeTemplateParmDecl()
-/// matches 'N', but not 'T'.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{nonTypeTemplateParmDecl()}
+/// matches \match{int N},
+/// but does not match \nomatch{typename T}.
extern const internal::VariadicDynCastAllOfMatcher<Decl,
NonTypeTemplateParmDecl>
nonTypeTemplateParmDecl;
@@ -594,8 +851,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl,
/// \code
/// template <typename T, int N> struct C {};
/// \endcode
-/// templateTypeParmDecl()
-/// matches 'T', but not 'N'.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{templateTypeParmDecl()}
+/// matches \match{typename T},
+/// but does not \nomatch{int N}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTypeParmDecl>
templateTypeParmDecl;
@@ -605,8 +864,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTypeParmDecl>
/// \code
/// template <template <typename> class Z, int N> struct C {};
/// \endcode
-/// templateTypeParmDecl()
-/// matches 'Z', but not 'N'.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{templateTemplateParmDecl()}
+/// matches \match{template <typename> class Z},
+/// but does not match \nomatch{int N}.
extern const internal::VariadicDynCastAllOfMatcher<Decl,
TemplateTemplateParmDecl>
templateTemplateParmDecl;
@@ -614,20 +875,31 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl,
/// Matches public C++ declarations and C++ base specifers that specify public
/// inheritance.
///
-/// Examples:
+/// Given
/// \code
/// class C {
-/// public: int a; // fieldDecl(isPublic()) matches 'a'
+/// public: int a;
/// protected: int b;
/// private: int c;
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl(isPublic())}
+/// matches \match{int a}.
///
+/// Given
/// \code
/// class Base {};
-/// class Derived1 : public Base {}; // matches 'Base'
-/// struct Derived2 : Base {}; // matches 'Base'
+/// class Derived1 : public Base {};
+/// struct Derived2 : Base {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))}
+/// matches \match{class Derived1 : public Base {}} and
+/// \match{struct Derived2 : Base {}},
+/// with \matcher{type=sub$cxxBaseSpecifier(isPublic())} matching
+/// \match{sub=base$public Base} and \match{sub=base$Base}.
AST_POLYMORPHIC_MATCHER(isPublic,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl,
CXXBaseSpecifier)) {
@@ -637,19 +909,28 @@ AST_POLYMORPHIC_MATCHER(isPublic,
/// Matches protected C++ declarations and C++ base specifers that specify
/// protected inheritance.
///
-/// Examples:
+/// Given
/// \code
/// class C {
/// public: int a;
-/// protected: int b; // fieldDecl(isProtected()) matches 'b'
+/// protected: int b;
/// private: int c;
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl(isProtected())}
+/// matches \match{int b}.
///
/// \code
/// class Base {};
-/// class Derived : protected Base {}; // matches 'Base'
+/// class Derived : protected Base {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))}
+/// matches \match{class Derived : protected Base {}}, with
+/// \matcher{type=sub$cxxBaseSpecifier(isProtected())} matching
+/// \match{sub=base$Base}.
AST_POLYMORPHIC_MATCHER(isProtected,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl,
CXXBaseSpecifier)) {
@@ -659,20 +940,30 @@ AST_POLYMORPHIC_MATCHER(isProtected,
/// Matches private C++ declarations and C++ base specifers that specify private
/// inheritance.
///
-/// Examples:
+/// Given
/// \code
/// class C {
/// public: int a;
/// protected: int b;
-/// private: int c; // fieldDecl(isPrivate()) matches 'c'
+/// private: int c;
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl(isPrivate())}
+/// matches \match{int c}.
///
/// \code
/// struct Base {};
-/// struct Derived1 : private Base {}; // matches 'Base'
-/// class Derived2 : Base {}; // matches 'Base'
+/// struct Derived1 : private Base {}; // \match{Base}
+/// class Derived2 : Base {}; // \match{Base}
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))}
+/// matches \match{struct Derived1 : private Base {}} and
+/// \match{class Derived2 : Base {}}, with
+/// \matcher{type=sub$cxxBaseSpecifier(isPrivate())} matching
+/// \match{sub=base;count=2$Base} each time.
AST_POLYMORPHIC_MATCHER(isPrivate,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl,
CXXBaseSpecifier)) {
@@ -688,11 +979,11 @@ AST_POLYMORPHIC_MATCHER(isPrivate,
/// int b;
/// };
/// \endcode
-/// fieldDecl(isBitField())
-/// matches 'int a;' but not 'int b;'.
-AST_MATCHER(FieldDecl, isBitField) {
- return Node.isBitField();
-}
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl(isBitField())}
+/// matches \match{int a : 2},
+/// but does not match \nomatch{int b}.
+AST_MATCHER(FieldDecl, isBitField) { return Node.isBitField(); }
/// Matches non-static data members that are bit-fields of the specified
/// bit width.
@@ -705,8 +996,10 @@ AST_MATCHER(FieldDecl, isBitField) {
/// int c : 2;
/// };
/// \endcode
-/// fieldDecl(hasBitWidth(2))
-/// matches 'int a;' and 'int c;' but not 'int b;'.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl(hasBitWidth(2))}
+/// matches \match{int a : 2} and \match{int c : 2},
+/// but not \nomatch{int b : 4}.
AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
return Node.isBitField() &&
Node.getBitWidthValue(Finder->getASTContext()) == Width;
@@ -722,10 +1015,14 @@ AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
/// int c;
/// };
/// \endcode
-/// fieldDecl(hasInClassInitializer(integerLiteral(equals(2))))
-/// matches 'int a;' but not 'int b;'.
-/// fieldDecl(hasInClassInitializer(anything()))
-/// matches 'int a;' and 'int b;' but not 'int c;'.
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{fieldDecl(hasInClassInitializer(integerLiteral(equals(2))))}
+/// matches \match{int a = 2},
+/// but does not match \nomatch{int b = 3}.
+/// The matcher \matcher{fieldDecl(hasInClassInitializer(anything()))}
+/// matches \match{int a = 2} and \match{int b = 3},
+/// but does not match \nomatch{int c}.
AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>,
InnerMatcher) {
const Expr *Initializer = Node.getInClassInitializer();
@@ -735,20 +1032,29 @@ AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>,
/// Determines whether the function is "main", which is the entry point
/// into an executable program.
-AST_MATCHER(FunctionDecl, isMain) {
- return Node.isMain();
-}
+///
+/// Given
+/// \code
+/// void f();
+/// int main() {}
+/// \endcode
+///
+/// The matcher \matcher{functionDecl(isMain())} matches \match{int main() {}}.
+AST_MATCHER(FunctionDecl, isMain) { return Node.isMain(); }
/// Matches the specialized template of a specialization declaration.
///
/// Given
/// \code
-/// template<typename T> class A {}; #1
-/// template<> class A<int> {}; #2
+/// template<typename T> class A {}; // #1
+/// template<> class A<int> {}; // #2
/// \endcode
-/// classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
-/// matches '#2' with classTemplateDecl() matching the class template
-/// declaration of 'A' at #1.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl().bind("ctd")))}
+/// matches \match{template<> class A<int> {}},
+/// with \matcher{type=sub$classTemplateDecl()} matching the class template
+/// declaration \match{sub=ctd$template <typename T> class A {}}.
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate,
internal::Matcher<ClassTemplateDecl>, InnerMatcher) {
const ClassTemplateDecl* Decl = Node.getSpecializedTemplate();
@@ -758,6 +1064,22 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate,
/// Matches an entity that has been implicitly added by the compiler (e.g.
/// implicit default/copy constructors).
+///
+/// Given
+/// \code
+/// struct S {};
+/// void f(S obj) {
+/// S copy = obj;
+/// [&](){ return copy; };
+/// }
+/// \endcode
+/// \compile_args{-std=c++11}
+///
+/// The matcher \matcher{cxxConstructorDecl(isImplicit(), isCopyConstructor())}
+/// matches the implicit copy constructor of \match{S}.
+/// The matcher \matcher{lambdaExpr(forEachLambdaCapture(
+/// lambdaCapture(isImplicit())))} matches \match{[&](){ return copy; }},
+/// because it implicitly captures \c copy .
AST_POLYMORPHIC_MATCHER(isImplicit,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr,
LambdaCapture)) {
@@ -774,17 +1096,21 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
/// template<> class A<double> {};
/// A<int> a;
///
-/// template<typename T> f() {};
+/// template<typename T> void f() {};
/// void func() { f<int>(); };
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
///
-/// \endcode
-/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
-/// refersToType(asString("int"))))
-/// matches the specialization \c A<int>
+/// The matcher \matcher{classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(
+/// refersToType(asString("int"))))}
+/// matches \match{type=typestr$class A<int>}.
///
-/// functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
-/// matches the specialization \c f<int>
+/// The matcher
+/// \matcher{functionDecl(hasAnyTemplateArgument(
+/// refersToType(asString("int"))))}
+/// matches the instantiation of
+/// \match{void f() {}}.
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -807,12 +1133,10 @@ AST_POLYMORPHIC_MATCHER_P(
/// }
/// \endcode
/// The matcher
-/// \code
-/// traverse(TK_IgnoreUnlessSpelledInSource,
+/// \matcher{traverse(TK_IgnoreUnlessSpelledInSource,
/// varDecl(hasInitializer(floatLiteral().bind("init")))
-/// )
-/// \endcode
-/// matches the variable declaration with "init" bound to the "3.0".
+/// )}
+/// matches \match{int i = 3.0} with "init" bound to \match{sub=init$3.0}.
template <typename T>
internal::Matcher<T> traverse(TraversalKind TK,
const internal::Matcher<T> &InnerMatcher) {
@@ -873,25 +1197,37 @@ traverse(TraversalKind TK, const internal::MapAnyOfHelper<T...> &InnerMatcher) {
/// nodes are stripped off.
///
/// Parentheses and explicit casts are not discarded.
+///
/// Given
/// \code
-/// class C {};
-/// C a = C();
-/// C b;
-/// C c = b;
-/// \endcode
-/// The matchers
-/// \code
-/// varDecl(hasInitializer(ignoringImplicit(cxxConstructExpr())))
-/// \endcode
-/// would match the declarations for a, b, and c.
-/// While
-/// \code
-/// varDecl(hasInitializer(cxxConstructExpr()))
+/// void f(int param) {
+/// int a = 0;
+/// int b = param;
+/// const int c = 0;
+/// const int d = param;
+/// int e = (0U);
+/// int f = (int)0.0;
+/// const int g = ((int)(((0))));
+/// }
/// \endcode
-/// only match the declarations for b and c.
-AST_MATCHER_P(Expr, ignoringImplicit, internal::Matcher<Expr>,
- InnerMatcher) {
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringImplicit(integerLiteral())))}
+/// matches \match{int a = 0} and \match{const int c = 0},
+/// but not \nomatch{int e = (0U)} and \nomatch{((int)(((0)))}.
+/// The matcher
+/// \matcher{varDecl(hasInitializer(integerLiteral()))}
+/// matches \match{int a = 0} and \match{const int c = 0},
+/// but not \nomatch{int e = (0U)} and \nomatch{((int)(((0)))}.
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringImplicit(declRefExpr())))}
+/// matches \match{int b = param} and \match{const int d = param}.
+/// The matcher
+/// \matcher{varDecl(hasInitializer(declRefExpr()))}
+/// matches neither \nomatch{int b = param} nor \nomatch{const int d = param},
+/// because an l-to-r-value cast happens.
+AST_MATCHER_P(Expr, ignoringImplicit, internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder);
}
@@ -902,24 +1238,32 @@ AST_MATCHER_P(Expr, ignoringImplicit, internal::Matcher<Expr>,
/// Given
/// \code
/// int arr[5];
-/// int a = 0;
+/// const int a = 0;
/// char b = 0;
/// const int c = a;
/// int *d = arr;
/// long e = (long) 0l;
/// \endcode
-/// The matchers
-/// \code
-/// varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
-/// varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
-/// \endcode
-/// would match the declarations for a, b, c, and d, but not e.
-/// While
-/// \code
-/// varDecl(hasInitializer(integerLiteral()))
-/// varDecl(hasInitializer(declRefExpr()))
-/// \endcode
-/// only match the declarations for a.
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))}
+/// matches \match{const int a = 0} and \match{char b = 0},
+/// but does not match \nomatch{long e = (long) 0l} because of the c-style
+/// case.
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))}
+/// matches \match{const int c = a} and \match{int *d = arr}.
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(integerLiteral()))}
+/// matches \match{const int a = 0},
+/// but does not match \nomatch{char b = 0} because of the implicit cast to
+/// \c char or \nomatch{long e = (long) 0l} because of the c-style cast.
+///
+/// The matcher \matcher{varDecl(hasInitializer(declRefExpr()))}
+/// does not match \nomatch{const int c = a} because \c a is cast from an
+/// l- to an r-value or \nomatch{int *d = arr} because the array-to-pointer
+/// decay.
AST_MATCHER_P(Expr, ignoringImpCasts,
internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.IgnoreImpCasts(), Finder, Builder);
@@ -936,12 +1280,15 @@ AST_MATCHER_P(Expr, ignoringImpCasts,
/// void* c = reinterpret_cast<char*>(0);
/// char d = char(0);
/// \endcode
+/// \compile_args{-std=c++}
/// The matcher
-/// varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
-/// would match the declarations for a, b, c, and d.
-/// while
-/// varDecl(hasInitializer(integerLiteral()))
-/// only match the declaration for a.
+/// \matcher{varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))}
+/// matches \match{int a = 0}, \match{char b = (0)},
+/// \match{void* c = reinterpret_cast<char*>(0)} and \match{type=name$d}.
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(integerLiteral()))}
+/// matches \match{int a = 0}.
AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.IgnoreParenCasts(), Finder, Builder);
}
@@ -959,14 +1306,25 @@ AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) {
/// int *d = (arr);
/// long e = ((long) 0l);
/// \endcode
-/// The matchers
-/// varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
-/// varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
-/// would match the declarations for a, b, c, and d, but not e.
-/// while
-/// varDecl(hasInitializer(integerLiteral()))
-/// varDecl(hasInitializer(declRefExpr()))
-/// would only match the declaration for a.
+/// \compile_args{-std=c++}
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))}
+/// matches \match{int a = 0} and \match{char b = (0)},
+/// but does not match \nomatch{long e = ((long) 0l)} because of the c-style
+/// cast.
+///
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))}
+/// matches \match{const int c = a} and \match{int *d = (arr)}.
+///
+/// The matcher \matcher{varDecl(hasInitializer(integerLiteral()))} matches
+/// \match{int a = 0}, but does not match \nomatch{char b = (0)} or
+/// \nomatch{long e = ((long) 0l)} because of the casts.
+///
+/// The matcher \matcher{varDecl(hasInitializer(declRefExpr()))}
+/// does not match \nomatch{const int c = a} because of the l- to r-value cast,
+/// or \nomatch{int *d = (arr)} because of the array-to-pointer decay.
AST_MATCHER_P(Expr, ignoringParenImpCasts,
internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.IgnoreParenImpCasts(), Finder, Builder);
@@ -979,10 +1337,8 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
/// void (*fp)(void);
/// \endcode
/// The matcher
-/// \code
-/// varDecl(hasType(pointerType(pointee(ignoringParens(functionType())))))
-/// \endcode
-/// would match the declaration for fp.
+/// \matcher{varDecl(hasType(pointerType(pointee(ignoringParens(functionType())))))}
+/// matches \match{void (*fp)(void)}.
AST_MATCHER_P_OVERLOAD(QualType, ignoringParens, internal::Matcher<QualType>,
InnerMatcher, 0) {
return InnerMatcher.matches(Node.IgnoreParens(), Finder, Builder);
@@ -995,10 +1351,9 @@ AST_MATCHER_P_OVERLOAD(QualType, ignoringParens, internal::Matcher<QualType>,
/// const char* str = ("my-string");
/// \endcode
/// The matcher
-/// \code
-/// implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral())))
-/// \endcode
-/// would match the implicit cast resulting from the assignment.
+/// \matcher{implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral())))}
+/// would match the implicit cast resulting from the assignment
+/// \match{("my-string")}.
AST_MATCHER_P_OVERLOAD(Expr, ignoringParens, internal::Matcher<Expr>,
InnerMatcher, 1) {
const Expr *E = Node.IgnoreParens();
@@ -1015,9 +1370,13 @@ AST_MATCHER_P_OVERLOAD(Expr, ignoringParens, internal::Matcher<Expr>,
/// sizeof is known.
/// \code
/// template<typename T>
-/// void f(T x, T y) { sizeof(sizeof(T() + T()); }
+/// void f(T x, T y) { sizeof(T() + T()); }
/// \endcode
-/// expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T())
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{expr(isInstantiationDependent())}
+/// matches \match{sizeof(T() + T())},
+/// \match{(T() + T())},
+/// \match{T() + T()} and two time \match{count=2$T()}.
AST_MATCHER(Expr, isInstantiationDependent) {
return Node.isInstantiationDependent();
}
@@ -1033,7 +1392,9 @@ AST_MATCHER(Expr, isInstantiationDependent) {
/// x + y;
/// }
/// \endcode
-/// expr(isTypeDependent()) matches x + y
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{expr(isTypeDependent())}
+/// matches \match{x + y} and \match{x}.
AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
/// Matches expression that are value-dependent because they contain a
@@ -1044,7 +1405,9 @@ AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
/// \code
/// template<int Size> int f() { return Size; }
/// \endcode
-/// expr(isValueDependent()) matches return Size
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{expr(isValueDependent())}
+/// matches the return value \match{Size}.
AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
/// Matches templateSpecializationType, class template specializations,
@@ -1054,18 +1417,21 @@ AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
/// Given
/// \code
/// template<typename T, typename U> class A {};
-/// A<bool, int> b;
-/// A<int, bool> c;
+/// A<double, int> b;
+/// A<int, double> c;
///
/// template<typename T> void f() {}
/// void func() { f<int>(); };
/// \endcode
-/// classTemplateSpecializationDecl(hasTemplateArgument(
-/// 1, refersToType(asString("int"))))
-/// matches the specialization \c A<bool, int>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasTemplateArgument(
+/// 1, refersToType(asString("int"))))}
+/// matches the specialization \match{type=typestr$class A<double, int>}.
///
-/// functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
-/// matches the specialization \c f<int>
+/// The matcher \matcher{functionDecl(hasTemplateArgument(0,
+/// refersToType(asString("int"))))}
+/// matches the specialization of \match{void f() {}}.
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -1086,8 +1452,10 @@ AST_POLYMORPHIC_MATCHER_P2(
/// template<typename T> struct C {};
/// C<int> c;
/// \endcode
-/// classTemplateSpecializationDecl(templateArgumentCountIs(1))
-/// matches C<int>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(templateArgumentCountIs(1))}
+/// matches \match{type=typestr$struct C<int>}.
AST_POLYMORPHIC_MATCHER_P(
templateArgumentCountIs,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -1104,9 +1472,11 @@ AST_POLYMORPHIC_MATCHER_P(
/// template<typename T> struct A {};
/// A<X> a;
/// \endcode
-/// classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
-/// recordType(hasDeclaration(recordDecl(hasName("X")))))))
-/// matches the specialization of \c struct A generated by \c A<X>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
+/// recordType(hasDeclaration(recordDecl(hasName("X")))))))}
+/// matches the specialization \match{type=typestr$struct A<struct X>}.
AST_MATCHER_P(TemplateArgument, refersToType,
internal::Matcher<QualType>, InnerMatcher) {
if (Node.getKind() != TemplateArgument::Type)
@@ -1122,9 +1492,11 @@ AST_MATCHER_P(TemplateArgument, refersToType,
/// template<typename T> class Y {};
/// X<Y> xi;
/// \endcode
-/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
-/// refersToTemplate(templateName())))
-/// matches the specialization \c X<Y>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasAnyTemplateArgument(
+/// refersToTemplate(templateName())))}
+/// matches the specialization \match{type=typestr$class X<Y>}
AST_MATCHER_P(TemplateArgument, refersToTemplate,
internal::Matcher<TemplateName>, InnerMatcher) {
if (Node.getKind() != TemplateArgument::Template)
@@ -1141,10 +1513,13 @@ AST_MATCHER_P(TemplateArgument, refersToTemplate,
/// template<int(B::*next_ptr)> struct A {};
/// A<&B::next> a;
/// \endcode
-/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
-/// refersToDeclaration(fieldDecl(hasName("next")))))
-/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching
-/// \c B::next
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{classTemplateSpecializationDecl(hasAnyTemplateArgument(
+/// refersToDeclaration(fieldDecl(hasName("next")).bind("next"))))}
+/// matches the specialization \match{type=typestr$struct A<&B::next>}
+/// with \matcher{type=sub$fieldDecl(hasName("next"))} matching
+/// \match{sub=next$int next}.
AST_MATCHER_P(TemplateArgument, refersToDeclaration,
internal::Matcher<Decl>, InnerMatcher) {
if (Node.getKind() == TemplateArgument::Declaration)
@@ -1160,10 +1535,13 @@ AST_MATCHER_P(TemplateArgument, refersToDeclaration,
/// template<int(B::*next_ptr)> struct A {};
/// A<&B::next> a;
/// \endcode
-/// templateSpecializationType(hasAnyTemplateArgument(
-/// isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
-/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching
-/// \c B::next
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{templateSpecializationType(hasAnyTemplateArgument(
+/// isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")).bind("next")))))))}
+/// matches the specialization \match{type=typestr$A<&struct B::next>}
+/// with \matcher{type=sub$fieldDecl(hasName("next"))} matching
+/// \match{sub=next$int next}.
AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) {
if (Node.getKind() == TemplateArgument::Expression)
return InnerMatcher.matches(*Node.getAsExpr(), Finder, Builder);
@@ -1177,10 +1555,12 @@ AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) {
/// template<int T> struct C {};
/// C<42> c;
/// \endcode
-/// classTemplateSpecializationDecl(
-/// hasAnyTemplateArgument(isIntegral()))
-/// matches the implicit instantiation of C in C<42>
-/// with isIntegral() matching 42.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(isIntegral()))}
+/// matches the implicitly declared specialization
+/// \match{type=typestr$struct C<42>} from the instantiation for the type of the
+/// variable \c c .
AST_MATCHER(TemplateArgument, isIntegral) {
return Node.getKind() == TemplateArgument::Integral;
}
@@ -1192,9 +1572,12 @@ AST_MATCHER(TemplateArgument, isIntegral) {
/// template<int T> struct C {};
/// C<42> c;
/// \endcode
-/// classTemplateSpecializationDecl(
-/// hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
-/// matches the implicit instantiation of C in C<42>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(refersToIntegralType(asString("int"))))}
+/// matches the implicitly declared specialization
+/// \match{type=typestr$struct C<42>} from the instantiation for the type of the
+/// variable \c c .
AST_MATCHER_P(TemplateArgument, refersToIntegralType,
internal::Matcher<QualType>, InnerMatcher) {
if (Node.getKind() != TemplateArgument::Integral)
@@ -1213,9 +1596,12 @@ AST_MATCHER_P(TemplateArgument, refersToIntegralType,
/// template<int T> struct C {};
/// C<42> c;
/// \endcode
-/// classTemplateSpecializationDecl(
-/// hasAnyTemplateArgument(equalsIntegralValue("42")))
-/// matches the implicit instantiation of C in C<42>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(equalsIntegralValue("42")))}
+/// matches the implicitly declared specialization
+/// \match{type=typestr$struct C<42>} from the instantiation for the type of the
+/// variable \c c .
AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
std::string, Value) {
if (Node.getKind() != TemplateArgument::Integral)
@@ -1231,23 +1617,28 @@ AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
/// int x = 0;
/// }
/// \endcode
-/// autoreleasePoolStmt(stmt()) matches the declaration of "x"
-/// inside the autorelease pool.
+/// \compile_args{-ObjC}
+/// The matcher \matcher{autoreleasePoolStmt(stmt())} matches the declaration of
+/// \match{int x = 0} inside the autorelease pool.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
ObjCAutoreleasePoolStmt> autoreleasePoolStmt;
/// Matches any value declaration.
///
-/// Example matches A, B, C and F
+/// Given
/// \code
/// enum X { A, B, C };
/// void F();
+/// int V = 0;
/// \endcode
+/// The matcher \matcher{valueDecl()}
+/// matches \match{A}, \match{B}, \match{C}, \match{void F()}
+/// and \match{int V = 0}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
/// Matches C++ constructor declarations.
///
-/// Example matches Foo::Foo() and Foo::Foo(int)
+/// Given
/// \code
/// class Foo {
/// public:
@@ -1255,93 +1646,134 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
/// Foo(int);
/// int DoSomething();
/// };
+///
+/// struct Bar {};
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxConstructorDecl()}
+/// matches \match{Foo()} and \match{Foo(int)}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl>
cxxConstructorDecl;
/// Matches explicit C++ destructor declarations.
///
-/// Example matches Foo::~Foo()
+/// Given
/// \code
/// class Foo {
/// public:
/// virtual ~Foo();
/// };
+///
+/// struct Bar {};
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxDestructorDecl()}
+/// matches \match{virtual ~Foo()}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl>
cxxDestructorDecl;
/// Matches enum declarations.
///
-/// Example matches X
+/// Given
/// \code
-/// enum X {
-/// A, B, C
-/// };
+/// enum X { A, B, C };
/// \endcode
+///
+/// The matcher \matcher{enumDecl()}
+/// matches the enum \match{enum X { A, B, C }}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl;
/// Matches enum constants.
///
-/// Example matches A, B, C
+/// Given
/// \code
/// enum X {
/// A, B, C
/// };
/// \endcode
+/// The matcher \matcher{enumConstantDecl()}
+/// matches \match{A}, \match{B} and \match{C}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, EnumConstantDecl>
enumConstantDecl;
/// Matches tag declarations.
///
-/// Example matches X, Z, U, S, E
+/// Given
/// \code
/// class X;
/// template<class T> class Z {};
/// struct S {};
/// union U {};
-/// enum E {
-/// A, B, C
-/// };
+/// enum E { A, B, C };
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+///
+/// The matcher \matcher{tagDecl()}
+/// matches \match{class X}, \match{class Z {}}, the implicit class
+/// declaration \match{class Z}, \match{struct S {}},
+/// the implicit class declaration \match{struct S}, \match{union U {}},
+/// the implicit class declaration \match{union U}
+/// and \match{enum E { A, B, C }}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, TagDecl> tagDecl;
/// Matches method declarations.
///
-/// Example matches y
+/// Given
/// \code
/// class X { void y(); };
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxMethodDecl()}
+/// matches \match{void y()}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl>
cxxMethodDecl;
/// Matches conversion operator declarations.
///
-/// Example matches the operator.
+/// Given
/// \code
/// class X { operator int() const; };
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxConversionDecl()}
+/// matches \match{operator int() const}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
cxxConversionDecl;
/// Matches user-defined and implicitly generated deduction guide.
///
-/// Example matches the deduction guide.
+/// Given
/// \code
/// template<typename T>
-/// class X { X(int) };
+/// class X { X(int); };
/// X(int) -> X<int>;
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxDeductionGuideDecl()}
+/// matches the written deduction guide
+/// \match{type=typestr$auto (int) -> X<int>},
+/// the implicit copy deduction guide \match{type=typestr$auto (int) -> X<T>}
+/// and the implicitly declared deduction guide
+/// \match{type=typestr$auto (X<T>) -> X<T>}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
cxxDeductionGuideDecl;
/// Matches concept declarations.
///
-/// Example matches integral
+/// Given
/// \code
-/// template<typename T>
-/// concept integral = std::is_integral_v<T>;
+/// template<typename T> concept my_concept = true;
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++20-or-later}
+///
+/// The matcher \matcher{conceptDecl()}
+/// matches \match{template<typename T>
+/// concept my_concept = true}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl>
conceptDecl;
@@ -1353,17 +1785,29 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl>
/// Example matches a
/// \code
/// int a;
+/// struct Foo {
+/// int x;
+/// };
+/// void bar(int val);
/// \endcode
+///
+/// The matcher \matcher{varDecl()}
+/// matches \match{int a} and \match{int val}, but not \nomatch{int x}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl;
/// Matches field declarations.
///
/// Given
/// \code
-/// class X { int m; };
+/// int a;
+/// struct Foo {
+/// int x;
+/// };
+/// void bar(int val);
/// \endcode
-/// fieldDecl()
-/// matches 'm'.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{fieldDecl()}
+/// matches \match{int x}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl;
/// Matches indirect field declarations.
@@ -1372,17 +1816,20 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl;
/// \code
/// struct X { struct { int a; }; };
/// \endcode
-/// indirectFieldDecl()
-/// matches 'a'.
+/// The matcher \matcher{indirectFieldDecl()}
+/// matches \match{a}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, IndirectFieldDecl>
indirectFieldDecl;
/// Matches function declarations.
///
-/// Example matches f
+/// Given
/// \code
/// void f();
/// \endcode
+///
+/// The matcher \matcher{functionDecl()}
+/// matches \match{void f()}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl>
functionDecl;
@@ -1392,6 +1839,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl>
/// \code
/// template<class T> void f(T t) {}
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+///
+/// The matcher \matcher{functionTemplateDecl()}
+/// matches \match{template<class T> void f(T t) {}}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionTemplateDecl>
functionTemplateDecl;
@@ -1401,28 +1852,32 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionTemplateDecl>
/// \code
/// class X { friend void foo(); };
/// \endcode
-/// friendDecl()
-/// matches 'friend void foo()'.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{friendDecl()}
+/// matches \match{friend void foo()}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl;
/// Matches statements.
///
/// Given
/// \code
-/// { ++a; }
+/// void foo(int a) { { ++a; } }
/// \endcode
-/// stmt()
-/// matches both the compound statement '{ ++a; }' and '++a'.
+/// The matcher \matcher{stmt()}
+/// matches the function body itself \match{{ { ++a; } }}, the compound
+/// statement \match{{ ++a; }}, the expression \match{++a} and \match{a}.
extern const internal::VariadicAllOfMatcher<Stmt> stmt;
/// Matches declaration statements.
///
/// Given
/// \code
-/// int a;
+/// void foo() {
+/// int a;
+/// }
/// \endcode
-/// declStmt()
-/// matches 'int a'.
+/// The matcher \matcher{declStmt()}
+/// matches \match{int a;}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclStmt> declStmt;
/// Matches member expressions.
@@ -1434,8 +1889,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclStmt> declStmt;
/// int a; static int b;
/// };
/// \endcode
-/// memberExpr()
-/// matches this->x, x, y.x, a, this->b
+/// \compile_args{-std=c++}
+/// The matcher \matcher{memberExpr()}
+/// matches \match{this->x}, \match{x}, \match{y.x}, \match{a}, \match{this->b}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr;
/// Matches unresolved member expressions.
@@ -1448,8 +1904,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr;
/// };
/// template <class T> void h() { X x; x.f<T>(); x.g(); }
/// \endcode
-/// unresolvedMemberExpr()
-/// matches x.f<T>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unresolvedMemberExpr()}
+/// matches \match{x.f<T>}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedMemberExpr>
unresolvedMemberExpr;
@@ -1460,8 +1917,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedMemberExpr>
/// \code
/// template <class T> void f() { T t; t.g(); }
/// \endcode
-/// cxxDependentScopeMemberExpr()
-/// matches t.g
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxDependentScopeMemberExpr()}
+/// matches \match{t.g}
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
CXXDependentScopeMemberExpr>
cxxDependentScopeMemberExpr;
@@ -1470,15 +1928,22 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
///
/// Example matches x.y() and y()
/// \code
-/// X x;
-/// x.y();
-/// y();
+/// struct X { void foo(); };
+/// void bar();
+/// void foobar() {
+/// X x;
+/// x.foo();
+/// bar();
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{callExpr()}
+/// matches \match{x.foo()} and \match{bar()};
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr;
/// Matches call expressions which were resolved using ADL.
///
-/// Example matches y(x) but not y(42) or NS::y(x).
+/// Given
/// \code
/// namespace NS {
/// struct X {};
@@ -1494,25 +1959,46 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr;
/// y(42); // Doesn't match
/// using NS::y;
/// y(x); // Found by both unqualified lookup and ADL, doesn't match
-// }
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{callExpr(usesADL())}
+/// matches \match{y(x)}, but not \nomatch{y(42)} or \nomatch{NS::y(x)}.
AST_MATCHER(CallExpr, usesADL) { return Node.usesADL(); }
/// Matches lambda expressions.
///
-/// Example matches [&](){return 5;}
+/// Given
/// \code
-/// [&](){return 5;}
+/// void f() {
+/// []() { return 5; };
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{lambdaExpr()} matches \match{[]() { return 5; }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr;
/// Matches member call expressions.
///
-/// Example matches x.y()
+/// Given
/// \code
-/// X x;
-/// x.y();
+/// struct X {
+/// void y();
+/// void m() { y(); }
+/// };
+/// void f();
+/// void g() {
+/// X x;
+/// x.y();
+/// f();
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxMemberCallExpr()} matches \match{x.y()} and
+/// \match{y()}, but not \nomatch{f()}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr>
cxxMemberCallExpr;
@@ -1525,6 +2011,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr>
/// \code
/// [[NSString alloc] initWithString:@"Hello"]
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{objcMessageExpr()} matches
+/// \match{[[NSString alloc] initWithString:@"Hello"]}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCMessageExpr>
objcMessageExpr;
@@ -1534,6 +2024,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCMessageExpr>
/// \code
/// NSString *s = @"abcd";
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCStringLiteral>
objcStringLiteral;
@@ -1544,6 +2035,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCStringLiteral>
/// @interface Foo
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCInterfaceDecl>
objcInterfaceDecl;
@@ -1554,6 +2046,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCInterfaceDecl>
/// @implementation Foo
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCImplementationDecl>
objcImplementationDecl;
@@ -1564,6 +2057,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCImplementationDecl>
/// @protocol FooDelegate
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCProtocolDecl>
objcProtocolDecl;
@@ -1574,6 +2068,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCProtocolDecl>
/// @interface Foo (Additions)
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryDecl>
objcCategoryDecl;
@@ -1584,6 +2079,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryDecl>
/// @implementation Foo (Additions)
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryImplDecl>
objcCategoryImplDecl;
@@ -1599,6 +2095,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryImplDecl>
/// - (void)method {}
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCMethodDecl>
objcMethodDecl;
@@ -1612,6 +2109,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCMethodDecl>
/// printf("%d", p);
/// })
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, BlockDecl>
blockDecl;
@@ -1624,6 +2122,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, BlockDecl>
/// }
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCIvarDecl>
objcIvarDecl;
@@ -1635,6 +2134,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCIvarDecl>
/// @property BOOL enabled;
/// @end
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCPropertyDecl>
objcPropertyDecl;
@@ -1644,6 +2144,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCPropertyDecl>
/// \code
/// @throw obj;
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtThrowStmt>
objcThrowStmt;
@@ -1654,6 +2155,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtThrowStmt>
/// @try {}
/// @catch (...) {}
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtTryStmt>
objcTryStmt;
@@ -1664,6 +2166,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtTryStmt>
/// @try {}
/// @catch (...) {}
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtCatchStmt>
objcCatchStmt;
@@ -1674,6 +2177,7 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtCatchStmt>
/// @try {}
/// @finally {}
/// \endcode
+/// \compile_args{-ObjC}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtFinallyStmt>
objcFinallyStmt;
@@ -1682,8 +2186,21 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtFinallyStmt>
///
/// Example matches std::string()
/// \code
-/// const std::string str = std::string();
+/// struct A { ~A(); };
+/// void f(A);
+/// void g(A&);
+/// void h() {
+/// A a = A{};
+/// f(A{});
+/// f(a);
+/// g(a);
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{exprWithCleanups()} matches \match{A{}},
+/// \match{f(A{})} and \match{f(a)},
+/// but does not match passing \nomatch{g(a)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExprWithCleanups>
exprWithCleanups;
@@ -1693,17 +2210,29 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExprWithCleanups>
/// \code
/// int a[] = { 1, 2 };
/// struct B { int x, y; };
-/// B b = { 5, 6 };
+/// struct B b = { 5, 6 };
/// \endcode
-/// initListExpr()
-/// matches "{ 1, 2 }" and "{ 5, 6 }"
+/// The matcher \matcher{initListExpr()}
+/// matches \match{{ 1, 2 }} and \match{{ 5, 6 }}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr>
initListExpr;
/// Matches the syntactic form of init list expressions
/// (if expression have it).
-AST_MATCHER_P(InitListExpr, hasSyntacticForm,
- internal::Matcher<Expr>, InnerMatcher) {
+///
+/// Given
+/// \code
+/// int a[] = { 1, 2 };
+/// struct B { int x, y; };
+/// struct B b = { 5, 6 };
+/// \endcode
+/// \compile_args{-std=c}
+///
+/// The matcher
+/// \matcher{initListExpr(hasSyntacticForm(expr().bind("syntactic")))}
+/// matches \match{{ 1, 2 }} and \match{{ 5, 6 }}.
+AST_MATCHER_P(InitListExpr, hasSyntacticForm, internal::Matcher<Expr>,
+ InnerMatcher) {
const Expr *SyntForm = Node.getSyntacticForm();
return (SyntForm != nullptr &&
InnerMatcher.matches(*SyntForm, Finder, Builder));
@@ -1713,13 +2242,26 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm,
///
/// Given
/// \code
-/// std::vector<int> a({ 1, 2, 3 });
-/// std::vector<int> b = { 4, 5 };
+/// namespace std {
+/// template <typename T>
+/// class initializer_list {
+/// const T* begin;
+/// const T* end;
+/// };
+/// }
+/// template <typename T> class vector {
+/// public: vector(std::initializer_list<T>) {}
+/// };
+///
+/// vector<int> a({ 1, 2, 3 });
+/// vector<int> b = { 4, 5 };
/// int c[] = { 6, 7 };
-/// std::pair<int, int> d = { 8, 9 };
+/// struct pair { int x; int y; };
+/// pair d = { 8, 9 };
/// \endcode
-/// cxxStdInitializerListExpr()
-/// matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+/// \compile_args{-fno-delayed-template-parsing;-std=c++11-or-later,-nostdinc++}
+/// The matcher \matcher{cxxStdInitializerListExpr()}
+/// matches \match{{ 1, 2, 3 }} and \match{{ 4, 5 }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
CXXStdInitializerListExpr>
cxxStdInitializerListExpr;
@@ -1728,10 +2270,12 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
///
/// Given
/// \code
-/// point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
+/// struct point { double x; double y; };
+/// struct point pt = { .x = 42.0 };
/// \endcode
-/// implicitValueInitExpr()
-/// matches "[0].y" (implicitly)
+/// The matcher
+/// \matcher{initListExpr(has(implicitValueInitExpr().bind("implicit")))}
+/// matches \match{{ .x = 42.0 }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr>
implicitValueInitExpr;
@@ -1748,8 +2292,12 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr>
/// }
/// };
/// \endcode
-/// parenListExpr() matches "*this" but NOT matches (a, b) because (a, b)
-/// has a predefined type and is a ParenExpr, not a ParenListExpr.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{parenListExpr()}
+/// matches \match{(*this)},
+/// but does not match \nomatch{(a, b)}
+/// because (a, b) has a predefined type and is a ParenExpr, not a
+/// ParenListExpr.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr>
parenListExpr;
@@ -1761,8 +2309,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr>
/// struct A { static const int n = N; };
/// struct B : public A<42> {};
/// \endcode
-/// substNonTypeTemplateParmExpr()
-/// matches "N" in the right-hand side of "static const int n = N;"
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{substNonTypeTemplateParmExpr()}
+/// matches \match{N} in the right-hand side of "static const int n = N;"
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
SubstNonTypeTemplateParmExpr>
substNonTypeTemplateParmExpr;
@@ -1774,19 +2323,21 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
/// namespace X { int x; }
/// using X::x;
/// \endcode
-/// usingDecl()
-/// matches \code using X::x \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{usingDecl()}
+/// matches \match{using X::x}
extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl;
/// Matches using-enum declarations.
///
/// Given
/// \code
-/// namespace X { enum x {...}; }
+/// namespace X { enum x { val1, val2 }; }
/// using enum X::x;
/// \endcode
-/// usingEnumDecl()
-/// matches \code using enum X::x \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{usingEnumDecl()}
+/// matches \match{using enum X::x}
extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingEnumDecl>
usingEnumDecl;
@@ -1797,8 +2348,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingEnumDecl>
/// namespace X { int x; }
/// using namespace X;
/// \endcode
-/// usingDirectiveDecl()
-/// matches \code using namespace X \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{usingDirectiveDecl()}
+/// matches \match{using namespace X}
extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDirectiveDecl>
usingDirectiveDecl;
@@ -1814,8 +2366,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDirectiveDecl>
/// foo<T>();
/// }
/// \endcode
-/// unresolvedLookupExpr()
-/// matches \code foo<T>() \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unresolvedLookupExpr()}
+/// matches \match{foo<T>}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedLookupExpr>
unresolvedLookupExpr;
@@ -1828,8 +2381,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedLookupExpr>
/// using X::x;
/// };
/// \endcode
-/// unresolvedUsingValueDecl()
-/// matches \code using X::x \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unresolvedUsingValueDecl()}
+/// matches \match{using X::x}
extern const internal::VariadicDynCastAllOfMatcher<Decl,
UnresolvedUsingValueDecl>
unresolvedUsingValueDecl;
@@ -1847,80 +2401,110 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl,
/// using typename Base<T>::Foo;
/// };
/// \endcode
-/// unresolvedUsingTypenameDecl()
-/// matches \code using Base<T>::Foo \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unresolvedUsingTypenameDecl()}
+/// matches \match{using typename Base<T>::Foo}
extern const internal::VariadicDynCastAllOfMatcher<Decl,
UnresolvedUsingTypenameDecl>
unresolvedUsingTypenameDecl;
/// Matches a constant expression wrapper.
///
-/// Example matches the constant in the case statement:
-/// (matcher = constantExpr())
+/// Given
/// \code
-/// switch (a) {
-/// case 37: break;
+/// void f(int a) {
+/// switch (a) {
+/// case 37: break;
+/// }
/// }
/// \endcode
+///
+/// The matcher \matcher{constantExpr()} matches \match{37}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ConstantExpr>
constantExpr;
/// Matches parentheses used in expressions.
///
-/// Example matches (foo() + 1)
+/// Given
/// \code
/// int foo() { return 1; }
-/// int a = (foo() + 1);
+/// int bar() {
+/// int a = (foo() + 1);
+/// }
/// \endcode
+///
+/// The matcher \matcher{parenExpr()} matches \match{(foo() + 1)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ParenExpr> parenExpr;
/// Matches constructor call expressions (including implicit ones).
///
-/// Example matches string(ptr, n) and ptr within arguments of f
-/// (matcher = cxxConstructExpr())
+/// Given
/// \code
+/// struct string {
+/// string(const char*);
+/// string(const char*s, int n);
+/// };
/// void f(const string &a, const string &b);
-/// char *ptr;
-/// int n;
-/// f(string(ptr, n), ptr);
+/// void foo(char *ptr, int n) {
+/// f(string(ptr, n), ptr);
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxConstructExpr()} matches \match{string(ptr, n)}
+/// and \match{ptr} within arguments of \c f .
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstructExpr>
cxxConstructExpr;
/// Matches unresolved constructor call expressions.
///
-/// Example matches T(t) in return statement of f
-/// (matcher = cxxUnresolvedConstructExpr())
+/// Given
/// \code
/// template <typename T>
/// void f(const T& t) { return T(t); }
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+///
+/// The matcher \matcher{cxxUnresolvedConstructExpr()} matches
+/// \match{T(t)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
CXXUnresolvedConstructExpr>
cxxUnresolvedConstructExpr;
/// Matches implicit and explicit this expressions.
///
-/// Example matches the implicit this expression in "return i".
-/// (matcher = cxxThisExpr())
+/// Given
/// \code
-/// struct foo {
-/// int i;
-/// int f() { return i; }
-/// };
+/// struct foo {
+/// int i;
+/// int f() { return i; }
+/// int g() { return this->i; }
+/// };
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxThisExpr()}
+/// matches \match{this} of \c this->i and the implicit \c this expression
+/// of \match{i}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr>
cxxThisExpr;
/// Matches nodes where temporaries are created.
///
-/// Example matches FunctionTakesString(GetStringByValue())
-/// (matcher = cxxBindTemporaryExpr())
+/// Given
/// \code
-/// FunctionTakesString(GetStringByValue());
-/// FunctionTakesStringByPointer(GetStringPointer());
-/// \endcode
-extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBindTemporaryExpr>
+/// struct S {
+/// S() { } // User defined constructor makes S non-POD.
+/// ~S() { } // User defined destructor makes it non-trivial.
+/// };
+/// void test() {
+/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
+/// }
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxBindTemporaryExpr()}
+/// matches the constructor call \match{S()}.
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBindTemporaryExpr>
cxxBindTemporaryExpr;
/// Matches nodes where temporaries are materialized.
@@ -1930,17 +2514,19 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBindTemporaryExpr>
/// struct T {void func();};
/// T f();
/// void g(T);
+/// void foo() {
+/// T u(f());
+/// g(f());
+/// f().func();
+/// f(); // does not match
+/// }
/// \endcode
-/// materializeTemporaryExpr() matches 'f()' in these statements
-/// \code
-/// T u(f());
-/// g(f());
-/// f().func();
-/// \endcode
-/// but does not match
-/// \code
-/// f();
-/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{materializeTemporaryExpr()} matches
+/// \match{std=c++14-or-earlier;count=3$f()} three times before C++17 and it
+/// matches \match{std=c++17-or-later$f()} one time with C++17 and later for
+/// \c f().func() , but it does not match the \nomatch{f()} in the last line in
+/// any version.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
MaterializeTemporaryExpr>
materializeTemporaryExpr;
@@ -1949,20 +2535,34 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
///
/// Given
/// \code
-/// new X;
+/// void* operator new(decltype(sizeof(void*)));
+/// struct X {};
+/// void foo() {
+/// auto* x = new X;
+/// }
/// \endcode
-/// cxxNewExpr()
-/// matches 'new X'.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{cxxNewExpr()}
+/// matches \match{new X}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr;
/// Matches delete expressions.
///
/// Given
/// \code
-/// delete X;
+/// void* operator new(decltype(sizeof(void*)));
+/// void operator delete(void*);
+/// struct X {};
+/// void foo() {
+/// auto* x = new X;
+/// delete x;
+/// }
/// \endcode
-/// cxxDeleteExpr()
-/// matches 'delete X'.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{cxxDeleteExpr()}
+/// matches \match{delete x}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr>
cxxDeleteExpr;
@@ -1976,13 +2576,16 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr>
/// bool d() noexcept(noexcept(a()));
/// bool e = noexcept(b()) || noexcept(c());
/// \endcode
-/// cxxNoexceptExpr()
-/// matches `noexcept(a())`, `noexcept(b())` and `noexcept(c())`.
-/// doesn't match the noexcept specifier in the declarations a, b, c or d.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{cxxNoexceptExpr()}
+/// matches \match{noexcept(a())}, \match{noexcept(b())} and
+/// \match{noexcept(c())}, but does not match the noexcept specifier in the
+/// declarations a, b, c or d.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
cxxNoexceptExpr;
-/// Matches a loop initializing the elements of an array in a number of contexts:
+/// Matches a loop initializing the elements of an array in a number of
+/// contexts:
/// * in the implicit copy/move constructor for a class with an array member
/// * when a lambda-expression captures an array by value
/// * when a decomposition declaration decomposes an array
@@ -1991,33 +2594,34 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
/// \code
/// void testLambdaCapture() {
/// int a[10];
-/// auto Lam1 = [a]() {
-/// return;
-/// };
+/// [a]() {};
/// }
/// \endcode
-/// arrayInitLoopExpr() matches the implicit loop that initializes each element of
-/// the implicit array field inside the lambda object, that represents the array `a`
-/// captured by value.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{arrayInitLoopExpr()} matches the implicit loop that
+/// initializes each element of the implicit array field inside the lambda
+/// object, that represents the array \match{a} captured by value.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArrayInitLoopExpr>
arrayInitLoopExpr;
/// The arrayInitIndexExpr consists of two subexpressions: a common expression
-/// (the source array) that is evaluated once up-front, and a per-element initializer
-/// that runs once for each array element. Within the per-element initializer,
-/// the current index may be obtained via an ArrayInitIndexExpr.
+/// (the source array) that is evaluated once up-front, and a per-element
+/// initializer that runs once for each array element. Within the per-element
+/// initializer, the current index may be obtained via an ArrayInitIndexExpr.
///
/// Given
/// \code
-/// void testStructBinding() {
+/// void testStructuredBinding() {
/// int a[2] = {1, 2};
/// auto [x, y] = a;
/// }
/// \endcode
-/// arrayInitIndexExpr() matches the array index that implicitly iterates
-/// over the array `a` to copy each element to the anonymous array
-/// that backs the structured binding `[x, y]` elements of which are
-/// referred to by their aliases `x` and `y`.
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{type=none$arrayInitIndexExpr()} matches the array index
+/// that implicitly iterates over the array `a` to copy each element to the
+/// anonymous array that backs the structured binding.
+/// \match{}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArrayInitIndexExpr>
arrayInitIndexExpr;
@@ -2025,22 +2629,30 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArrayInitIndexExpr>
///
/// Given
/// \code
-/// int i = a[1];
+/// void foo() {
+/// int a[2] = {0, 1};
+/// int i = a[1];
+/// }
/// \endcode
-/// arraySubscriptExpr()
-/// matches "a[1]"
+/// The matcher \matcher{arraySubscriptExpr()}
+/// matches \match{a[1]}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArraySubscriptExpr>
arraySubscriptExpr;
/// Matches the value of a default argument at the call site.
///
-/// Example matches the CXXDefaultArgExpr placeholder inserted for the
-/// default value of the second parameter in the call expression f(42)
-/// (matcher = cxxDefaultArgExpr())
+/// Given
/// \code
/// void f(int x, int y = 0);
-/// f(42);
+/// void g() {
+/// f(42);
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{callExpr(has(cxxDefaultArgExpr()))}
+/// matches the \c CXXDefaultArgExpr placeholder inserted for the default value
+/// of the second parameter in the call expression \match{f(42)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr>
cxxDefaultArgExpr;
@@ -2051,13 +2663,18 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr>
/// Currently it does not match operators such as new delete.
/// FIXME: figure out why these do not match?
///
-/// Example matches both operator<<((o << b), c) and operator<<(o, b)
-/// (matcher = cxxOperatorCallExpr())
+/// Given
/// \code
+/// struct ostream;
/// ostream &operator<< (ostream &out, int i) { };
-/// ostream &o; int b = 1, c = 1;
-/// o << b << c;
+/// void f(ostream& o, int b, int c) {
+/// o << b << c;
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxOperatorCallExpr()} matches \match{o << b << c}
+/// and \match{o << b}.
/// See also the binaryOperation() matcher for more-general matching of binary
/// uses of this AST node.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr>
@@ -2065,13 +2682,16 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr>
/// Matches C++17 fold expressions.
///
-/// Example matches `(0 + ... + args)`:
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr()} matches \match{(0 + ... + args)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFoldExpr>
cxxFoldExpr;
@@ -2079,17 +2699,21 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFoldExpr>
///
/// Example matches use of "<":
/// \code
-/// #include <compare>
/// struct HasSpaceshipMem {
/// int a;
-/// constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
+/// constexpr bool operator==(const HasSpaceshipMem&) const = default;
/// };
/// void compare() {
/// HasSpaceshipMem hs1, hs2;
-/// if (hs1 < hs2)
+/// if (hs1 != hs2)
/// return;
/// }
/// \endcode
+/// \compile_args{-std=c++20-or-later}
+///
+/// The matcher \matcher{cxxRewrittenBinaryOperator()} matches
+/// \match{hs1 != hs2}.
+///
/// See also the binaryOperation() matcher for more-general matching
/// of this AST node.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
@@ -2098,25 +2722,34 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
/// Matches expressions.
///
-/// Example matches x()
+/// Given
/// \code
-/// void f() { x(); }
+/// int f(int x, int y) { return x + y; }
/// \endcode
+///
+/// The matcher \matcher{expr()} matches \match{x + y} once,
+/// \match{count=2$x} twice and \match{count=2$y} twice, matching the
+/// \c DeclRefExpr , and the \c ImplicitCastExpr that does an l- to r-value
+/// cast.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr;
/// Matches expressions that refer to declarations.
///
-/// Example matches x in if (x)
+/// Given
/// \code
-/// bool x;
-/// if (x) {}
+/// void f(bool x) {
+/// if (x) {}
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+///
+/// The matcher \matcher{declRefExpr()} matches \match{x}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr>
declRefExpr;
/// Matches a reference to an ObjCIvar.
///
-/// Example: matches "a" in "init" method:
+/// Given
/// \code
/// @implementation A {
/// NSString *a;
@@ -2125,42 +2758,61 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr>
/// a = @"hello";
/// }
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{objcIvarRefExpr()} matches \match{a}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCIvarRefExpr>
objcIvarRefExpr;
/// Matches a reference to a block.
///
-/// Example: matches "^{}":
+/// Given
/// \code
/// void f() { ^{}(); }
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{blockExpr()} matches \match{^{}}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, BlockExpr> blockExpr;
/// Matches if statements.
///
-/// Example matches 'if (x) {}'
+/// Given
/// \code
-/// if (x) {}
+/// void foo(int x) {
+/// if (x) {}
+/// }
/// \endcode
+///
+/// The matcher \matcher{ifStmt()} matches \match{if (x) {}}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt;
/// Matches for statements.
///
-/// Example matches 'for (;;) {}'
+/// Given
/// \code
-/// for (;;) {}
-/// int i[] = {1, 2, 3}; for (auto a : i);
+/// void foo() {
+/// for (;;) {}
+/// int i[] = {1, 2, 3}; for (auto a : i);
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{forStmt()} matches \match{for (;;) {}},
+/// but not \nomatch{for (auto a : i);}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt;
/// Matches the increment statement of a for loop.
///
-/// Example:
-/// forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
-/// matches '++x' in
+/// Given
/// \code
-/// for (x; x < N; ++x) { }
+/// void foo(int N) {
+/// for (int x = 0; x < N; ++x) { }
+/// }
/// \endcode
+/// The matcher
+/// \matcher{forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))}
+/// matches \match{for (int x = 0; x < N; ++x) { }}
AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
InnerMatcher) {
const Stmt *const Increment = Node.getInc();
@@ -2170,12 +2822,14 @@ AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
/// Matches the initialization statement of a for loop.
///
-/// Example:
-/// forStmt(hasLoopInit(declStmt()))
-/// matches 'int x = 0' in
+/// Given
/// \code
+/// void foo(int N) {
/// for (int x = 0; x < N; ++x) { }
+/// }
/// \endcode
+/// The matcher \matcher{forStmt(hasLoopInit(declStmt()))}
+/// matches \match{for (int x = 0; x < N; ++x) { }}
AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>,
InnerMatcher) {
const Stmt *const Init = Node.getInit();
@@ -2184,22 +2838,31 @@ AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>,
/// Matches range-based for statements.
///
-/// cxxForRangeStmt() matches 'for (auto a : i)'
+/// Given
/// \code
-/// int i[] = {1, 2, 3}; for (auto a : i);
-/// for(int j = 0; j < 5; ++j);
+/// void foo() {
+/// int i[] = {1, 2, 3}; for (auto a : i);
+/// for(int j = 0; j < 5; ++j);
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{cxxForRangeStmt()}
+/// matches \match{for (auto a : i);}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXForRangeStmt>
cxxForRangeStmt;
/// Matches the initialization statement of a for loop.
///
-/// Example:
-/// forStmt(hasLoopVariable(anything()))
-/// matches 'int x' in
+/// Given
/// \code
+/// void foo() {
+/// int a[42] = {};
/// for (int x : a) { }
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{cxxForRangeStmt(hasLoopVariable(anything()))}
+/// matches \match{for (int x : a) { }}
AST_MATCHER_P(CXXForRangeStmt, hasLoopVariable, internal::Matcher<VarDecl>,
InnerMatcher) {
const VarDecl *const Var = Node.getLoopVariable();
@@ -2208,12 +2871,16 @@ AST_MATCHER_P(CXXForRangeStmt, hasLoopVariable, internal::Matcher<VarDecl>,
/// Matches the range initialization statement of a for loop.
///
-/// Example:
-/// forStmt(hasRangeInit(anything()))
-/// matches 'a' in
+/// Given
/// \code
+/// void foo() {
+/// int a[42] = {};
/// for (int x : a) { }
+/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{cxxForRangeStmt(hasRangeInit(anything()))}
+/// matches \match{for (int x : a) { }}
AST_MATCHER_P(CXXForRangeStmt, hasRangeInit, internal::Matcher<Expr>,
InnerMatcher) {
const Expr *const Init = Node.getRangeInit();
@@ -2224,40 +2891,52 @@ AST_MATCHER_P(CXXForRangeStmt, hasRangeInit, internal::Matcher<Expr>,
///
/// Given
/// \code
+/// void foo() {
/// while (true) {}
+/// }
/// \endcode
-/// whileStmt()
-/// matches 'while (true) {}'.
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{whileStmt()}
+/// matches \match{while (true) {}}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt;
/// Matches do statements.
///
/// Given
/// \code
+/// void foo() {
/// do {} while (true);
+/// }
/// \endcode
-/// doStmt()
-/// matches 'do {} while(true)'
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{doStmt()}
+/// matches \match{do {} while (true)}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt;
/// Matches break statements.
///
/// Given
/// \code
+/// void foo() {
/// while (true) { break; }
+/// }
/// \endcode
-/// breakStmt()
-/// matches 'break'
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{breakStmt()}
+/// matches \match{break}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt;
/// Matches continue statements.
///
/// Given
/// \code
+/// void foo() {
/// while (true) { continue; }
+/// }
/// \endcode
-/// continueStmt()
-/// matches 'continue'
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{continueStmt()}
+/// matches \match{continue}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt>
continueStmt;
@@ -2265,10 +2944,46 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt>
///
/// Given
/// \code
-/// while (true) { co_return; }
+/// namespace std {
+/// template <typename T = void>
+/// struct coroutine_handle {
+/// static constexpr coroutine_handle from_address(void* addr) {
+/// return {};
+/// }
+/// };
+///
+/// struct always_suspend {
+/// bool await_ready() const noexcept;
+/// bool await_resume() const noexcept;
+/// template <typename T>
+/// bool await_suspend(coroutine_handle<T>) const noexcept;
+/// };
+///
+/// template <typename T>
+/// struct coroutine_traits {
+/// using promise_type = T::promise_type;
+/// };
+/// } // namespace std
+///
+/// struct generator {
+/// struct promise_type {
+/// void return_value(int v);
+/// std::always_suspend yield_value(int&&);
+/// std::always_suspend initial_suspend() const noexcept;
+/// std::always_suspend final_suspend() const noexcept;
+/// void unhandled_exception();
+/// generator get_return_object();
+/// };
+/// };
+///
+/// generator f() {
+/// co_return 10;
+/// }
+///
/// \endcode
-/// coreturnStmt()
-/// matches 'co_return'
+/// \compile_args{-std=c++20-or-later}
+/// The matcher \matcher{coreturnStmt(has(integerLiteral()))}
+/// matches \match{co_return 10}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoreturnStmt>
coreturnStmt;
@@ -2276,44 +2991,55 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoreturnStmt>
///
/// Given
/// \code
+/// int foo() {
/// return 1;
+/// }
/// \endcode
-/// returnStmt()
-/// matches 'return 1'
+/// The matcher \matcher{returnStmt()}
+/// matches \match{return 1}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt;
/// Matches goto statements.
///
/// Given
/// \code
+/// void bar();
+/// void foo() {
/// goto FOO;
/// FOO: bar();
+/// }
/// \endcode
-/// gotoStmt()
-/// matches 'goto FOO'
+/// The matcher \matcher{gotoStmt()}
+/// matches \match{goto FOO}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt;
/// Matches label statements.
///
/// Given
/// \code
+/// void bar();
+/// void foo() {
/// goto FOO;
/// FOO: bar();
+/// }
/// \endcode
-/// labelStmt()
-/// matches 'FOO:'
+/// The matcher \matcher{labelStmt()}
+/// matches \match{FOO: bar()}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt;
/// Matches address of label statements (GNU extension).
///
/// Given
/// \code
+/// void bar();
+/// void foo() {
/// FOO: bar();
/// void *ptr = &&FOO;
-/// goto *bar;
+/// goto *ptr;
+/// }
/// \endcode
-/// addrLabelExpr()
-/// matches '&&FOO'
+/// The matcher \matcher{addrLabelExpr()}
+/// matches \match{&&FOO}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr>
addrLabelExpr;
@@ -2321,116 +3047,147 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr>
///
/// Given
/// \code
+/// void foo(int a) {
/// switch(a) { case 42: break; default: break; }
+/// }
/// \endcode
-/// switchStmt()
-/// matches 'switch(a)'.
+/// The matcher \matcher{switchStmt()}
+/// matches \match{switch(a) { case 42: break; default: break; }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt;
/// Matches case and default statements inside switch statements.
///
/// Given
/// \code
+/// void foo(int a) {
/// switch(a) { case 42: break; default: break; }
+/// }
/// \endcode
-/// switchCase()
-/// matches 'case 42:' and 'default:'.
+/// The matcher \matcher{switchCase()}
+/// matches \match{case 42: break} and \match{default: break}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase;
/// Matches case statements inside switch statements.
///
/// Given
/// \code
+/// void foo(int a) {
/// switch(a) { case 42: break; default: break; }
+/// }
/// \endcode
-/// caseStmt()
-/// matches 'case 42:'.
+/// The matcher \matcher{caseStmt()}
+/// matches \match{case 42: break}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt;
/// Matches default statements inside switch statements.
///
/// Given
/// \code
+/// void foo(int a) {
/// switch(a) { case 42: break; default: break; }
+/// }
/// \endcode
-/// defaultStmt()
-/// matches 'default:'.
+/// The matcher \matcher{defaultStmt()}
+/// matches \match{default: break}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt>
defaultStmt;
/// Matches compound statements.
///
-/// Example matches '{}' and '{{}}' in 'for (;;) {{}}'
+/// Given
/// \code
-/// for (;;) {{}}
+/// void foo() { for (;;) {{}} }
/// \endcode
+///
+/// The matcher \matcher{compoundStmt()} matches
+/// \match{{ for (;;) {{}} }}, \match{{{}}} and \match{{}}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt>
compoundStmt;
/// Matches catch statements.
///
/// \code
+/// void foo() {
/// try {} catch(int i) {}
+/// }
/// \endcode
-/// cxxCatchStmt()
-/// matches 'catch(int i)'
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxCatchStmt()}
+/// matches \match{catch(int i) {}}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt>
cxxCatchStmt;
/// Matches try statements.
///
/// \code
+/// void foo() {
/// try {} catch(int i) {}
+/// }
/// \endcode
-/// cxxTryStmt()
-/// matches 'try {}'
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxTryStmt()}
+/// matches \match{try {} catch(int i) {}}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt;
/// Matches throw expressions.
///
/// \code
+/// void foo() {
/// try { throw 5; } catch(int i) {}
+/// }
/// \endcode
-/// cxxThrowExpr()
-/// matches 'throw 5'
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxThrowExpr()}
+/// matches \match{throw 5}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr>
cxxThrowExpr;
/// Matches null statements.
///
/// \code
+/// void foo() {
/// foo();;
+/// }
/// \endcode
-/// nullStmt()
-/// matches the second ';'
+/// The matcher \matcher{nullStmt()}
+/// matches the second \match{;}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt;
/// Matches asm statements.
///
/// \code
+/// void foo() {
/// int i = 100;
-/// __asm("mov al, 2");
+/// __asm("mov %al, 2");
+/// }
/// \endcode
-/// asmStmt()
-/// matches '__asm("mov al, 2")'
+/// The matcher \matcher{asmStmt()}
+/// matches \match{__asm("mov %al, 2")}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt;
/// Matches bool literals.
///
/// Example matches true
/// \code
-/// true
+/// bool Flag = true;
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+///
+/// The matcher \matcher{cxxBoolLiteral()} matches \match{true}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBoolLiteralExpr>
cxxBoolLiteral;
/// Matches string literals (also matches wide string literals).
///
-/// Example matches "abcd", L"abcd"
+/// Given
/// \code
/// char *s = "abcd";
/// wchar_t *ws = L"abcd";
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{stringLiteral()} matches \match{"abcd"} and
+/// \match{L"abcd"}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral>
stringLiteral;
@@ -2439,11 +3196,15 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral>
/// Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
/// though.
///
-/// Example matches 'a', L'a'
+/// Given
/// \code
/// char ch = 'a';
/// wchar_t chw = L'a';
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{characterLiteral()} matches \match{'a'} and
+/// \match{L'a'}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CharacterLiteral>
characterLiteral;
@@ -2451,31 +3212,80 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CharacterLiteral>
/// 1, 1L, 0x1 and 1U.
///
/// Does not match character-encoded integers such as L'a'.
+///
+/// Given
+/// \code
+/// int a = 1;
+/// int b = 1L;
+/// int c = 0x1;
+/// int d = 1U;
+/// int e = 1.0;
+/// \endcode
+///
+/// The matcher \matcher{integerLiteral()} matches
+/// \match{1}, \match{1L}, \match{0x1} and \match{1U}, but does not match
+/// \nomatch{1.0}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, IntegerLiteral>
integerLiteral;
/// Matches float literals of all sizes / encodings, e.g.
/// 1.0, 1.0f, 1.0L and 1e10.
///
-/// Does not match implicit conversions such as
+/// Given
/// \code
-/// float a = 10;
+/// int a = 1.0;
+/// int b = 1.0F;
+/// int c = 1.0L;
+/// int d = 1e10;
+/// int e = 1;
/// \endcode
+///
+/// The matcher \matcher{floatLiteral()} matches
+/// \match{1.0}, \match{1.0F}, \match{1.0L} and \match{1e10}, but does not match
+/// \nomatch{1}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, FloatingLiteral>
floatLiteral;
/// Matches imaginary literals, which are based on integer and floating
/// point literals e.g.: 1i, 1.0i
+///
+/// Given
+/// \code
+/// auto a = 1i;
+/// auto b = 1.0i;
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{imaginaryLiteral()} matches \match{1i} and
+/// \match{1.0i}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImaginaryLiteral>
imaginaryLiteral;
/// Matches fixed point literals
+///
+/// Given
+/// \code
+/// void f() {
+/// 0.0k;
+/// }
+/// \endcode
+/// \compile_args{-ffixed-point}
+///
+/// The matcher \matcher{type=none$fixedPointLiteral()} matches \match{0.0k}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, FixedPointLiteral>
fixedPointLiteral;
/// Matches user defined literal operator call.
///
/// Example match: "foo"_suffix
+/// Given
+/// \code
+/// float operator ""_foo(long double);
+/// float a = 1234.5_foo;
+/// \endcode
+/// \compile_args{-std=c++11}
+///
+/// The matcher \matcher{userDefinedLiteral()} matches \match{1234.5_foo}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral>
userDefinedLiteral;
@@ -2483,9 +3293,12 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral>
///
/// Example match: {1}, (1, 2)
/// \code
-/// int array[4] = {1};
-/// vector int myvec = (vector int)(1, 2);
+/// struct vector { int x; int y; };
+/// struct vector myvec = (struct vector){ 1, 2 };
/// \endcode
+///
+/// The matcher \matcher{compoundLiteralExpr()}
+/// matches \match{(struct vector){ 1, 2 }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
compoundLiteralExpr;
@@ -2493,78 +3306,297 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
///
/// Given
/// \code
-/// co_await 1;
+/// namespace std {
+/// template <typename T = void>
+/// struct coroutine_handle {
+/// static constexpr coroutine_handle from_address(void* addr) {
+/// return {};
+/// }
+/// };
+///
+/// struct always_suspend {
+/// bool await_ready() const noexcept;
+/// bool await_resume() const noexcept;
+/// template <typename T>
+/// bool await_suspend(coroutine_handle<T>) const noexcept;
+/// };
+///
+/// template <typename T>
+/// struct coroutine_traits {
+/// using promise_type = T::promise_type;
+/// };
+/// } // namespace std
+///
+/// struct generator {
+/// struct promise_type {
+/// std::always_suspend yield_value(int&&);
+/// std::always_suspend initial_suspend() const noexcept;
+/// std::always_suspend final_suspend() const noexcept;
+/// void return_void();
+/// void unhandled_exception();
+/// generator get_return_object();
+/// };
+/// };
+///
+/// std::always_suspend h();
+///
+/// generator g() { co_await h(); }
/// \endcode
-/// coawaitExpr()
-/// matches 'co_await 1'
+/// \compile_args{-std=c++20-or-later}
+/// The matcher
+/// \matcher{coawaitExpr(has(callExpr(callee(functionDecl(hasName("h"))))))}
+/// matches \match{co_await h()}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoawaitExpr>
coawaitExpr;
+
/// Matches co_await expressions where the type of the promise is dependent
+///
+/// Given
+/// \code
+/// namespace std {
+/// template <typename T = void>
+/// struct coroutine_handle {
+/// static constexpr coroutine_handle from_address(void* addr) {
+/// return {};
+/// }
+/// };
+///
+/// struct always_suspend {
+/// bool await_ready() const noexcept;
+/// bool await_resume() const noexcept;
+/// template <typename T>
+/// bool await_suspend(coroutine_handle<T>) const noexcept;
+/// };
+///
+/// template <typename T>
+/// struct coroutine_traits {
+/// using promise_type = T::promise_type;
+/// };
+/// } // namespace std
+///
+/// template <typename T>
+/// struct generator {
+/// struct promise_type {
+/// std::always_suspend yield_value(int&&);
+/// std::always_suspend initial_suspend() const noexcept;
+/// std::always_suspend final_suspend() const noexcept;
+/// void return_void();
+/// void unhandled_exception();
+/// generator get_return_object();
+/// };
+/// };
+///
+/// template <typename T>
+/// std::always_suspend h();
+///
+/// template <>
+/// std::always_suspend h<void>();
+///
+/// template<typename T>
+/// generator<T> g() { co_await h<T>(); }
+/// \endcode
+/// \compile_args{-std=c++20-or-later}
+/// The matcher \matcher{dependentCoawaitExpr()}
+/// matches \match{co_await h<T>()}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DependentCoawaitExpr>
dependentCoawaitExpr;
+
/// Matches co_yield expressions.
///
/// Given
/// \code
-/// co_yield 1;
+/// namespace std {
+/// template <typename T = void>
+/// struct coroutine_handle {
+/// static constexpr coroutine_handle from_address(void* addr) {
+/// return {};
+/// }
+/// };
+///
+/// struct always_suspend {
+/// bool await_ready() const noexcept;
+/// bool await_resume() const noexcept;
+/// template <typename T>
+/// bool await_suspend(coroutine_handle<T>) const noexcept;
+/// };
+///
+/// template <typename T>
+/// struct coroutine_traits {
+/// using promise_type = T::promise_type;
+/// };
+/// } // namespace std
+///
+/// struct generator {
+/// struct promise_type {
+/// std::always_suspend yield_value(int&&);
+/// std::always_suspend initial_suspend() const noexcept;
+/// std::always_suspend final_suspend() const noexcept;
+/// void return_void();
+/// void unhandled_exception();
+/// generator get_return_object();
+/// };
+/// };
+///
+/// generator f() {
+/// while (true) {
+/// co_yield 10;
+/// }
+/// }
/// \endcode
-/// coyieldExpr()
-/// matches 'co_yield 1'
+/// \compile_args{-std=c++20-or-later}
+/// The matcher \matcher{coyieldExpr()}
+/// matches \match{co_yield 10}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoyieldExpr>
coyieldExpr;
/// Matches coroutine body statements.
///
-/// coroutineBodyStmt() matches the coroutine below
+/// Given
/// \code
-/// generator<int> gen() {
-/// co_return;
-/// }
+/// namespace std {
+/// template <typename T = void>
+/// struct coroutine_handle {
+/// static constexpr coroutine_handle from_address(void* addr) {
+/// return {};
+/// }
+/// };
+///
+/// struct suspend_always {
+/// bool await_ready() const noexcept;
+/// bool await_resume() const noexcept;
+/// template <typename T>
+/// bool await_suspend(coroutine_handle<T>) const noexcept;
+/// };
+///
+/// template <typename...>
+/// struct coroutine_traits {
+/// struct promise_type {
+/// std::suspend_always initial_suspend() const noexcept;
+/// std::suspend_always final_suspend() const noexcept;
+/// void return_void();
+/// void unhandled_exception();
+/// coroutine_traits get_return_object();
+/// };
+/// };
+/// } // namespace std
+///
+/// void f() { while (true) { co_return; } }
+///
/// \endcode
+/// \compile_args{-std=c++20-or-later}
+///
+/// The matcher \matcher{coroutineBodyStmt()} matches
+/// \match{{ while (true) { co_return; } }}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoroutineBodyStmt>
coroutineBodyStmt;
/// Matches nullptr literal.
+///
+/// Given
+/// \code
+/// int a = 0;
+/// int* b = 0;
+/// int *c = nullptr;
+/// \endcode
+/// \compile_args{-std=c++11,c23-or-later}
+///
+/// The matcher \matcher{cxxNullPtrLiteralExpr()} matches \match{nullptr}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
cxxNullPtrLiteralExpr;
/// Matches GNU __builtin_choose_expr.
-extern const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr>
- chooseExpr;
+///
+/// Given
+/// \code
+/// void f() { (void)__builtin_choose_expr(1, 2, 3); }
+/// \endcode
+///
+/// The matcher \matcher{chooseExpr()} matches
+/// \match{__builtin_choose_expr(1, 2, 3)}.
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr> chooseExpr;
/// Matches builtin function __builtin_convertvector.
+///
+/// Given
+/// \code
+/// typedef double vector4double __attribute__((__vector_size__(32)));
+/// typedef float vector4float __attribute__((__vector_size__(16)));
+/// vector4float vf;
+/// void f() { (void)__builtin_convertvector(vf, vector4double); }
+/// \endcode
+///
+/// The matcher \matcher{convertVectorExpr()} matches
+/// \match{__builtin_convertvector(vf, vector4double)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ConvertVectorExpr>
convertVectorExpr;
/// Matches GNU __null expression.
+///
+/// Given
+/// \code
+/// auto val = __null;
+/// \endcode
+/// \compile_args{-std=c++11}
+///
+/// The matcher \matcher{gnuNullExpr()} matches \match{__null}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr>
gnuNullExpr;
/// Matches C11 _Generic expression.
+///
+/// Given
+/// \code
+/// double fdouble(double);
+/// float ffloat(float);
+/// #define GENERIC_MACRO(X) _Generic((X), double: fdouble, float: ffloat)(X)
+///
+/// void f() {
+/// GENERIC_MACRO(0.0);
+/// GENERIC_MACRO(0.0F);
+/// }
+/// \endcode
+/// \compile_args{-std=c}
+///
+/// The matcher \matcher{type=none$genericSelectionExpr()} matches
+/// the generic selection expression that is expanded in
+/// \match{GENERIC_MACRO(0.0)} and \match{GENERIC_MACRO(0.0F)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, GenericSelectionExpr>
genericSelectionExpr;
/// Matches atomic builtins.
-/// Example matches __atomic_load_n(ptr, 1)
+///
+/// Given
/// \code
/// void foo() { int *ptr; __atomic_load_n(ptr, 1); }
/// \endcode
+///
+/// The matcher \matcher{atomicExpr()} matches \match{__atomic_load_n(ptr, 1)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr;
/// Matches statement expression (GNU extension).
///
-/// Example match: ({ int X = 4; X; })
+/// Given
/// \code
-/// int C = ({ int X = 4; X; });
+/// void f() {
+/// int C = ({ int X = 4; X; });
+/// }
/// \endcode
+///
+/// The matcher \matcher{stmtExpr()} matches \match{({ int X = 4; X; })}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr;
/// Matches binary operator expressions.
///
-/// Example matches a || b
+/// Given
/// \code
-/// !(a || b)
+/// void foo(bool a, bool b) {
+/// !(a || b);
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+///
+/// The matcher \matcher{binaryOperator()} matches \match{a || b}.
+///
/// See also the binaryOperation() matcher for more-general matching.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryOperator>
binaryOperator;
@@ -2573,26 +3605,39 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryOperator>
///
/// Example matches !a
/// \code
-/// !a || b
+/// void foo(bool a, bool b) {
+/// !a || b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+///
+/// The matcher \matcher{unaryOperator()} matches \match{!a}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryOperator>
unaryOperator;
/// Matches conditional operator expressions.
///
-/// Example matches a ? b : c
+/// Given
/// \code
-/// (a ? b : c) + 42
+/// int f(int a, int b, int c) {
+/// return (a ? b : c) + 42;
+/// }
/// \endcode
+///
+/// The matcher \matcher{conditionalOperator()} matches \match{a ? b : c}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ConditionalOperator>
conditionalOperator;
/// Matches binary conditional operator expressions (GNU extension).
///
-/// Example matches a ?: b
+/// Given
/// \code
-/// (a ?: b) + 42;
+/// int f(int a, int b) {
+/// return (a ?: b) + 42;
+/// }
/// \endcode
+///
+/// The matcher \matcher{binaryConditionalOperator()} matches \match{a ?: b}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
BinaryConditionalOperator>
binaryConditionalOperator;
@@ -2601,26 +3646,32 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
/// to reference another expressions and can be met
/// in BinaryConditionalOperators, for example.
///
-/// Example matches 'a'
+/// Given
/// \code
-/// (a ?: c) + 42;
+/// int f(int a, int b) {
+/// return (a ?: b) + 42;
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{opaqueValueExpr()} matches \match{count=2$a} twice,
+/// once for the check and once for the expression of the true path.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, OpaqueValueExpr>
opaqueValueExpr;
/// Matches a C++ static_assert declaration.
///
-/// Example:
-/// staticAssertDecl()
-/// matches
-/// static_assert(sizeof(S) == sizeof(int))
-/// in
+/// Given
/// \code
/// struct S {
/// int x;
/// };
/// static_assert(sizeof(S) == sizeof(int));
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{staticAssertDecl()}
+/// matches \match{static_assert(sizeof(S) == sizeof(int))}.
extern const internal::VariadicDynCastAllOfMatcher<Decl, StaticAssertDecl>
staticAssertDecl;
@@ -2634,6 +3685,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, StaticAssertDecl>
/// \code
/// void* p = reinterpret_cast<char*>(&p);
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxReinterpretCastExpr()}
+/// matches \match{reinterpret_cast<char*>(&p)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXReinterpretCastExpr>
cxxReinterpretCastExpr;
@@ -2642,49 +3697,56 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXReinterpretCastExpr>
/// \see hasDestinationType
/// \see reinterpretCast
///
-/// Example:
-/// cxxStaticCastExpr()
-/// matches
-/// static_cast<long>(8)
-/// in
+/// Given
/// \code
/// long eight(static_cast<long>(8));
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxStaticCastExpr()}
+/// matches \match{static_cast<long>(8)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXStaticCastExpr>
cxxStaticCastExpr;
/// Matches a dynamic_cast expression.
///
-/// Example:
-/// cxxDynamicCastExpr()
-/// matches
-/// dynamic_cast<D*>(&b);
-/// in
+/// Given
/// \code
/// struct B { virtual ~B() {} }; struct D : B {};
/// B b;
/// D* p = dynamic_cast<D*>(&b);
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxDynamicCastExpr()}
+/// matches \match{dynamic_cast<D*>(&b)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDynamicCastExpr>
cxxDynamicCastExpr;
/// Matches a const_cast expression.
///
-/// Example: Matches const_cast<int*>(&r) in
+/// Given
/// \code
/// int n = 42;
/// const int &r(n);
/// int* p = const_cast<int*>(&r);
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxConstCastExpr()}
+/// matches \match{const_cast<int*>(&r)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr>
cxxConstCastExpr;
/// Matches a C-style cast expression.
///
-/// Example: Matches (int) 2.2f in
+/// Given
/// \code
/// int i = (int) 2.2f;
/// \endcode
+///
+/// The matcher \matcher{cStyleCastExpr()}
+/// matches \match{(int) 2.2f}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr>
cStyleCastExpr;
@@ -2701,14 +3763,25 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr>
///
/// \see hasDestinationType.
///
-/// Example: matches all five of the casts in
/// \code
-/// int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
-/// \endcode
-/// but does not match the implicit conversion in
-/// \code
-/// long ell = 42;
-/// \endcode
+/// struct S {};
+/// const S* s;
+/// S* s2 = const_cast<S*>(s);
+///
+/// const int val = 0;
+/// char val0 = val;
+/// char val1 = (char)val;
+/// char val2 = static_cast<char>(val);
+/// int* val3 = reinterpret_cast<int*>(val);
+/// char val4 = char(val);
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{explicitCastExpr()}
+/// matches \match{(char)val}, \match{static_cast<char>(val)},
+/// \match{reinterpret_cast<int*>(val)}, \match{const_cast<S*>(s)}
+/// and \match{char(val)}, but not the initialization of \c val0 with
+/// \nomatch{val}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr>
explicitCastExpr;
@@ -2716,41 +3789,89 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr>
///
/// This matches many
diff erent places, including function call return value
/// eliding, as well as any type conversions.
+///
+/// \code
+/// void f(int);
+/// void g(int val1, int val2) {
+/// unsigned int a = val1;
+/// f(val2);
+/// }
+/// \endcode
+///
+/// The matcher \matcher{implicitCastExpr()}
+/// matches \match{count=2$val1} for the implicit cast from an l- to an r-value
+/// and for the cast to \c{unsigned int}, \match{f} for the function pointer
+/// decay, and \match{val2} for the cast from an l- to an r-value.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitCastExpr>
implicitCastExpr;
/// Matches any cast nodes of Clang's AST.
///
-/// Example: castExpr() matches each of the following:
-/// \code
-/// (int) 3;
-/// const_cast<Expr *>(SubExpr);
-/// char c = 0;
-/// \endcode
-/// but does not match
+/// Given
/// \code
-/// int i = (0);
-/// int k = 0;
+/// struct S {};
+/// const S* s;
+/// S* s2 = const_cast<S*>(s);
+///
+/// const int val = 0;
+/// char val0 = 1;
+/// char val1 = (char)2;
+/// char val2 = static_cast<char>(3);
+/// int* val3 = reinterpret_cast<int*>(4);
+/// char val4 = char(5);
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{castExpr()}
+/// matches
+/// \match{const_cast<S*>(s)} and the implicit l- to r-value cast for \match{s},
+/// the implicit cast to \c char for the initializer \match{1},
+/// the c-style cast \match{(char)2} and it's implicit cast to \c char
+/// (part of the c-style cast) \match{2},
+/// \match{static_cast<char>(3)} and it's implicit cast to \c char
+/// (part of the \c static_cast) \match{3},
+/// \match{reinterpret_cast<int*>(4)},
+/// \match{char(5)} and it's implicit cast to \c char
+/// (part of the functional cast) \match{5}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr;
/// Matches functional cast expressions
///
-/// Example: Matches Foo(bar);
+/// Given
/// \code
-/// Foo f = bar;
-/// Foo g = (Foo) bar;
-/// Foo h = Foo(bar);
+/// struct Foo {
+/// Foo(int x);
+/// };
+///
+/// void foo(int bar) {
+/// Foo f = bar;
+/// Foo g = (Foo) bar;
+/// Foo h = Foo(bar);
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxFunctionalCastExpr()}
+/// matches \match{Foo(bar)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFunctionalCastExpr>
cxxFunctionalCastExpr;
/// Matches functional cast expressions having N != 1 arguments
///
-/// Example: Matches Foo(bar, bar)
+/// Given
/// \code
-/// Foo h = Foo(bar, bar);
+/// struct Foo {
+/// Foo(int x, int y);
+/// };
+///
+/// void foo(int bar) {
+/// Foo h = Foo(bar, bar);
+/// }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxTemporaryObjectExpr()}
+/// matches \match{Foo(bar, bar)}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTemporaryObjectExpr>
cxxTemporaryObjectExpr;
@@ -2758,17 +3879,27 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTemporaryObjectExpr>
///
/// Example: Matches __func__
/// \code
-/// printf("%s", __func__);
+/// void f() {
+/// const char* func_name = __func__;
+/// }
/// \endcode
+///
+/// The matcher \matcher{predefinedExpr()}
+/// matches \match{__func__}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, PredefinedExpr>
predefinedExpr;
/// Matches C99 designated initializer expressions [C99 6.7.8].
///
-/// Example: Matches { [2].y = 1.0, [0].x = 1.0 }
+/// Example: Given
/// \code
-/// point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+/// struct point2 { double x; double y; };
+/// struct point2 ptarray[10] = { [0].x = 1.0 };
+/// struct point2 pt = { .x = 2.0 };
/// \endcode
+///
+/// The matcher \matcher{designatedInitExpr()}
+/// matches \match{[0].x = 1.0} and \match{.x = 2.0}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, DesignatedInitExpr>
designatedInitExpr;
@@ -2777,23 +3908,53 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, DesignatedInitExpr>
///
/// Example: Given
/// \code
-/// point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
-/// point ptarray2[10] = { [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 };
+/// struct point2 { double x; double y; };
+/// struct point2 ptarray[10] = { [0].x = 1.0 };
+/// struct point2 pt = { .x = 2.0 };
/// \endcode
-/// designatorCountIs(2)
-/// matches '{ [2].y = 1.0, [0].x = 1.0 }',
-/// but not '{ [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }'.
+///
+/// The matcher \matcher{designatedInitExpr(designatorCountIs(2))}
+/// matches \match{[0].x = 1.0}, but not \nomatch{.x = 2.0}.
AST_MATCHER_P(DesignatedInitExpr, designatorCountIs, unsigned, N) {
return Node.size() == N;
}
/// Matches \c QualTypes in the clang AST.
+///
+/// Given
+/// \code
+/// int a = 0;
+/// const int b = 1;
+/// \endcode
+///
+/// The matcher \matcher{varDecl(hasType(qualType(isConstQualified())))}
+/// matches \match{const int b = 1}, but not \nomatch{int a = 0}.
extern const internal::VariadicAllOfMatcher<QualType> qualType;
/// Matches \c Types in the clang AST.
+///
+/// Given
+/// \code
+/// const int b = 1;
+/// \endcode
+///
+/// The matcher \matcher{varDecl(hasType(type().bind("type")))}
+/// matches \match{const int b = 1}, with \matcher{type=sub$type()}
+/// matching \match{sub=type$int}.
extern const internal::VariadicAllOfMatcher<Type> type;
/// Matches \c TypeLocs in the clang AST.
+///
+/// That is, information about a type and where it was written.
+///
+/// \code
+/// void foo(int val);
+/// \endcode
+///
+/// The matcher \matcher{declaratorDecl(hasTypeLoc(typeLoc().bind("type")))}
+/// matches \match{void foo(int val)} and \match{int val}, with
+/// \matcher{type=sub$typeLoc()} matching \match{sub=type$void} and
+/// \match{sub=type$int} respectively.
extern const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
/// Matches if any of the given matchers matches.
@@ -2801,18 +3962,20 @@ extern const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
/// Unlike \c anyOf, \c eachOf will generate a match result for each
/// matching submatcher.
///
-/// For example, in:
-/// \code
-/// class A { int a; int b; };
-/// \endcode
-/// The matcher:
+/// Given
/// \code
-/// cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
-/// has(fieldDecl(hasName("b")).bind("v"))))
+/// void f(int a, int b);
/// \endcode
-/// will generate two results binding "v", the first of which binds
-/// the field declaration of \c a, the second the field declaration of
-/// \c b.
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{functionDecl(hasAnyParameter(
+/// eachOf(parmVarDecl(hasName("a")).bind("v"),
+/// parmVarDecl(hasName("b")).bind("v"))))}
+/// matches \match{void f(int a, int b)},
+/// with \matcher{type=sub$parmVarDecl(hasName("a"))} matching \match{sub=v$a}
+/// for one match,
+/// and with \matcher{type=sub$parmVarDecl(hasName("b"))} matching
+/// \match{sub=v$b} for the other match.
///
/// Usable as: Any Matcher
extern const internal::VariadicOperatorMatcherFunc<
@@ -2822,6 +3985,15 @@ extern const internal::VariadicOperatorMatcherFunc<
/// Matches if any of the given matchers matches.
///
/// Usable as: Any Matcher
+///
+/// \code
+/// char v0 = 'a';
+/// int v1 = 1;
+/// float v2 = 2.0;
+/// \endcode
+///
+/// The matcher \matcher{varDecl(anyOf(hasName("v0"), hasType(isInteger())))}
+/// matches \match{char v0 = 'a'} and \match{int v1 = 1}.
extern const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
anyOf;
@@ -2829,6 +4001,14 @@ extern const internal::VariadicOperatorMatcherFunc<
/// Matches if all given matchers match.
///
/// Usable as: Any Matcher
+///
+/// \code
+/// int v0 = 0;
+/// int v1 = 1;
+/// \endcode
+///
+/// The matcher \matcher{varDecl(allOf(hasName("v0"), hasType(isInteger())))}
+/// matches \match{int v0 = 0}.
extern const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
allOf;
@@ -2839,22 +4019,14 @@ extern const internal::VariadicOperatorMatcherFunc<
/// Useful when additional information which may or may not present about a main
/// matching node is desired.
///
-/// For example, in:
-/// \code
-/// class Foo {
-/// int bar;
-/// }
-/// \endcode
-/// The matcher:
+/// Given
/// \code
-/// cxxRecordDecl(
-/// optionally(has(
-/// fieldDecl(hasName("bar")).bind("var")
-/// ))).bind("record")
+/// int a = 0;
+/// int b;
/// \endcode
-/// will produce a result binding for both "record" and "var".
-/// The matcher will produce a "record" binding for even if there is no data
-/// member named "bar" in that class.
+///
+/// The matcher \matcher{varDecl(optionally(hasInitializer(expr())))}
+/// matches \match{int a = 0} and \match{int b}.
///
/// Usable as: Any Matcher
extern const internal::VariadicOperatorMatcherFunc<1, 1> optionally;
@@ -2863,11 +4035,12 @@ extern const internal::VariadicOperatorMatcherFunc<1, 1> optionally;
///
/// Given
/// \code
-/// Foo x = bar;
+/// int x = 42;
/// int y = sizeof(x) + alignof(x);
/// \endcode
-/// unaryExprOrTypeTraitExpr()
-/// matches \c sizeof(x) and \c alignof(x)
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+/// The matcher \matcher{unaryExprOrTypeTraitExpr()}
+/// matches \match{sizeof(x)} and \match{alignof(x)}
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
@@ -2876,26 +4049,26 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
///
/// Given
/// \code
-/// if (true);
-/// for (; true; );
-/// \endcode
-/// with the matcher
-/// \code
-/// mapAnyOf(ifStmt, forStmt).with(
-/// hasCondition(cxxBoolLiteralExpr(equals(true)))
-/// ).bind("trueCond")
-/// \endcode
-/// matches the \c if and the \c for. It is equivalent to:
-/// \code
-/// auto trueCond = hasCondition(cxxBoolLiteralExpr(equals(true)));
-/// anyOf(
-/// ifStmt(trueCond).bind("trueCond"),
-/// forStmt(trueCond).bind("trueCond")
-/// );
+/// void f() {
+/// if (true);
+/// for (; true; );
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+///
+/// The matcher \matcher{stmt(mapAnyOf(ifStmt, forStmt).with(
+/// hasCondition(cxxBoolLiteral(equals(true)))
+/// ))},
+/// which is equivalent to
+/// \matcher{stmt(anyOf(
+/// ifStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond"),
+/// forStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond")
+/// ))},
+/// matches \match{if (true);} and \match{for (; true; );}.
///
/// The with() chain-call accepts zero or more matchers which are combined
/// as-if with allOf() in each of the node matchers.
+///
/// Usable as: Any Matcher
template <typename T, typename... U>
auto mapAnyOf(internal::VariadicDynCastAllOfMatcher<T, U> const &...) {
@@ -2904,34 +4077,23 @@ auto mapAnyOf(internal::VariadicDynCastAllOfMatcher<T, U> const &...) {
/// Matches nodes which can be used with binary operators.
///
-/// The code
-/// \code
-/// var1 != var2;
-/// \endcode
-/// might be represented in the clang AST as a binaryOperator, a
-/// cxxOperatorCallExpr or a cxxRewrittenBinaryOperator, depending on
+/// A comparison of two expressions might be represented in the clang AST as a
+/// \c binaryOperator, a \c cxxOperatorCallExpr or a
+/// \c cxxRewrittenBinaryOperator, depending on
///
/// * whether the types of var1 and var2 are fundamental (binaryOperator) or at
-/// least one is a class type (cxxOperatorCallExpr)
+/// least one is a class type (\c cxxOperatorCallExpr)
/// * whether the code appears in a template declaration, if at least one of the
-/// vars is a dependent-type (binaryOperator)
+/// vars is a dependent-type (\c binaryOperator)
/// * whether the code relies on a rewritten binary operator, such as a
/// spaceship operator or an inverted equality operator
-/// (cxxRewrittenBinaryOperator)
+/// (\c cxxRewrittenBinaryOperator)
///
/// This matcher elides details in places where the matchers for the nodes are
/// compatible.
///
/// Given
/// \code
-/// binaryOperation(
-/// hasOperatorName("!="),
-/// hasLHS(expr().bind("lhs")),
-/// hasRHS(expr().bind("rhs"))
-/// )
-/// \endcode
-/// matches each use of "!=" in:
-/// \code
/// struct S{
/// bool operator!=(const S&) const;
/// };
@@ -2945,25 +4107,28 @@ auto mapAnyOf(internal::VariadicDynCastAllOfMatcher<T, U> const &...) {
/// template<typename T>
/// void templ()
/// {
-/// 1 != 2;
+/// 3 != 4;
/// T() != S();
/// }
/// struct HasOpEq
/// {
-/// bool operator==(const HasOpEq &) const;
+/// friend bool
+/// operator==(const HasOpEq &, const HasOpEq&) noexcept = default;
/// };
///
/// void inverse()
/// {
-/// HasOpEq s1;
-/// HasOpEq s2;
-/// if (s1 != s2)
+/// HasOpEq e1;
+/// HasOpEq e2;
+/// if (e1 != e2)
/// return;
/// }
///
/// struct HasSpaceship
/// {
-/// bool operator<=>(const HasOpEq &) const;
+/// friend bool
+/// operator<=>(const HasSpaceship &,
+/// const HasSpaceship&) noexcept = default;
/// };
///
/// void use_spaceship()
@@ -2974,18 +4139,27 @@ auto mapAnyOf(internal::VariadicDynCastAllOfMatcher<T, U> const &...) {
/// return;
/// }
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++20-or-later}
+///
+/// The matcher \matcher{binaryOperation(
+/// hasOperatorName("!="),
+/// hasLHS(expr().bind("lhs")),
+/// hasRHS(expr().bind("rhs"))
+/// )}
+/// matches \match{1 != 2}, \match{S() != S()}, \match{3 != 4},
+/// \match{T() != S()}, \match{e1 != e2} and \match{s1 != s2}.
extern const internal::MapAnyOfMatcher<BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator>
binaryOperation;
/// Matches function calls and constructor calls
///
-/// Because CallExpr and CXXConstructExpr do not share a common
+/// Because \c CallExpr and \c CXXConstructExpr do not share a common
/// base class with API accessing arguments etc, AST Matchers for code
/// which should match both are typically duplicated. This matcher
/// removes the need for duplication.
///
-/// Given code
+/// Given
/// \code
/// struct ConstructorTakesInt
/// {
@@ -3006,12 +4180,12 @@ extern const internal::MapAnyOfMatcher<BinaryOperator, CXXOperatorCallExpr,
/// ConstructorTakesInt cti(42);
/// }
/// \endcode
+/// \compile_args{-std=c++}
///
/// The matcher
-/// \code
-/// invocation(hasArgument(0, integerLiteral(equals(42))))
-/// \endcode
-/// matches the expression in both doCall and doConstruct
+/// \matcher{expr(invocation(hasArgument(0, integerLiteral(equals(42)))))}
+/// matches the expressions \match{callTakesInt(42)}
+/// and \match{cti(42)}.
extern const internal::MapAnyOfMatcher<CallExpr, CXXConstructExpr> invocation;
/// Matches unary expressions that have a specific type of argument.
@@ -3020,8 +4194,10 @@ extern const internal::MapAnyOfMatcher<CallExpr, CXXConstructExpr> invocation;
/// \code
/// int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
/// \endcode
-/// unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
-/// matches \c sizeof(a) and \c alignof(c)
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+/// The matcher
+/// \matcher{unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")))}
+/// matches \match{sizeof(a)} and \match{alignof(c)}
AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType,
internal::Matcher<QualType>, InnerMatcher) {
const QualType ArgumentType = Node.getTypeOfArgument();
@@ -3033,10 +4209,11 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType,
/// Given
/// \code
/// int x;
-/// int s = sizeof(x) + alignof(x)
+/// int s = sizeof(x) + alignof(x);
/// \endcode
-/// unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
-/// matches \c sizeof(x)
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+/// The matcher \matcher{unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))}
+/// matches \match{sizeof(x)}
///
/// If the matcher is use from clang-query, UnaryExprOrTypeTrait parameter
/// should be passed as a quoted string. e.g., ofKind("UETT_SizeOf").
@@ -3046,8 +4223,17 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) {
/// Same as unaryExprOrTypeTraitExpr, but only matching
/// alignof.
-inline internal::BindableMatcher<Stmt> alignOfExpr(
- const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
+///
+/// Given
+/// \code
+/// int align = alignof(int);
+/// \endcode
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+///
+/// The matcher \matcher{alignOfExpr(expr())}
+/// matches \match{alignof(int)}.
+inline internal::BindableMatcher<Stmt>
+alignOfExpr(const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
return stmt(unaryExprOrTypeTraitExpr(
allOf(anyOf(ofKind(UETT_AlignOf), ofKind(UETT_PreferredAlignOf)),
InnerMatcher)));
@@ -3055,6 +4241,15 @@ inline internal::BindableMatcher<Stmt> alignOfExpr(
/// Same as unaryExprOrTypeTraitExpr, but only matching
/// sizeof.
+///
+/// Given
+/// \code
+/// struct S { double x; double y; };
+/// int size = sizeof(struct S);
+/// \endcode
+///
+/// The matcher \matcher{sizeOfExpr(expr())}
+/// matches \match{sizeof(struct S)}.
inline internal::BindableMatcher<Stmt> sizeOfExpr(
const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
return stmt(unaryExprOrTypeTraitExpr(
@@ -3067,15 +4262,26 @@ inline internal::BindableMatcher<Stmt> sizeOfExpr(
/// with '<enclosing>::'.
/// Does not match typedefs of an underlying type with the given name.
///
-/// Example matches X (Name == "X")
+/// Given
/// \code
/// class X;
/// \endcode
+/// \compile_args{-std=c++}
///
-/// Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
+/// The matcher \matcher{namedDecl(hasName("X"))}
+/// matches \match{class X}.
+///
+/// Given
/// \code
/// namespace a { namespace b { class X; } }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matchers \matcher{namedDecl(hasName("::a::b::X"))},
+/// \matcher{namedDecl(hasName("a::b::X"))},
+/// \matcher{namedDecl(hasName("b::X"))} and
+/// \matcher{namedDecl(hasName("X"))}
+/// match \match{class X}.
inline internal::Matcher<NamedDecl> hasName(StringRef Name) {
return internal::Matcher<NamedDecl>(
new internal::HasNameMatcher({std::string(Name)}));
@@ -3084,13 +4290,17 @@ inline internal::Matcher<NamedDecl> hasName(StringRef Name) {
/// Matches NamedDecl nodes that have any of the specified names.
///
/// This matcher is only provided as a performance optimization of hasName.
+///
+/// Given
/// \code
-/// hasAnyName(a, b, c)
-/// \endcode
-/// is equivalent to, but faster than
-/// \code
-/// anyOf(hasName(a), hasName(b), hasName(c))
+/// void f(int a, int b);
/// \endcode
+///
+/// The matcher \matcher{namedDecl(hasAnyName("a", "b"))},
+/// which is equivalent to the matcher
+/// \matcher{namedDecl(hasAnyName("a", "b"))},
+/// matches \match{int a} and \match{int b}, but not
+/// \nomatch{void f(int a, int b)}.
extern const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
internal::hasAnyNameFunc>
hasAnyName;
@@ -3102,15 +4312,14 @@ extern const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
/// prefixing the name with '<enclosing>::'. Does not match typedefs
/// of an underlying type with the given name.
///
-/// Example matches X (regexp == "::X")
-/// \code
-/// class X;
-/// \endcode
-///
-/// Example matches X (regexp is one of "::X", "^foo::.*X", among others)
+/// Given
/// \code
/// namespace foo { namespace bar { class X; } }
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{namedDecl(matchesName("^::foo:.*X"))}
+/// matches \match{class X}.
AST_MATCHER_REGEX(NamedDecl, matchesName, RegExp) {
std::string FullNameString = "::" + Node.getQualifiedNameAsString();
return RegExp->match(FullNameString);
@@ -3121,18 +4330,21 @@ AST_MATCHER_REGEX(NamedDecl, matchesName, RegExp) {
/// Matches overloaded operator names specified in strings without the
/// "operator" prefix: e.g. "<<".
///
-/// Given:
+/// Given
/// \code
-/// class A { int operator*(); };
+/// struct A { int operator*(); };
/// const A &operator<<(const A &a, const A &b);
-/// A a;
-/// a << a; // <-- This matches
+/// void f(A a) {
+/// a << a; // <-- This matches
+/// }
/// \endcode
+/// \compile_args{-std=c++}
///
-/// \c cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
-/// specified line and
-/// \c cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
-/// matches the declaration of \c A.
+/// The matcher \matcher{cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))}
+/// matches \match{a << a}.
+/// The matcher
+/// \matcher{cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))}
+/// matches \match{struct A { int operator*(); }}.
///
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl>
inline internal::PolymorphicMatcher<
@@ -3152,6 +4364,32 @@ hasOverloadedOperatorName(StringRef Name) {
/// "operator" prefix: e.g. "<<".
///
/// hasAnyOverloadedOperatorName("+", "-")
+///
+/// Given
+/// \code
+/// struct Point { double x; double y; };
+/// Point operator+(const Point&, const Point&);
+/// Point operator-(const Point&, const Point&);
+///
+/// Point sub(Point a, Point b) {
+/// return b - a;
+/// }
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{functionDecl(hasAnyOverloadedOperatorName("+", "-"))},
+/// which is equivalent to
+/// \matcher{functionDecl(anyOf(hasAnyOverloadedOperatorName("+"),
+/// hasOverloadedOperatorName("-")))},
+/// matches \match{Point operator+(const Point&, const Point&)} and
+/// \match{Point operator-(const Point&, const Point&)}.
+/// The matcher
+/// \matcher{cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-"))},
+/// which is equivalent to
+/// \matcher{cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"),
+/// hasOverloadedOperatorName("-")))},
+/// matches \match{b - a}.
+///
/// Is equivalent to
/// anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-"))
extern const internal::VariadicFunction<
@@ -3181,7 +4419,9 @@ extern const internal::VariadicFunction<
/// s.mem();
/// }
/// \endcode
-/// \c cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()`
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxDependentScopeMemberExpr(hasMemberName("mem"))}
+/// matches \match{s.mem}.
AST_MATCHER_P(CXXDependentScopeMemberExpr, hasMemberName, std::string, N) {
return Node.getMember().getAsString() == N;
}
@@ -3207,19 +4447,20 @@ AST_MATCHER_P(CXXDependentScopeMemberExpr, hasMemberName, std::string, N) {
/// s.mem();
/// }
/// \endcode
-/// The matcher
-/// @code
-/// \c cxxDependentScopeMemberExpr(
-/// hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxDependentScopeMemberExpr(
+/// hasObjectExpression(declRefExpr(hasType(
+/// elaboratedType(namesType(templateSpecializationType(
/// hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has(
/// cxxMethodDecl(hasName("mem")).bind("templMem")
/// )))))
-/// )))),
+/// )))
+/// ))),
/// memberHasSameNameAsBoundNode("templMem")
-/// )
-/// @endcode
-/// first matches and binds the @c mem member of the @c S template, then
-/// compares its name to the usage in @c s.mem() in the @c x function template
+/// )}
+/// matches \match{s.mem}, with the inner matcher
+/// \matcher{type=sub$cxxMethodDecl(hasName("mem"))} matching
+/// \match{sub=templMem$void mem()} of the \c S template.
AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,
std::string, BindingID) {
auto MemberName = Node.getMember().getAsString();
@@ -3244,26 +4485,33 @@ AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,
///
/// Example matches Y, Z, C (Base == hasName("X"))
/// \code
-/// class X;
+/// class X {};
/// class Y : public X {}; // directly derived
/// class Z : public Y {}; // indirectly derived
/// typedef X A;
/// typedef A B;
/// class C : public B {}; // derived from a typedef of X
-/// \endcode
///
-/// In the following example, Bar matches isDerivedFrom(hasName("X")):
-/// \code
-/// class Foo;
-/// typedef Foo X;
-/// class Bar : public Foo {}; // derived from a type that X is a typedef of
+/// class Foo {};
+/// typedef Foo Alias;
+/// class Bar : public Alias {};
+/// // derived from a type that Alias is a typedef of Foo
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxRecordDecl(isDerivedFrom(hasName("X")))}
+/// matches \match{class Y : public X {}}, \match{class Z : public Y {}}
+/// and \match{class C : public B {}}.
+///
+/// The matcher \matcher{cxxRecordDecl(isDerivedFrom(hasName("Foo")))}
+/// matches \match{class Bar : public Alias {}}.
///
/// In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
/// \code
/// @interface NSObject @end
/// @interface Bar : NSObject @end
/// \endcode
+/// \compile_args{-ObjC}
///
/// Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
AST_POLYMORPHIC_MATCHER_P(
@@ -3281,6 +4529,44 @@ AST_POLYMORPHIC_MATCHER_P(
}
/// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
+///
+/// Matches C++ classes that are directly or indirectly derived from a class
+/// matching \c Base, or Objective-C classes that directly or indirectly
+/// subclass a class matching \c Base.
+///
+/// Note that a class is not considered to be derived from itself.
+///
+/// Example matches Y, Z, C (Base == hasName("X"))
+/// \code
+/// class X {};
+/// class Y : public X {}; // directly derived
+/// class Z : public Y {}; // indirectly derived
+/// typedef X A;
+/// typedef A B;
+/// class C : public B {}; // derived from a typedef of X
+///
+/// class Foo {};
+/// typedef Foo Alias;
+/// class Bar : public Alias {}; // derived from Alias, which is a
+/// // typedef of Foo
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxRecordDecl(isDerivedFrom("X"))}
+/// matches \match{class Y : public X {}}, \match{class Z : public Y {}}
+/// and \match{class C : public B {}}.
+///
+/// The matcher \matcher{cxxRecordDecl(isDerivedFrom("Foo"))}
+/// matches \match{class Bar : public Alias {}}.
+///
+/// In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+/// \code
+/// @interface NSObject @end
+/// @interface Bar : NSObject @end
+/// \endcode
+/// \compile_args{-ObjC}
+///
+/// Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
isDerivedFrom,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
@@ -3300,17 +4586,21 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matches C++ classes that have a direct or indirect base matching \p
/// BaseSpecMatcher.
///
-/// Example:
-/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
+/// Given
/// \code
-/// class Foo;
+/// class Foo {};
/// class Bar : Foo {};
/// class Baz : Bar {};
-/// class SpecialBase;
+/// class SpecialBase {};
/// class Proxy : SpecialBase {}; // matches Proxy
/// class IndirectlyDerived : Proxy {}; //matches IndirectlyDerived
/// \endcode
+/// \compile_args{-std=c++}
///
+/// The matcher
+/// \matcher{cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))}
+/// matches \match{class Proxy : SpecialBase {}} and
+/// \match{class IndirectlyDerived : Proxy {}}.
// FIXME: Refactor this and isDerivedFrom to reuse implementation.
AST_MATCHER_P(CXXRecordDecl, hasAnyBase, internal::Matcher<CXXBaseSpecifier>,
BaseSpecMatcher) {
@@ -3319,16 +4609,19 @@ AST_MATCHER_P(CXXRecordDecl, hasAnyBase, internal::Matcher<CXXBaseSpecifier>,
/// Matches C++ classes that have a direct base matching \p BaseSpecMatcher.
///
-/// Example:
-/// matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
+/// Given
/// \code
-/// class Foo;
+/// class Foo {};
/// class Bar : Foo {};
/// class Baz : Bar {};
-/// class SpecialBase;
+/// class SpecialBase {};
/// class Proxy : SpecialBase {}; // matches Proxy
/// class IndirectlyDerived : Proxy {}; // doesn't match
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))}
+/// matches \match{class Proxy : SpecialBase {}}.
AST_MATCHER_P(CXXRecordDecl, hasDirectBase, internal::Matcher<CXXBaseSpecifier>,
BaseSpecMatcher) {
return Node.hasDefinition() &&
@@ -3339,6 +4632,22 @@ AST_MATCHER_P(CXXRecordDecl, hasDirectBase, internal::Matcher<CXXBaseSpecifier>,
/// Similar to \c isDerivedFrom(), but also matches classes that directly
/// match \c Base.
+///
+/// Given
+/// \code
+/// class X {};
+/// class Y : public X {}; // directly derived
+/// class Z : public Y {}; // indirectly derived
+/// typedef X A;
+/// typedef A B;
+/// class C : public B {}; // derived from a typedef of X
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+/// isDefinition())}
+/// matches \match{class X {}}, \match{class Y : public X {}},
+/// \match{class Z : public Y {}} and \match{class C : public B {}}.
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
isSameOrDerivedFrom,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
@@ -3352,8 +4661,25 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
return Matcher<ObjCInterfaceDecl>(M).matches(*InterfaceDecl, Finder, Builder);
}
+/// Similar to \c isDerivedFrom(), but also matches classes that directly
+/// match \c Base.
/// Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
+///
+/// Given
+/// \code
+/// class X {};
+/// class Y : public X {}; // directly derived
+/// class Z : public Y {}; // indirectly derived
+/// typedef X A;
+/// typedef A B;
+/// class C : public B {}; // derived from a typedef of X
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())}
+/// matches \match{class X {}}, \match{class Y : public X {}},
+/// \match{class Z : public Y {}} and \match{class C : public B {}}.
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
isSameOrDerivedFrom,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
@@ -3375,22 +4701,30 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
///
/// Note that a class is not considered to be derived from itself.
///
-/// Example matches Y, C (Base == hasName("X"))
+/// Given
/// \code
-/// class X;
+/// class X {};
/// class Y : public X {}; // directly derived
/// class Z : public Y {}; // indirectly derived
/// typedef X A;
/// typedef A B;
/// class C : public B {}; // derived from a typedef of X
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X"))))}
+/// matches \match{class Y : public X {}} and \match{class C : public B {}}
+/// (Base == hasName("X").
///
/// In the following example, Bar matches isDerivedFrom(hasName("X")):
/// \code
-/// class Foo;
+/// class Foo {};
/// typedef Foo X;
/// class Bar : public Foo {}; // derived from a type that X is a typedef of
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(isDerivedFrom(hasName("X")))}
+/// matches \match{class Bar : public Foo {}}.
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
isDirectlyDerivedFrom,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
@@ -3406,6 +4740,18 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
}
/// Overloaded method as shortcut for \c isDirectlyDerivedFrom(hasName(...)).
+///
+/// Given
+/// \code
+/// struct Base {};
+/// struct DirectlyDerived : public Base {};
+/// struct IndirectlyDerived : public DirectlyDerived {};
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{cxxRecordDecl(isDirectlyDerivedFrom("Base"))}
+/// matches \match{struct DirectlyDerived : public Base {}}, but not
+/// \nomatch{struct IndirectlyDerived : public DirectlyDerived {}}.
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
isDirectlyDerivedFrom,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
@@ -3423,14 +4769,16 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matches the first method of a class or struct that satisfies \c
/// InnerMatcher.
///
-/// Given:
+/// Given
/// \code
/// class A { void func(); };
/// class B { void member(); };
/// \endcode
+/// \compile_args{-std=c++}
///
-/// \c cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
-/// \c A but not \c B.
+/// The matcher \matcher{cxxRecordDecl(hasMethod(hasName("func")))}
+/// matches the declaration of \match{class A { void func(); }}
+/// but does not match \nomatch{class B { void member(); }}
AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
InnerMatcher) {
BoundNodesTreeBuilder Result(*Builder);
@@ -3447,13 +4795,14 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
/// Matches the generated class of lambda expressions.
///
-/// Given:
+/// Given
/// \code
/// auto x = []{};
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c cxxRecordDecl(isLambda()) matches the implicit class declaration of
-/// \c decltype(x)
+/// The matcher \matcher{varDecl(hasType(cxxRecordDecl(isLambda())))}
+/// matches \match{auto x = []{}}.
AST_MATCHER(CXXRecordDecl, isLambda) {
return Node.isLambda();
}
@@ -3461,33 +4810,53 @@ AST_MATCHER(CXXRecordDecl, isLambda) {
/// Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
-/// Example matches X, Y
-/// (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
+/// Given
/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class Y { class X {}; };
/// class Z { class Y { class X {}; }; }; // Does not match Z.
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(has(cxxRecordDecl(hasName("X"))))}
+/// matches \match{count=3$class X {}} three times for the definitions of \c X
+/// that contain the implicit class declarations of \c X ,
+/// and \match{count=2$class Y { class X {}; }} two times for the two
diff erent
+/// definitions of \c Y that contain \c X .
///
/// ChildT must be an AST base type.
///
/// Usable as: Any Matcher
/// Note that has is direct matcher, so it also matches things like implicit
/// casts and paren casts. If you are matching with expr then you should
-/// probably consider using ignoringParenImpCasts like:
-/// has(ignoringParenImpCasts(expr())).
+/// probably consider using ignoringParenImpCasts:
+///
+/// Given
+/// \code
+/// int x =0;
+/// double y = static_cast<double>(x);
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxStaticCastExpr(has(ignoringParenImpCasts(declRefExpr())))}.
+/// matches \match{static_cast<double>(x)}
extern const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> has;
/// Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
///
-/// Example matches X, Y, Z
-/// (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
+/// Given
/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class Y { class X {}; };
/// class Z { class Y { class X {}; }; };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X"))))}
+/// matches \match{count=3$class X {}} three times for the definitions of \c X
+/// that contain the implicit class declarations of \c X ,
+/// \match{count=2$class Y { class X {}; }} two times for the declaration of
+/// \c X they contain, and \match{class Z { class Y { class X {}; }; }}.
///
/// DescendantT must be an AST base type.
///
@@ -3499,19 +4868,24 @@ extern const internal::ArgumentAdaptingMatcherFunc<
/// Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
-/// Example matches X, Y, Y::X, Z::Y, Z::Y::X
-/// (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
+/// Given
/// \code
/// class X {};
/// class Y { class X {}; }; // Matches Y, because Y::X is a class of name X
/// // inside Y.
/// class Z { class Y { class X {}; }; }; // Does not match Z.
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(forEach(cxxRecordDecl(hasName("X"))))}
+/// matches \match{type=typestr$class X},
+/// \match{type=typestr$class Y},
+/// \match{type=typestr$class Y::X},
+/// \match{type=typestr$class Z::Y::X} and \match{type=typestr$class Z::Y}
///
/// ChildT must be an AST base type.
///
/// As opposed to 'has', 'forEach' will cause a match for each result that
-/// matches instead of only on the first one.
+/// matches instead of only on the first one.
///
/// Usable as: Any Matcher
extern const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher>
@@ -3520,14 +4894,21 @@ extern const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher>
/// Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
///
-/// Example matches X, A, A::X, B, B::C, B::C::X
-/// (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
+/// Given
/// \code
/// class X {};
/// class A { class X {}; }; // Matches A, because A::X is a class of name
/// // X inside A.
/// class B { class C { class X {}; }; };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X"))))}
+/// matches \match{count=3$class X {}} three times, once for each of the
+/// declared classes \c X and their implicit class declaration,
+/// \match{class A { class X {}; }},
+/// \match{class B { class C { class X {}; }; }} and
+/// \match{class C { class X {}; }}.
///
/// DescendantT must be an AST base type.
///
@@ -3535,13 +4916,63 @@ extern const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher>
/// each result that matches instead of only on the first one.
///
/// Note: Recursively combined ForEachDescendant can cause many matches:
-/// cxxRecordDecl(forEachDescendant(cxxRecordDecl(
-/// forEachDescendant(cxxRecordDecl())
-/// )))
-/// will match 10 times (plus injected class name matches) on:
/// \code
-/// class A { class B { class C { class D { class E {}; }; }; }; };
+/// struct A {
+/// struct B {
+/// struct C {};
+/// struct D {};
+/// };
+/// };
+///
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(forEachDescendant(cxxRecordDecl(
+/// forEachDescendant(cxxRecordDecl().bind("inner"))
+/// ).bind("middle")))}
+/// will match 9 times:
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$B} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$B} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$C} in the middle and the definition of
+/// \match{sub=inner;type=name$B} as the innermost \c cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$C} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$B} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$B} in the middle and the definition of
+/// \match{sub=inner;type=name$D} as the innermost \c cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$B} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$D} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$C} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$C} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$A} with the definition of
+/// \match{sub=middle;type=name$D} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$D} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$B} with the definition of
+/// \match{sub=middle;type=name$C} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$C} as the innermost \c
+/// cxxRecordDecl.
+///
+/// It matches the definition of \match{type=name$B} with the definition of
+/// \match{sub=middle;type=name$D} in the middle and the implicit class
+/// declaration of \match{sub=inner;type=name$D} as the innermost \c
+/// cxxRecordDecl.
///
/// Usable as: Any Matcher
extern const internal::ArgumentAdaptingMatcherFunc<
@@ -3556,12 +4987,14 @@ extern const internal::ArgumentAdaptingMatcherFunc<
/// \code
/// class A { class B {}; class C {}; };
/// \endcode
-/// The matcher:
-/// \code
-/// cxxRecordDecl(hasName("::A"),
-/// findAll(cxxRecordDecl(isDefinition()).bind("m")))
-/// \endcode
-/// will generate results for \c A, \c B and \c C.
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasName("::A"),
+/// findAll(cxxRecordDecl(isDefinition()).bind("m")))}
+/// matches \match{count=3$class A { class B {}; class C {}; }} three times,
+/// with \matcher{type=sub$cxxRecordDecl(isDefinition()).bind("m")}
+/// matching \match{type=name;sub=m$A},
+/// \match{type=name;sub=m$B} and \match{type=name;sub=m$C}.
///
/// Usable as: Any Matcher
template <typename T>
@@ -3576,7 +5009,9 @@ internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) {
/// \code
/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
/// \endcode
-/// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{compoundStmt(hasParent(ifStmt()))}
+/// matches \match{{ int x = 43; }}
///
/// Usable as: Any Matcher
extern const internal::ArgumentAdaptingMatcherFunc<
@@ -3593,7 +5028,10 @@ extern const internal::ArgumentAdaptingMatcherFunc<
/// void f() { if (true) { int x = 42; } }
/// void g() { for (;;) { int x = 43; } }
/// \endcode
-/// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43.
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{expr(integerLiteral(hasAncestor(ifStmt())))}
+/// matches \match{42}
+/// but does not match \nomatch{43}
///
/// Usable as: Any Matcher
extern const internal::ArgumentAdaptingMatcherFunc<
@@ -3604,17 +5042,20 @@ extern const internal::ArgumentAdaptingMatcherFunc<
/// Matches if the provided matcher does not match.
///
-/// Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
+/// Given
/// \code
-/// class X {};
-/// class Y {};
+/// int x;
+/// int y = 0;
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{varDecl(unless(hasInitializer(expr())))}
+/// matches \match{int x}, but not \nomatch{int y = 0}.
///
/// Usable as: Any Matcher
extern const internal::VariadicOperatorMatcherFunc<1, 1> unless;
/// Matches a node if the declaration associated with that node
-/// matches the given matcher.
+/// matches the given matcher.
///
/// The associated declaration is:
/// - for type nodes, the declaration of the underlying type
@@ -3624,21 +5065,27 @@ extern const internal::VariadicOperatorMatcherFunc<1, 1> unless;
/// - for CXXNewExpr, the declaration of the operator new
/// - for ObjCIvarExpr, the declaration of the ivar
///
-/// For type nodes, hasDeclaration will generally match the declaration of the
-/// sugared type. Given
+/// Given
/// \code
/// class X {};
/// typedef X Y;
/// Y y;
/// \endcode
-/// in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
-/// typedefDecl. A common use case is to match the underlying, desugared type.
+/// \compile_args{-std=c++}
+/// For type nodes, hasDeclaration will generally match the declaration of the
+/// sugared type, i.e., the matcher
+/// \matcher{varDecl(hasType(qualType(hasDeclaration(decl().bind("d")))))},
+/// matches \match{Y y}, with
+/// the matcher \matcher{type=sub$decl()} matching
+/// \match{sub=d$typedef X Y;}.
+/// A common use case is to match the underlying, desugared type.
/// This can be achieved by using the hasUnqualifiedDesugaredType matcher:
-/// \code
-/// varDecl(hasType(hasUnqualifiedDesugaredType(
-/// recordType(hasDeclaration(decl())))))
-/// \endcode
-/// In this matcher, the decl will match the CXXRecordDecl of class X.
+/// \matcher{varDecl(hasType(hasUnqualifiedDesugaredType(
+/// recordType(hasDeclaration(decl().bind("d"))))))}
+/// matches \match{Y y}.
+/// In this matcher, the matcher \matcher{type=sub$decl()} will match the
+/// CXXRecordDecl
+/// \match{sub=d$class X {};}.
///
/// Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>,
/// Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>,
@@ -3665,9 +5112,10 @@ hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
/// namespace N { template<class T> void f(T t); }
/// template <class T> void g() { using N::f; f(T()); }
/// \endcode
-/// \c unresolvedLookupExpr(hasAnyDeclaration(
-/// namedDecl(hasUnderlyingDecl(hasName("::N::f")))))
-/// matches the use of \c f in \c g() .
+/// \compile_args{-fno-delayed-template-parsing;-std=c++11-or-later}
+/// The matcher \matcher{unresolvedLookupExpr(hasAnyDeclaration(
+/// namedDecl(hasUnderlyingDecl(hasName("::N::f")))))}
+/// matches \match{f} in \c g().
AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher<NamedDecl>,
InnerMatcher) {
const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
@@ -3686,12 +5134,15 @@ AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher<NamedDecl>,
/// class X : public Y {};
/// void z(Y y, X x) { y.m(); (g()).m(); x.m(); }
/// \endcode
-/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))
-/// matches `y.m()` and `(g()).m()`.
-/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))))
-/// matches `x.m()`.
-/// cxxMemberCallExpr(on(callExpr()))
-/// matches `(g()).m()`.
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))}
+/// matches \match{y.m()} and \match{(g()).m()}.
+/// The matcher
+/// \matcher{cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))))}
+/// matches \match{x.m()}.
+/// The matcher \matcher{cxxMemberCallExpr(on(callExpr()))}
+/// matches \match{(g()).m()}.
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
@@ -3702,17 +5153,17 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
InnerMatcher.matches(*ExprNode, Finder, Builder));
}
-
/// Matches on the receiver of an ObjectiveC Message expression.
///
-/// Example
-/// matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
-/// matches the [webView ...] message invocation.
/// \code
/// NSString *webViewJavaScript = ...
/// UIWebView *webView = ...
/// [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objCMessageExpr(hasReceiverType(asString("UIWebView
+/// *")))} matches
+/// \match{[webViewstringByEvaluatingJavaScriptFromString:webViewJavascript];}
AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>,
InnerMatcher) {
const QualType TypeDecl = Node.getReceiverType();
@@ -3721,66 +5172,63 @@ AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>,
/// Returns true when the Objective-C method declaration is a class method.
///
-/// Example
-/// matcher = objcMethodDecl(isClassMethod())
-/// matches
+/// Given
/// \code
/// @interface I + (void)foo; @end
-/// \endcode
-/// but not
-/// \code
/// @interface I - (void)bar; @end
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objcMethodDecl(isClassMethod())}
+/// matches \match{@interface I + (void)foo; @end}
+/// but does not match \nomatch{interface I + (void)foo; @end}
AST_MATCHER(ObjCMethodDecl, isClassMethod) {
return Node.isClassMethod();
}
/// Returns true when the Objective-C method declaration is an instance method.
///
-/// Example
-/// matcher = objcMethodDecl(isInstanceMethod())
-/// matches
+/// Given
/// \code
/// @interface I - (void)bar; @end
-/// \endcode
-/// but not
-/// \code
/// @interface I + (void)foo; @end
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objcMethodDecl(isInstanceMethod())}
+/// matches \match{@interface I - (void)bar; @end}
+/// but does not match \nomatch{@interface I - (void)foo; @end}
+/// \compile_args{-ObjC}
AST_MATCHER(ObjCMethodDecl, isInstanceMethod) {
return Node.isInstanceMethod();
}
/// Returns true when the Objective-C message is sent to a class.
///
-/// Example
-/// matcher = objcMessageExpr(isClassMessage())
-/// matches
+/// Given
/// \code
/// [NSString stringWithFormat:@"format"];
-/// \endcode
-/// but not
-/// \code
/// NSString *x = @"hello";
/// [x containsString:@"h"];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objcMessageExpr(isClassMessage())}
+/// matches \match{[NSString stringWithFormat:@"format"];}
+/// but does not match \nomatch{[[x containsString:@"h"]}
AST_MATCHER(ObjCMessageExpr, isClassMessage) {
return Node.isClassMessage();
}
/// Returns true when the Objective-C message is sent to an instance.
///
-/// Example
-/// matcher = objcMessageExpr(isInstanceMessage())
-/// matches
+/// Given
/// \code
/// NSString *x = @"hello";
/// [x containsString:@"h"];
-/// \endcode
-/// but not
-/// \code
/// [NSString stringWithFormat:@"format"];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objcMessageExpr(isInstanceMessage())}
+/// matches \match{[x containsString:@"h"];}
+/// but does not match \nomatch{[NSString stringWithFormat:@"format"];}
AST_MATCHER(ObjCMessageExpr, isInstanceMessage) {
return Node.isInstanceMessage();
}
@@ -3788,13 +5236,15 @@ AST_MATCHER(ObjCMessageExpr, isInstanceMessage) {
/// Matches if the Objective-C message is sent to an instance,
/// and the inner matcher matches on that instance.
///
-/// For example the method call in
+/// Given
/// \code
/// NSString *x = @"hello";
/// [x containsString:@"h"];
/// \endcode
-/// is matched by
-/// objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))
+/// \compile_args{-ObjC}
+/// The matcher
+/// \matcher{objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))}
+/// matches \match{[x containsString:@"h"];}
AST_MATCHER_P(ObjCMessageExpr, hasReceiver, internal::Matcher<Expr>,
InnerMatcher) {
const Expr *ReceiverNode = Node.getInstanceReceiver();
@@ -3805,12 +5255,14 @@ AST_MATCHER_P(ObjCMessageExpr, hasReceiver, internal::Matcher<Expr>,
/// Matches when BaseName == Selector.getAsString()
///
-/// matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
-/// matches the outer message expr in the code below, but NOT the message
-/// invocation for self.bodyView.
/// \code
/// [self.bodyView loadHTMLString:html baseURL:NULL];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher
+/// \matcher{objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));} matches
+/// the outer message expr in the code below, but NOT the message invocation
+/// for self.bodyView.
AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) {
Selector Sel = Node.getSelector();
return BaseName == Sel.getAsString();
@@ -3819,12 +5271,13 @@ AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) {
/// Matches when at least one of the supplied string equals to the
/// Selector.getAsString()
///
-/// matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
-/// matches both of the expressions below:
/// \code
/// [myObj methodA:argA];
/// [myObj methodB:argB];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objCMessageExpr(hasSelector("methodA:", "methodB:"));}
+/// matches \match{[myObj methodA:argA];} and \match{[myObj methodB:argB];}
extern const internal::VariadicFunction<internal::Matcher<ObjCMessageExpr>,
StringRef,
internal::hasAnySelectorFunc>
@@ -3832,12 +5285,17 @@ extern const internal::VariadicFunction<internal::Matcher<ObjCMessageExpr>,
/// Matches ObjC selectors whose name contains
/// a substring matched by the given RegExp.
-/// matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?"));
-/// matches the outer message expr in the code below, but NOT the message
-/// invocation for self.bodyView.
+///
+/// Given
/// \code
/// [self.bodyView loadHTMLString:html baseURL:NULL];
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher
+/// \matcher{objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?"))}
+/// matches the outer message expr in the code below, but NOT the message
+/// invocation for self.bodyView.
AST_MATCHER_REGEX(ObjCMessageExpr, matchesSelector, RegExp) {
std::string SelectorString = Node.getSelector().getAsString();
return RegExp->match(SelectorString);
@@ -3853,21 +5311,22 @@ AST_MATCHER(ObjCMessageExpr, hasNullSelector) {
/// Matches when the selector is a Unary Selector
///
-/// matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
-/// matches self.bodyView in the code below, but NOT the outer message
-/// invocation of "loadHTMLString:baseURL:".
+/// Given
/// \code
/// [self.bodyView loadHTMLString:html baseURL:NULL];
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{objCMessageExpr(matchesSelector(hasUnarySelector());}
+/// matches \match{self.bodyView}, but does not match the outer message
+/// invocation of "loadHTMLString:baseURL:".
AST_MATCHER(ObjCMessageExpr, hasUnarySelector) {
return Node.getSelector().isUnarySelector();
}
/// Matches when the selector is a keyword selector
///
-/// objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
-/// message expression in
-///
+/// Given
/// \code
/// UIWebView *webView = ...;
/// CGRect bodyFrame = webView.frame;
@@ -3875,21 +5334,25 @@ AST_MATCHER(ObjCMessageExpr, hasUnarySelector) {
/// webView.frame = bodyFrame;
/// // ^---- matches here
/// \endcode
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{objCMessageExpr(hasKeywordSelector())} matches the
+/// generated setFrame message expression in
AST_MATCHER(ObjCMessageExpr, hasKeywordSelector) {
return Node.getSelector().isKeywordSelector();
}
/// Matches when the selector has the specified number of arguments
///
-/// matcher = objCMessageExpr(numSelectorArgs(0));
-/// matches self.bodyView in the code below
-///
-/// matcher = objCMessageExpr(numSelectorArgs(2));
-/// matches the invocation of "loadHTMLString:baseURL:" but not that
-/// of self.bodyView
/// \code
/// [self.bodyView loadHTMLString:html baseURL:NULL];
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objCMessageExpr(numSelectorArgs(0))}
+/// matches \match{self.bodyView}.
+/// The matcher \matcher{objCMessageExpr(numSelectorArgs(2))}
+/// matches the invocation of \match{loadHTMLString:baseURL:}
+/// but does not match \nomatch{self.bodyView}
AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) {
return Node.getSelector().getNumArgs() == N;
}
@@ -3901,13 +5364,21 @@ AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) {
/// class Y { void x() { this->x(); x(); Y y; y.x(); } };
/// void f() { f(); }
/// \endcode
-/// callExpr(callee(expr()))
-/// matches this->x(), x(), y.x(), f()
-/// with callee(...)
-/// matching this->x, x, y.x, f respectively
+/// \compile_args{-std=c++}
+/// The matcher \matcher{callExpr(callee(expr().bind("callee")))}
+/// matches \match{this->x()}, \match{x()}, \match{y.x()}, \match{f()}
+/// with \matcher{type=sub$expr()} inside of \c callee
+/// matching \match{sub=callee$this->x}, \match{sub=callee$x},
+/// \match{sub=callee$y.x}, \match{sub=callee$f} respectively
///
/// Given
/// \code
+/// struct Dummy {};
+/// // makes sure there is a callee, otherwise there would be no callee,
+/// // just a builtin operator
+/// Dummy operator+(Dummy, Dummy);
+/// // not defining a '*' operator
+///
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
@@ -3918,10 +5389,14 @@ AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) {
/// return (args * ... * 1);
/// }
/// \endcode
-/// cxxFoldExpr(callee(expr()))
-/// matches (args * ... * 1)
-/// with callee(...)
-/// matching *
+/// \compile_args{-std=c++17-or-later}
+/// The matcher \matcher{cxxFoldExpr(callee(expr().bind("op")))}
+/// matches \match{(0 + ... + args)}
+/// with \matcher{type=sub$callee(...)} matching \match{sub=op$*},
+/// but does not match \nomatch{(args * ... * 1)}.
+/// A \c CXXFoldExpr only has an \c UnresolvedLookupExpr as a callee.
+/// When there are no define operators that could be used instead of builtin
+/// ones, then there will be no \c callee .
///
/// Note: Callee cannot take the more general internal::Matcher<Expr>
/// because this introduces ambiguous overloads with calls to Callee taking a
@@ -3940,16 +5415,16 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(callee,
/// given matcher; or 2) if the Obj-C message expression's callee's method
/// declaration matches the given matcher.
///
-/// Example matches y.x() (matcher = callExpr(callee(
-/// cxxMethodDecl(hasName("x")))))
+/// Example 1
/// \code
/// class Y { public: void x(); };
/// void z() { Y y; y.x(); }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{callExpr(callee(cxxMethodDecl(hasName("x"))))}
+/// matches \match{y.x()}
///
-/// Example 2. Matches [I foo] with
-/// objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
-///
+/// Example 2
/// \code
/// @interface I: NSObject
/// +(void)foo;
@@ -3957,6 +5432,10 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(callee,
/// ...
/// [I foo]
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher
+/// \matcher{objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))}
+/// matches \match{[I foo]}
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
callee, AST_POLYMORPHIC_SUPPORTED_TYPES(ObjCMessageExpr, CallExpr),
internal::Matcher<Decl>, InnerMatcher, 1) {
@@ -3976,12 +5455,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matches if the expression's or declaration's type matches a type
/// matcher.
///
-/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-/// and U (matcher = typedefDecl(hasType(asString("int")))
-/// and friend class X (matcher = friendDecl(hasType("X"))
-/// and public virtual X (matcher = cxxBaseSpecifier(hasType(
-/// asString("class X")))
+/// Exmaple
/// \code
/// class X {};
/// void y(X &x) { x; X z; }
@@ -3989,6 +5463,19 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// class Y { friend class X; };
/// class Z : public virtual X {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{expr(hasType(cxxRecordDecl(hasName("X"))))}
+/// matches \match{x} and \match{z}.
+/// The matcher \matcher{varDecl(hasType(cxxRecordDecl(hasName("X"))))}
+/// matches \match{X z}
+/// The matcher \matcher{typedefDecl(hasType(asString("int")))}
+/// matches \match{typedef int U}
+/// The matcher \matcher{friendDecl(hasType(asString("class X")))}
+/// matches \match{friend class X}
+/// The matcher \matcher{cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+/// asString("X"))).bind("b")))} matches \match{class Z : public virtual X {}},
+/// with \matcher{type=sub$cxxBaseSpecifier(...)}
+/// matching \match{sub=b$public virtual X}.
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
hasType,
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, TypedefNameDecl,
@@ -4009,24 +5496,34 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
/// declaration of x.
///
-/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-/// and friend class X (matcher = friendDecl(hasType("X"))
-/// and public virtual X (matcher = cxxBaseSpecifier(hasType(
-/// cxxRecordDecl(hasName("X"))))
/// \code
/// class X {};
/// void y(X &x) { x; X z; }
/// class Y { friend class X; };
/// class Z : public virtual X {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{expr(hasType(cxxRecordDecl(hasName("X"))))}
+/// matches \match{x} and \match{z}.
+/// The matcher \matcher{varDecl(hasType(cxxRecordDecl(hasName("X"))))}
+/// matches \match{X z}.
+/// The matcher \matcher{friendDecl(hasType(asString("class X")))}
+/// matches \match{friend class X}.
+/// The matcher \matcher{cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+/// asString("X"))).bind("b")))} matches
+/// \match{class Z : public virtual X {}},
+/// with \matcher{type=sub$cxxBaseSpecifier(...)}
+/// matching \match{sub=b$public virtual X}.
///
-/// Example matches class Derived
-/// (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+/// Given
/// \code
/// class Base {};
/// class Derived : Base {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))}
+/// matches \match{class Derived : Base {}}.
///
/// Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>,
/// Matcher<CXXBaseSpecifier>
@@ -4043,25 +5540,32 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matches if the type location of a node matches the inner matcher.
///
-/// Examples:
+/// Given
/// \code
/// int x;
/// \endcode
-/// declaratorDecl(hasTypeLoc(loc(asString("int"))))
-/// matches int x
+/// The matcher \matcher{declaratorDecl(hasTypeLoc(loc(asString("int"))))}
+/// matches \match{int x}.
///
+/// Given
/// \code
-/// auto x = int(3);
+/// struct point { point(double, double); };
+/// point p = point(1.0, -1.0);
/// \endcode
-/// cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-/// matches int(3)
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))}
+/// matches \match{point(1.0, -1.0)}.
///
+/// Given
/// \code
/// struct Foo { Foo(int, int); };
-/// auto x = Foo(1, 2);
+/// Foo x = Foo(1, 2);
/// \endcode
-/// cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-/// matches Foo(1, 2)
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxTemporaryObjectExpr(hasTypeLoc(
+/// loc(asString("Foo"))))}
+/// matches \match{Foo(1, 2)}.
///
/// Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
/// Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -4094,22 +5598,25 @@ AST_POLYMORPHIC_MATCHER_P(
/// class Y { public: void x(); };
/// void z() { Y* y; y->x(); }
/// \endcode
-/// cxxMemberCallExpr(on(hasType(asString("class Y *"))))
-/// matches y->x()
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMemberCallExpr(on(hasType(asString("Y *"))))}
+/// matches \match{y->x()}
AST_MATCHER_P(QualType, asString, std::string, Name) {
return Name == Node.getAsString();
}
/// Matches if the matched type is a pointer type and the pointee type
-/// matches the specified matcher.
+/// matches the specified matcher.
///
-/// Example matches y->x()
-/// (matcher = cxxMemberCallExpr(on(hasType(pointsTo
-/// cxxRecordDecl(hasName("Y")))))))
+/// Given
/// \code
/// class Y { public: void x(); };
/// void z() { Y *y; y->x(); }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMemberCallExpr(on(hasType(pointsTo(
+/// qualType()))))}
+/// matches \match{y->x()}
AST_MATCHER_P(
QualType, pointsTo, internal::Matcher<QualType>,
InnerMatcher) {
@@ -4117,7 +5624,19 @@ AST_MATCHER_P(
InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
}
+/// Matches if the matched type is a pointer type and the pointee type
+/// matches the specified matcher.
/// Overloaded to match the pointee type's declaration.
+///
+/// Given
+/// \code
+/// class Y { public: void x(); };
+/// void z() { Y *y; y->x(); }
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMemberCallExpr(on(hasType(pointsTo(
+/// cxxRecordDecl(hasName("Y"))))))}
+/// matches \match{y->x()}
AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
InnerMatcher, 1) {
return pointsTo(qualType(hasDeclaration(InnerMatcher)))
@@ -4131,9 +5650,12 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
/// \code
/// class A {};
/// using B = A;
+/// B b;
/// \endcode
-/// The matcher type(hasUnqualifiedDesugaredType(recordType())) matches
-/// both B and A.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{varDecl(hasType(hasUnqualifiedDesugaredType(recordType())))}
+/// matches \match{B b}.
AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>,
InnerMatcher) {
return InnerMatcher.matches(*Node.getUnqualifiedDesugaredType(), Finder,
@@ -4143,8 +5665,7 @@ AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>,
/// Matches if the matched type is a reference type and the referenced
/// type matches the specified matcher.
///
-/// Example matches X &x and const X &y
-/// (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
+/// Given
/// \code
/// class X {
/// void a(X b) {
@@ -4153,24 +5674,29 @@ AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>,
/// }
/// };
/// \endcode
-AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
- InnerMatcher) {
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{varDecl(hasType(references(qualType())))} matches
+/// \match{X &x = b} and \match{const X &y = b}.
+AST_MATCHER_P(QualType, references, internal::Matcher<QualType>, InnerMatcher) {
return (!Node.isNull() && Node->isReferenceType() &&
InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
}
/// Matches QualTypes whose canonical type matches InnerMatcher.
///
-/// Given:
+/// Given
/// \code
/// typedef int &int_ref;
/// int a;
/// int_ref b = a;
/// \endcode
-///
-/// \c varDecl(hasType(qualType(referenceType()))))) will not match the
-/// declaration of b but \c
-/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{varDecl(hasType(qualType(referenceType())))}
+/// does not match \nomatch{int_ref b = a},
+/// but the matcher
+/// \matcher{varDecl(hasType(qualType(hasCanonicalType(referenceType()))))}
+/// does match \match{int_ref b = a}.
AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
InnerMatcher) {
if (Node.isNull())
@@ -4178,7 +5704,23 @@ AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
}
+/// Matches if the matched type is a reference type and the referenced
+/// type matches the specified matcher.
/// Overloaded to match the referenced type's declaration.
+///
+/// Given
+/// \code
+/// class X {
+/// void a(X b) {
+/// X &x = b;
+/// const X &y = b;
+/// }
+/// };
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{varDecl(hasType(references(cxxRecordDecl(hasName("X")))))} matches
+/// \match{X &x = b} and \match{const X &y = b}.
AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
InnerMatcher, 1) {
return references(qualType(hasDeclaration(InnerMatcher)))
@@ -4192,14 +5734,17 @@ AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
/// \code
/// class Y { public: void m(); };
/// Y g();
-/// class X : public Y { void g(); };
+/// class X : public Y { public: void g(); };
/// void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); }
/// \endcode
-/// cxxMemberCallExpr(onImplicitObjectArgument(hasType(
-/// cxxRecordDecl(hasName("Y")))))
-/// matches `y.m()`, `x.m()` and (`g()).m()`, but not `x.g()`).
-/// cxxMemberCallExpr(on(callExpr()))
-/// only matches `(g()).m()` (the parens are ignored).
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMemberCallExpr(onImplicitObjectArgument(hasType(
+/// cxxRecordDecl(hasName("Y")))))}
+/// matches \match{y.m()}, \match{x.m()} and \match{(g()).m()}
+/// but does not match \nomatch{x.g()}.
+/// The matcher \matcher{cxxMemberCallExpr(on(callExpr()))}
+/// only matches \match{(g()).m()}, because the parens are ignored.
+/// FIXME: should they be ignored? (ignored bc of `on`)
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
@@ -4210,21 +5755,20 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
}
/// Matches if the type of the expression's implicit object argument either
-/// matches the InnerMatcher, or is a pointer to a type that matches the
+/// matches the InnerMatcher, or is a pointer to a type that matches the
/// InnerMatcher.
///
/// Given
/// \code
-/// class Y { public: void m(); };
-/// class X : public Y { void g(); };
-/// void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
+/// class Y { public: void m() const; };
+/// class X : public Y { public: void g(); };
+/// void z() { const Y y; y.m(); const Y *p; p->m(); X x; x.m(); x.g(); }
/// \endcode
-/// cxxMemberCallExpr(thisPointerType(hasDeclaration(
-/// cxxRecordDecl(hasName("Y")))))
-/// matches `y.m()`, `p->m()` and `x.m()`.
-/// cxxMemberCallExpr(thisPointerType(hasDeclaration(
-/// cxxRecordDecl(hasName("X")))))
-/// matches `x.g()`.
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxMemberCallExpr(thisPointerType(isConstQualified()))}
+/// matches \match{y.m()}, \match{x.m()} and \match{p->m()},
+/// but not \nomatch{x.g()}.
AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
internal::Matcher<QualType>, InnerMatcher, 0) {
return onImplicitObjectArgument(
@@ -4233,6 +5777,20 @@ AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
}
/// Overloaded to match the type's declaration.
+///
+/// Given
+/// \code
+/// class Y { public: void m(); };
+/// class X : public Y { public: void g(); };
+/// void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMemberCallExpr(thisPointerType(
+/// cxxRecordDecl(hasName("Y"))))}
+/// matches \match{y.m()}, \match{p->m()} and \match{x.m()}.
+/// The matcher \matcher{cxxMemberCallExpr(thisPointerType(
+/// cxxRecordDecl(hasName("X"))))}
+/// matches \match{x.g()}.
AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
internal::Matcher<Decl>, InnerMatcher, 1) {
return onImplicitObjectArgument(
@@ -4243,14 +5801,17 @@ AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
/// Matches a DeclRefExpr that refers to a declaration that matches the
/// specified matcher.
///
-/// Example matches x in if(x)
-/// (matcher = declRefExpr(to(varDecl(hasName("x")))))
+/// Given
/// \code
-/// bool x;
-/// if (x) {}
+/// void foo() {
+/// bool x;
+/// if (x) {}
+/// }
/// \endcode
-AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
- InnerMatcher) {
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{declRefExpr(to(varDecl(hasName("x"))))}
+/// matches \match{x} inside the condition of the if-stmt.
+AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>, InnerMatcher) {
const Decl *DeclNode = Node.getDecl();
return (DeclNode != nullptr &&
InnerMatcher.matches(*DeclNode, Finder, Builder));
@@ -4259,22 +5820,24 @@ AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
/// Matches if a node refers to a declaration through a specific
/// using shadow declaration.
///
-/// Examples:
+/// Given
/// \code
/// namespace a { int f(); }
/// using a::f;
/// int x = f();
/// \endcode
-/// declRefExpr(throughUsingDecl(anything()))
-/// matches \c f
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{declRefExpr(throughUsingDecl(anything()))}
+/// matches \match{f}
///
/// \code
/// namespace a { class X{}; }
/// using a::X;
/// X x;
/// \endcode
-/// typeLoc(loc(usingType(throughUsingDecl(anything()))))
-/// matches \c X
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{typeLoc(loc(usingType(throughUsingDecl(anything()))))}
+/// matches \match{X}
///
/// Usable as: Matcher<DeclRefExpr>, Matcher<UsingType>
AST_POLYMORPHIC_MATCHER_P(throughUsingDecl,
@@ -4299,9 +5862,11 @@ AST_POLYMORPHIC_MATCHER_P(throughUsingDecl,
/// bar(t);
/// }
/// \endcode
-/// unresolvedLookupExpr(hasAnyDeclaration(
-/// functionTemplateDecl(hasName("foo"))))
-/// matches \c foo in \c foo(t); but not \c bar in \c bar(t);
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unresolvedLookupExpr(hasAnyDeclaration(
+/// functionTemplateDecl(hasName("foo"))))}
+/// matches \match{foo} in \c foo(t);
+/// but does not match \nomatch{bar} in \c bar(t);
AST_MATCHER_P(OverloadExpr, hasAnyDeclaration, internal::Matcher<Decl>,
InnerMatcher) {
return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(),
@@ -4313,11 +5878,14 @@ AST_MATCHER_P(OverloadExpr, hasAnyDeclaration, internal::Matcher<Decl>,
///
/// Given
/// \code
-/// int a, b;
-/// int c;
+/// void foo() {
+/// int a, b;
+/// int c;
+/// }
/// \endcode
-/// declStmt(hasSingleDecl(anything()))
-/// matches 'int c;' but not 'int a, b;'.
+/// The matcher \matcher{declStmt(hasSingleDecl(anything()))}
+/// matches \match{int c;}
+/// but does not match \nomatch{int a, b;}
AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) {
if (Node.isSingleDecl()) {
const Decl *FoundDecl = Node.getSingleDecl();
@@ -4329,11 +5897,15 @@ AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) {
/// Matches a variable declaration that has an initializer expression
/// that matches the given matcher.
///
-/// Example matches x (matcher = varDecl(hasInitializer(callExpr())))
+/// Given
/// \code
-/// bool y() { return true; }
-/// bool x = y();
+/// int y() { return 0; }
+/// void foo() {
+/// int x = y();
+/// }
/// \endcode
+/// The matcher \matcher{varDecl(hasInitializer(callExpr()))}
+/// matches \match{int x = y()}
AST_MATCHER_P(
VarDecl, hasInitializer, internal::Matcher<Expr>,
InnerMatcher) {
@@ -4345,10 +5917,13 @@ AST_MATCHER_P(
/// Matches a variable serving as the implicit variable for a lambda init-
/// capture.
///
-/// Example matches x (matcher = varDecl(isInitCapture()))
+/// Given
/// \code
-/// auto f = [x=3]() { return x; };
+/// auto f = [x = 3]() { return x; };
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{varDecl(isInitCapture())}
+/// matches \match{x = 3}.
AST_MATCHER(VarDecl, isInitCapture) { return Node.isInitCapture(); }
/// Matches each lambda capture in a lambda expression.
@@ -4356,14 +5931,19 @@ AST_MATCHER(VarDecl, isInitCapture) { return Node.isInitCapture(); }
/// Given
/// \code
/// int main() {
-/// int x, y;
+/// int x;
+/// int y;
/// float z;
/// auto f = [=]() { return x + y + z; };
/// }
/// \endcode
-/// lambdaExpr(forEachLambdaCapture(
-/// lambdaCapture(capturesVar(varDecl(hasType(isInteger()))))))
-/// will trigger two matches, binding for 'x' and 'y' respectively.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{lambdaExpr(forEachLambdaCapture(
+/// lambdaCapture(capturesVar(
+/// varDecl(hasType(isInteger())).bind("captured")))))}
+/// matches \match{count=2$[=]() { return x + y + z; }} two times,
+/// with \matcher{type=sub$varDecl(hasType(isInteger()))} matching
+/// \match{sub=captured$int x} and \match{sub=captured$int y}.
AST_MATCHER_P(LambdaExpr, forEachLambdaCapture,
internal::Matcher<LambdaCapture>, InnerMatcher) {
BoundNodesTreeBuilder Result;
@@ -4383,7 +5963,7 @@ AST_MATCHER_P(LambdaExpr, forEachLambdaCapture,
/// \brief Matches a static variable with local scope.
///
-/// Example matches y (matcher = varDecl(isStaticLocal()))
+/// Given
/// \code
/// void f() {
/// int x;
@@ -4391,6 +5971,8 @@ AST_MATCHER_P(LambdaExpr, forEachLambdaCapture,
/// }
/// static int z;
/// \endcode
+/// The matcher \matcher{varDecl(isStaticLocal())}
+/// matches \match{static int y}.
AST_MATCHER(VarDecl, isStaticLocal) {
return Node.isStaticLocal();
}
@@ -4398,7 +5980,7 @@ AST_MATCHER(VarDecl, isStaticLocal) {
/// Matches a variable declaration that has function scope and is a
/// non-static local variable.
///
-/// Example matches x (matcher = varDecl(hasLocalStorage())
+/// Given
/// \code
/// void f() {
/// int x;
@@ -4406,13 +5988,15 @@ AST_MATCHER(VarDecl, isStaticLocal) {
/// }
/// int z;
/// \endcode
+/// The matcher \matcher{varDecl(hasLocalStorage())}
+/// matches \match{int x}.
AST_MATCHER(VarDecl, hasLocalStorage) {
return Node.hasLocalStorage();
}
/// Matches a variable declaration that does not have local storage.
///
-/// Example matches y and z (matcher = varDecl(hasGlobalStorage())
+/// Given
/// \code
/// void f() {
/// int x;
@@ -4420,14 +6004,15 @@ AST_MATCHER(VarDecl, hasLocalStorage) {
/// }
/// int z;
/// \endcode
+/// The matcher \matcher{varDecl(hasGlobalStorage())}
+/// matches \match{static int y} and \match{int z}.
AST_MATCHER(VarDecl, hasGlobalStorage) {
return Node.hasGlobalStorage();
}
/// Matches a variable declaration that has automatic storage duration.
///
-/// Example matches x, but not y, z, or a.
-/// (matcher = varDecl(hasAutomaticStorageDuration())
+/// Given
/// \code
/// void f() {
/// int x;
@@ -4436,6 +6021,11 @@ AST_MATCHER(VarDecl, hasGlobalStorage) {
/// }
/// int a;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{varDecl(hasAutomaticStorageDuration())}
+/// matches \match{int x}
+/// but does not match \nomatch{static int y}, \nomatch{thread_local int z} or
+/// \nomatch{int a}
AST_MATCHER(VarDecl, hasAutomaticStorageDuration) {
return Node.getStorageDuration() == SD_Automatic;
}
@@ -4453,17 +6043,18 @@ AST_MATCHER(VarDecl, hasAutomaticStorageDuration) {
/// int a;
/// static int b;
/// extern int c;
-/// varDecl(hasStaticStorageDuration())
-/// matches the function declaration y, a, b and c.
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{varDecl(hasStaticStorageDuration())}
+/// matches \match{static int y}, \match{int a}, \match{static int b} and
+/// \match{extern int c}
AST_MATCHER(VarDecl, hasStaticStorageDuration) {
return Node.getStorageDuration() == SD_Static;
}
/// Matches a variable declaration that has thread storage duration.
///
-/// Example matches z, but not x, z, or a.
-/// (matcher = varDecl(hasThreadStorageDuration())
+/// Given
/// \code
/// void f() {
/// int x;
@@ -4472,6 +6063,10 @@ AST_MATCHER(VarDecl, hasStaticStorageDuration) {
/// }
/// int a;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{varDecl(hasThreadStorageDuration())}
+/// matches \match{thread_local int z}
+/// but does not match \nomatch{int x} or \nomatch{type=name$a}.
AST_MATCHER(VarDecl, hasThreadStorageDuration) {
return Node.getStorageDuration() == SD_Thread;
}
@@ -4479,7 +6074,7 @@ AST_MATCHER(VarDecl, hasThreadStorageDuration) {
/// Matches a variable declaration that is an exception variable from
/// a C++ catch block, or an Objective-C \@catch statement.
///
-/// Example matches x (matcher = varDecl(isExceptionVariable())
+/// Given
/// \code
/// void f(int y) {
/// try {
@@ -4487,6 +6082,9 @@ AST_MATCHER(VarDecl, hasThreadStorageDuration) {
/// }
/// }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{varDecl(isExceptionVariable())}
+/// matches \match{int x}.
AST_MATCHER(VarDecl, isExceptionVariable) {
return Node.isExceptionVariable();
}
@@ -4494,11 +6092,15 @@ AST_MATCHER(VarDecl, isExceptionVariable) {
/// Checks that a call expression or a constructor call expression has
/// a specific number of arguments (including absent default arguments).
///
-/// Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+/// Given
/// \code
/// void f(int x, int y);
-/// f(0, 0);
+/// void foo() {
+/// f(0, 0);
+/// }
/// \endcode
+/// The matcher \matcher{callExpr(argumentCountIs(2))}
+/// matches \match{f(0, 0)}.
AST_POLYMORPHIC_MATCHER_P(argumentCountIs,
AST_POLYMORPHIC_SUPPORTED_TYPES(
CallExpr, CXXConstructExpr,
@@ -4518,14 +6120,17 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs,
/// Checks that a call expression or a constructor call expression has at least
/// the specified number of arguments (including absent default arguments).
///
-/// Example matches f(0, 0) and g(0, 0, 0)
-/// (matcher = callExpr(argumentCountAtLeast(2)))
+/// Given
/// \code
/// void f(int x, int y);
/// void g(int x, int y, int z);
-/// f(0, 0);
-/// g(0, 0, 0);
+/// void foo() {
+/// f(0, 0);
+/// g(0, 0, 0);
+/// }
/// \endcode
+/// The matcher \matcher{callExpr(argumentCountAtLeast(2))}
+/// matches \match{f(0, 0)} and \match{g(0, 0, 0)}
AST_POLYMORPHIC_MATCHER_P(argumentCountAtLeast,
AST_POLYMORPHIC_SUPPORTED_TYPES(
CallExpr, CXXConstructExpr,
@@ -4545,11 +6150,13 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountAtLeast,
/// Matches the n'th argument of a call expression or a constructor
/// call expression.
///
-/// Example matches y in x(y)
-/// (matcher = callExpr(hasArgument(0, declRefExpr())))
+/// Given
/// \code
/// void x(int) { int y; x(y); }
/// \endcode
+/// The matcher \matcher{callExpr(hasArgument(0, declRefExpr().bind("arg")))}
+/// matches \match{x(y)},
+/// with \matcher{type=sub$declRefExpr()} matching \match{sub="arg"$y}.
AST_POLYMORPHIC_MATCHER_P2(hasArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(
CallExpr, CXXConstructExpr,
@@ -4565,10 +6172,7 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument,
/// Matches the operand that does not contain the parameter pack.
///
-/// Example matches `(0 + ... + args)` and `(args * ... * 1)`
-/// (matcher = cxxFoldExpr(hasFoldInit(expr())))
-/// with hasFoldInit(...)
-/// matching `0` and `1` respectively
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4580,6 +6184,12 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument,
/// return (args * ... * 1);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(hasFoldInit(expr().bind("init")))}
+/// matches \match{(0 + ... + args)} and \match{(args * ... * 1)}
+/// with \matcher{type=sub$hasFoldInit(expr().bind("init"))} matching
+/// \match{sub=init$0} and \match{sub=init$1}.
AST_MATCHER_P(CXXFoldExpr, hasFoldInit, internal::Matcher<Expr>, InnerMacher) {
const auto *const Init = Node.getInit();
return Init && InnerMacher.matches(*Init, Finder, Builder);
@@ -4587,10 +6197,7 @@ AST_MATCHER_P(CXXFoldExpr, hasFoldInit, internal::Matcher<Expr>, InnerMacher) {
/// Matches the operand that contains the parameter pack.
///
-/// Example matches `(0 + ... + args)`
-/// (matcher = cxxFoldExpr(hasPattern(expr())))
-/// with hasPattern(...)
-/// matching `args`
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4602,6 +6209,12 @@ AST_MATCHER_P(CXXFoldExpr, hasFoldInit, internal::Matcher<Expr>, InnerMacher) {
/// return (args * ... * 1);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(hasPattern(expr().bind("pattern")))}
+/// matches \match{(0 + ... + args)} and \match{(args * ... * 1)},
+/// with \matcher{type=sub$hasPattern(expr().bind("pattern"))} matching
+/// \match{count=2;sub=pattern$args} two times.
AST_MATCHER_P(CXXFoldExpr, hasPattern, internal::Matcher<Expr>, InnerMacher) {
const Expr *const Pattern = Node.getPattern();
return Pattern && InnerMacher.matches(*Pattern, Finder, Builder);
@@ -4609,8 +6222,7 @@ AST_MATCHER_P(CXXFoldExpr, hasPattern, internal::Matcher<Expr>, InnerMacher) {
/// Matches right-folding fold expressions.
///
-/// Example matches `(args * ... * 1)`
-/// (matcher = cxxFoldExpr(isRightFold()))
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4622,12 +6234,15 @@ AST_MATCHER_P(CXXFoldExpr, hasPattern, internal::Matcher<Expr>, InnerMacher) {
/// return (args * ... * 1);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(isRightFold())}
+/// matches \match{(args * ... * 1)}.
AST_MATCHER(CXXFoldExpr, isRightFold) { return Node.isRightFold(); }
/// Matches left-folding fold expressions.
///
-/// Example matches `(0 + ... + args)`
-/// (matcher = cxxFoldExpr(isLeftFold()))
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4639,13 +6254,16 @@ AST_MATCHER(CXXFoldExpr, isRightFold) { return Node.isRightFold(); }
/// return (args * ... * 1);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(isLeftFold())}
+/// matches \match{(0 + ... + args)}.
AST_MATCHER(CXXFoldExpr, isLeftFold) { return Node.isLeftFold(); }
/// Matches unary fold expressions, i.e. fold expressions without an
/// initializer.
///
-/// Example matches `(args * ...)`
-/// (matcher = cxxFoldExpr(isUnaryFold()))
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4657,12 +6275,15 @@ AST_MATCHER(CXXFoldExpr, isLeftFold) { return Node.isLeftFold(); }
/// return (args * ...);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(isUnaryFold())}
+/// matches \match{(args * ...)}, but not \nomatch{(0 + ... + args)}.
AST_MATCHER(CXXFoldExpr, isUnaryFold) { return Node.getInit() == nullptr; }
/// Matches binary fold expressions, i.e. fold expressions with an initializer.
///
-/// Example matches `(0 + ... + args)`
-/// (matcher = cxxFoldExpr(isBinaryFold()))
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
@@ -4674,32 +6295,42 @@ AST_MATCHER(CXXFoldExpr, isUnaryFold) { return Node.getInit() == nullptr; }
/// return (args * ...);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+///
+/// The matcher \matcher{cxxFoldExpr(isBinaryFold())}
+/// matches \match{(0 + ... + args)}.
AST_MATCHER(CXXFoldExpr, isBinaryFold) { return Node.getInit() != nullptr; }
/// Matches the n'th item of an initializer list expression.
///
-/// Example matches y.
-/// (matcher = initListExpr(hasInit(0, expr())))
+/// Given
/// \code
-/// int x{y}.
+/// int y = 42;
+/// int x{y};
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{initListExpr(hasInit(0, expr()))}
+/// matches \match{{y}}.
AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, internal::Matcher<Expr>,
InnerMatcher) {
return N < Node.getNumInits() &&
- InnerMatcher.matches(*Node.getInit(N), Finder, Builder);
+ InnerMatcher.matches(*Node.getInit(N), Finder, Builder);
}
/// Matches declaration statements that contain a specific number of
/// declarations.
///
-/// Example: Given
+/// Given
/// \code
-/// int a, b;
-/// int c;
-/// int d = 2, e;
+/// void foo() {
+/// int a, b;
+/// int c;
+/// int d = 2, e;
+/// }
/// \endcode
-/// declCountIs(2)
-/// matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+/// The matcher \matcher{declStmt(declCountIs(2))}
+/// matches \match{int a, b;} and \match{int d = 2, e;},
+/// but does not match \nomatch{int c;}
AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) {
return std::distance(Node.decl_begin(), Node.decl_end()) == (ptr
diff _t)N;
}
@@ -4709,20 +6340,21 @@ AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) {
/// Note that this does not work for global declarations because the AST
/// breaks up multiple-declaration DeclStmt's into multiple single-declaration
/// DeclStmt's.
-/// Example: Given non-global declarations
-/// \code
-/// int a, b = 0;
-/// int c;
-/// int d = 2, e;
-/// \endcode
-/// declStmt(containsDeclaration(
-/// 0, varDecl(hasInitializer(anything()))))
-/// matches only 'int d = 2, e;', and
-/// declStmt(containsDeclaration(1, varDecl()))
+///
+/// Given non-global declarations
/// \code
-/// matches 'int a, b = 0' as well as 'int d = 2, e;'
-/// but 'int c;' is not matched.
+/// void foo() {
+/// int a, b = 0;
+/// int c;
+/// int d = 2, e;
+/// }
/// \endcode
+/// The matcher \matcher{declStmt(containsDeclaration(
+/// 0, varDecl(hasInitializer(anything()))))}
+/// matches \match{int d = 2, e;}.
+/// The matcher \matcher{declStmt(containsDeclaration(1, varDecl()))}
+/// matches \match{int a, b = 0;} and \match{int d = 2, e;}
+/// but does not match \nomatch{int c;}.
AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
internal::Matcher<Decl>, InnerMatcher) {
const unsigned NumDecls = std::distance(Node.decl_begin(), Node.decl_end());
@@ -4737,15 +6369,16 @@ AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
///
/// Given
/// \code
-/// try {
-/// // ...
-/// } catch (int) {
-/// // ...
-/// } catch (...) {
-/// // ...
+/// void foo() {
+/// try {}
+/// catch (int) {}
+/// catch (...) {}
/// }
/// \endcode
-/// cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxCatchStmt(isCatchAll())}
+/// matches \match{catch (...) {}}
+/// but does not match \nomatch{catch(int)}
AST_MATCHER(CXXCatchStmt, isCatchAll) {
return Node.getExceptionDecl() == nullptr;
}
@@ -4759,10 +6392,13 @@ AST_MATCHER(CXXCatchStmt, isCatchAll) {
/// int foo_;
/// };
/// \endcode
-/// cxxRecordDecl(has(cxxConstructorDecl(
-/// hasAnyConstructorInitializer(anything())
-/// )))
-/// record matches Foo, hasAnyConstructorInitializer matches foo_(1)
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(
+/// hasAnyConstructorInitializer(cxxCtorInitializer().bind("ctor_init"))
+/// )}
+/// matches \match{Foo() : foo_(1) { }},
+/// with \matcher{type=sub$cxxCtorInitializer()}
+/// matching \match{sub=ctor_init$foo_(1)}.
AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
auto MatchIt = matchesFirstInPointerRange(InnerMatcher, Node.init_begin(),
@@ -4781,10 +6417,13 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
/// int foo_;
/// };
/// \endcode
-/// cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
-/// forField(hasName("foo_"))))))
-/// matches Foo
-/// with forField matching foo_
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasAnyConstructorInitializer(
+/// forField(fieldDecl(hasName("foo_")).bind("field"))))}
+/// matches \match{Foo() : foo_(1) { }},
+/// with \matcher{type=sub$fieldDecl(hasName("foo_"))}
+/// matching \match{sub=field$foo_(1)}.
AST_MATCHER_P(CXXCtorInitializer, forField,
internal::Matcher<FieldDecl>, InnerMatcher) {
const FieldDecl *NodeAsDecl = Node.getAnyMember();
@@ -4801,10 +6440,13 @@ AST_MATCHER_P(CXXCtorInitializer, forField,
/// int foo_;
/// };
/// \endcode
-/// cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
-/// withInitializer(integerLiteral(equals(1)))))))
-/// matches Foo
-/// with withInitializer matching (1)
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasAnyConstructorInitializer(
+/// withInitializer(integerLiteral(equals(1)).bind("literal"))))}
+/// matches \match{Foo() : foo_(1) { }},
+/// with \matcher{type=sub$integerLiteral(equals(1))} matching
+/// \match{sub=literal$1}.
AST_MATCHER_P(CXXCtorInitializer, withInitializer,
internal::Matcher<Expr>, InnerMatcher) {
const Expr* NodeAsExpr = Node.getInit();
@@ -4817,14 +6459,17 @@ AST_MATCHER_P(CXXCtorInitializer, withInitializer,
///
/// Given
/// \code
+/// struct Bar { explicit Bar(const char*); };
/// struct Foo {
/// Foo() { }
/// Foo(int) : foo_("A") { }
-/// string foo_;
+/// Bar foo_{""};
/// };
/// \endcode
-/// cxxConstructorDecl(hasAnyConstructorInitializer(isWritten()))
-/// will match Foo(int), but not Foo()
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasAnyConstructorInitializer(isWritten()))} will
+/// match \match{Foo(int) : foo_("A") { }}, but not \nomatch{Foo() { }}
AST_MATCHER(CXXCtorInitializer, isWritten) {
return Node.isWritten();
}
@@ -4843,8 +6488,12 @@ AST_MATCHER(CXXCtorInitializer, isWritten) {
/// E() : B() {}
/// };
/// \endcode
-/// cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer()))
-/// will match E(), but not match D(int).
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer()))}
+/// matches \match{E() : B() {}} and \match{D(int i) : I(i) {}}.
+/// The constructor of \c D is matched, because it implicitly has a constructor
+/// initializer for \c B .
AST_MATCHER(CXXCtorInitializer, isBaseInitializer) {
return Node.isBaseInitializer();
}
@@ -4863,8 +6512,11 @@ AST_MATCHER(CXXCtorInitializer, isBaseInitializer) {
/// E() : B() {}
/// };
/// \endcode
-/// cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer()))
-/// will match D(int), but not match E().
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer()))}
+/// will match \match{D(int i) : I(i) {}}, but not match \nomatch{E() : B()
+/// {}}.
AST_MATCHER(CXXCtorInitializer, isMemberInitializer) {
return Node.isMemberInitializer();
}
@@ -4874,11 +6526,11 @@ AST_MATCHER(CXXCtorInitializer, isMemberInitializer) {
///
/// Given
/// \code
-/// void x(int, int, int) { int y; x(1, y, 42); }
+/// void x(int, int, int) { int y = 42; x(1, y, 42); }
/// \endcode
-/// callExpr(hasAnyArgument(declRefExpr()))
-/// matches x(1, y, 42)
-/// with hasAnyArgument(...)
+/// The matcher
+/// \matcher{callExpr(hasAnyArgument(ignoringImplicit(declRefExpr())))} matches
+/// \match{x(1, y, 42)} with hasAnyArgument(...)
/// matching y
///
/// For ObjectiveC, given
@@ -4886,8 +6538,10 @@ AST_MATCHER(CXXCtorInitializer, isMemberInitializer) {
/// @interface I - (void) f:(int) y; @end
/// void foo(I *i) { [i f:12]; }
/// \endcode
-/// objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))
-/// matches [i f:12]
+/// \compile_args{-ObjC}
+/// The matcher
+/// \matcher{objcMessageExpr(hasAnyArgument(integerLiteral(equals(12))))}
+/// matches \match{[i f:12]}
AST_POLYMORPHIC_MATCHER_P(hasAnyArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(
CallExpr, CXXConstructExpr,
@@ -4916,8 +6570,12 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument,
/// auto g = [x = 1](){};
/// }
/// \endcode
-/// In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`,
-/// `lambdaCapture()` matches `x` and `x=1`.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{lambdaExpr(hasAnyCapture(lambdaCapture().bind("capture")))},
+/// matches \match{[x](){}} and \match{[x = 1](){}},
+/// with \matcher{type=sub$lambdaCapture()} matching
+/// \match{sub=capture$x} and \match{sub=capture$x = 1}.
extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture;
/// Matches any capture in a lambda expression.
@@ -4929,9 +6587,10 @@ extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture;
/// auto f = [=](){ return t; };
/// }
/// \endcode
-/// lambdaExpr(hasAnyCapture(lambdaCapture())) and
-/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t")))))
-/// both match `[=](){ return t; }`.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{lambdaExpr(hasAnyCapture(lambdaCapture()))} and
+/// \matcher{lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("t")))))}
+/// both match \match{[=](){ return t; }}.
AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<LambdaCapture>,
InnerMatcher) {
for (const LambdaCapture &Capture : Node.captures()) {
@@ -4956,9 +6615,13 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<LambdaCapture>,
/// auto g = [x = 1](){};
/// }
/// \endcode
-/// In the matcher
-/// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))),
-/// capturesVar(hasName("x")) matches `x` and `x = 1`.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{lambdaExpr(hasAnyCapture(
+/// lambdaCapture(capturesVar(hasName("x"))).bind("capture")))}
+/// matches \match{[x](){}} and \match{[x = 1](){}}, with
+/// \matcher{type=sub$lambdaCapture(capturesVar(hasName("x"))).bind("capture")}
+/// matching \match{sub=capture$x} and \match{sub=capture$x = 1}.
AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
InnerMatcher) {
if (!Node.capturesVariable())
@@ -4979,11 +6642,36 @@ AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
/// }
/// };
/// \endcode
-/// lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis())))
-/// matches `[this]() { return cc; }`.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis())))}
+/// matches \match{[this]() { return cc; }}.
AST_MATCHER(LambdaCapture, capturesThis) { return Node.capturesThis(); }
/// Matches a constructor call expression which uses list initialization.
+///
+/// Given
+/// \code
+/// namespace std {
+/// template <typename T>
+/// class initializer_list {
+/// const T* begin;
+/// const T* end;
+/// };
+/// }
+/// template <typename T> class vector {
+/// public: vector(std::initializer_list<T>) {}
+/// };
+///
+/// vector<int> a({ 1, 2, 3 });
+/// vector<int> b = { 4, 5 };
+/// int c[] = { 6, 7 };
+/// struct pair { int x; int y; };
+/// pair d = { 8, 9 };
+/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++11-or-later}
+/// The matcher \matcher{cxxConstructExpr(isListInitialization())}
+/// matches \match{{ 4, 5 }}.
AST_MATCHER(CXXConstructExpr, isListInitialization) {
return Node.isListInitialization();
}
@@ -4994,12 +6682,16 @@ AST_MATCHER(CXXConstructExpr, isListInitialization) {
/// Given
/// \code
/// void foo() {
-/// struct point { double x; double y; };
-/// point pt[2] = { { 1.0, 2.0 } };
+/// struct Foo {
+/// double x;
+/// };
+/// auto Val = Foo();
/// }
/// \endcode
-/// initListExpr(has(cxxConstructExpr(requiresZeroInitialization()))
-/// will match the implicit array filler for pt[1].
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxConstructExpr(requiresZeroInitialization())}
+/// matches \match{Foo()} because the \c x member has to be zero initialized.
AST_MATCHER(CXXConstructExpr, requiresZeroInitialization) {
return Node.requiresZeroInitialization();
}
@@ -5011,17 +6703,20 @@ AST_MATCHER(CXXConstructExpr, requiresZeroInitialization) {
/// \code
/// class X { void f(int x) {} };
/// \endcode
-/// cxxMethodDecl(hasParameter(0, hasType(varDecl())))
-/// matches f(int x) {}
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxMethodDecl(hasParameter(0, hasType(asString("int"))))}
+/// matches \match{void f(int x) {}}
/// with hasParameter(...)
-/// matching int x
+/// matching int x.
///
/// For ObjectiveC, given
/// \code
/// @interface I - (void) f:(int) y; @end
/// \endcode
-//
-/// the matcher objcMethodDecl(hasParameter(0, hasName("y")))
+/// \compile_args{-ObjC}
+///
+/// The matcher \matcher{objcMethodDecl(hasParameter(0, hasName("y")))}
/// matches the declaration of method f with hasParameter
/// matching y.
AST_POLYMORPHIC_MATCHER_P2(hasParameter,
@@ -5046,9 +6741,13 @@ AST_POLYMORPHIC_MATCHER_P2(hasParameter,
/// int operator+(int);
/// };
/// \endcode
+/// \compile_args{-std=c++23-or-later}
///
-/// cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two
-/// methods but not the last two.
+/// The matcher \matcher{cxxMethodDecl(isExplicitObjectMemberFunction())}
+/// matches \match{int operator-(this A, int)} and
+/// \match{void fun(this A &&self)},
+/// but not \nomatch{static int operator()(int)} or
+/// \nomatch{int operator+(int)}.
AST_MATCHER(CXXMethodDecl, isExplicitObjectMemberFunction) {
return Node.isExplicitObjectMemberFunction();
}
@@ -5059,14 +6758,16 @@ AST_MATCHER(CXXMethodDecl, isExplicitObjectMemberFunction) {
/// \code
/// void f(int i);
/// int y;
-/// f(y);
+/// void foo() {
+/// f(y);
+/// }
/// \endcode
-/// callExpr(
+/// The matcher \matcher{callExpr(
/// forEachArgumentWithParam(
/// declRefExpr(to(varDecl(hasName("y")))),
/// parmVarDecl(hasType(isInteger()))
-/// ))
-/// matches f(y);
+/// ))}
+/// matches \match{f(y)};
/// with declRefExpr(...)
/// matching int y
/// and parmVarDecl(...)
@@ -5119,17 +6820,18 @@ AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParam,
/// Given
/// \code
/// void f(int i);
-/// int y;
-/// f(y);
-/// void (*f_ptr)(int) = f;
-/// f_ptr(y);
+/// void foo(int y) {
+/// f(y);
+/// void (*f_ptr)(int) = f;
+/// f_ptr(y);
+/// }
/// \endcode
-/// callExpr(
+/// The matcher \matcher{callExpr(
/// forEachArgumentWithParamType(
/// declRefExpr(to(varDecl(hasName("y")))),
-/// qualType(isInteger()).bind("type)
-/// ))
-/// matches f(y) and f_ptr(y)
+/// qualType(isInteger()).bind("type")
+/// ))}
+/// matches \match{f(y)} and \match{f_ptr(y)}
/// with declRefExpr(...)
/// matching int y
/// and qualType(...)
@@ -5222,9 +6924,11 @@ AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParamType,
/// }
/// \endcode
///
-/// ``parmVarDecl(isAtPosition(0))`` matches ``int a``.
+/// The matcher \matcher{parmVarDecl(isAtPosition(0))} matches
+/// \match{int a}.
///
-/// ``parmVarDecl(isAtPosition(1))`` matches ``int b``.
+/// The matcher \matcher{parmVarDecl(isAtPosition(1))}
+/// matches \match{int b}.
AST_MATCHER_P(ParmVarDecl, isAtPosition, unsigned, N) {
const clang::DeclContext *Context = Node.getParentFunctionOrMethod();
@@ -5247,27 +6951,32 @@ AST_MATCHER_P(ParmVarDecl, isAtPosition, unsigned, N) {
/// \code
/// class X { void f(int x, int y, int z) {} };
/// \endcode
-/// cxxMethodDecl(hasAnyParameter(hasName("y")))
-/// matches f(int x, int y, int z) {}
-/// with hasAnyParameter(...)
-/// matching int y
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxMethodDecl(hasAnyParameter(
+/// parmVarDecl(hasName("y")).bind("parm")))}
+/// matches \match{void f(int x, int y, int z) {}},
+/// with \matcher{type=sub$parmVarDecl(hasName("y"))}
+/// matching \match{sub=parm$int y}.
///
/// For ObjectiveC, given
/// \code
/// @interface I - (void) f:(int) y; @end
/// \endcode
-//
-/// the matcher objcMethodDecl(hasAnyParameter(hasName("y")))
-/// matches the declaration of method f with hasParameter
+/// \compile_args{-ObjC}
+///
+/// the matcher \matcher{objcMethodDecl(hasAnyParameter(hasName("y")))}
+/// matches the declaration of method f with hasParameter
/// matching y.
///
/// For blocks, given
/// \code
/// b = ^(int y) { printf("%d", y) };
/// \endcode
+/// \compile_args{-ObjC}
///
-/// the matcher blockDecl(hasAnyParameter(hasName("y")))
-/// matches the declaration of the block b with hasParameter
+/// the matcher \matcher{blockDecl(hasAnyParameter(hasName("y")))}
+/// matches the declaration of the block b with hasParameter
/// matching y.
AST_POLYMORPHIC_MATCHER_P(hasAnyParameter,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
@@ -5291,12 +7000,12 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyParameter,
/// void j(int i);
/// void k(int x, int y, int z, ...);
/// \endcode
-/// functionDecl(parameterCountIs(2))
-/// matches \c g and \c h
-/// functionProtoType(parameterCountIs(2))
-/// matches \c g and \c h
-/// functionProtoType(parameterCountIs(3))
-/// matches \c k
+/// The matcher \matcher{functionDecl(parameterCountIs(2))}
+/// matches \match{void g(int i, int j) {}} and \match{void h(int i, int j)}
+/// The matcher \matcher{functionProtoType(parameterCountIs(1))}
+/// matches the type \match{type=typestr;count=2$void (int)} of \c f and \c j.
+/// The matcher \matcher{functionProtoType(parameterCountIs(3))} matches the
+/// type \match{type=typestr$void (int, int, int, ...)} of \c k.
AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
FunctionProtoType),
@@ -5320,14 +7029,24 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
/// template <typename T, typename U>
/// void f(T&& t, U&& u) {}
///
-/// bool B = false;
-/// f(R, B);
+/// void foo() {
+/// bool B = false;
+/// f(R, B);
+/// }
/// \endcode
-/// templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
-/// matches twice, with expr() matching 'R * 2' and 'R * 4'
-/// functionDecl(forEachTemplateArgument(refersToType(builtinType())))
-/// matches the specialization f<unsigned, bool> twice, for 'unsigned'
-/// and 'bool'
+/// \compile_args{-fno-delayed-template-parsing;-std=c++11-or-later}
+/// The matcher
+/// \matcher{templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg"))))}
+/// matches \match{type=typestr;count=2$Matrix<int, R * 2, R * 4>} twice, with
+/// \matcher{type=sub$expr()} matching \match{sub=t_arg$R * 2} and
+/// \match{sub=t_arg$R * 4}.
+/// The matcher
+/// \matcher{functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type"))))}
+/// matches the specialization of \match{count=2$void f(T&& t, U&& u) {}} twice
+/// for each of the template arguments, with \matcher{type=sub$qualType()}
+/// matching
+/// \match{sub=type;type=typestr$unsigned} and
+/// \match{sub=type;type=typestr$bool}.
AST_POLYMORPHIC_MATCHER_P(
forEachTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -5356,23 +7075,23 @@ AST_POLYMORPHIC_MATCHER_P(
/// void nope();
/// [[noreturn]] void a();
/// __attribute__((noreturn)) void b();
-/// struct c { [[noreturn]] c(); };
-/// \endcode
-/// functionDecl(isNoReturn())
-/// matches all of those except
-/// \code
-/// void nope();
+/// struct C { [[noreturn]] void c(); };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(isNoReturn())}
+/// matches \match{void a()}, \match{__attribute__((noreturn)) void b()} and
+/// \match{void c()} but does not match \nomatch{void nope()}.
AST_MATCHER(FunctionDecl, isNoReturn) { return Node.isNoReturn(); }
/// Matches the return type of a function declaration.
///
-/// Given:
+/// Given
/// \code
/// class X { int f() { return 1; } };
/// \endcode
-/// cxxMethodDecl(returns(asString("int")))
-/// matches int f() { return 1; }
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(returns(asString("int")))}
+/// matches \match{int f() { return 1; }}.
AST_MATCHER_P(FunctionDecl, returns,
internal::Matcher<QualType>, InnerMatcher) {
return InnerMatcher.matches(Node.getReturnType(), Finder, Builder);
@@ -5380,19 +7099,21 @@ AST_MATCHER_P(FunctionDecl, returns,
/// Matches extern "C" function or variable declarations.
///
-/// Given:
+/// Given
/// \code
/// extern "C" void f() {}
/// extern "C" { void g() {} }
/// void h() {}
/// extern "C" int x = 1;
-/// extern "C" int y = 2;
+/// extern "C" { int y = 2; }
/// int z = 3;
/// \endcode
-/// functionDecl(isExternC())
-/// matches the declaration of f and g, but not the declaration of h.
-/// varDecl(isExternC())
-/// matches the declaration of x and y, but not the declaration of z.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(isExternC())}
+/// matches \match{void f() {}} and \match{void g() {}}.
+/// The matcher \matcher{varDecl(isExternC())}
+/// matches \match{int x = 1} and \match{int y = 2}, but does not
+/// match \nomatch{int z = 3}.
AST_POLYMORPHIC_MATCHER(isExternC, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl)) {
return Node.isExternC();
@@ -5401,17 +7122,17 @@ AST_POLYMORPHIC_MATCHER(isExternC, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
/// Matches variable/function declarations that have "static" storage
/// class specifier ("static" keyword) written in the source.
///
-/// Given:
+/// Given
/// \code
/// static void f() {}
/// static int i = 0;
/// extern int j;
/// int k;
/// \endcode
-/// functionDecl(isStaticStorageClass())
-/// matches the function declaration f.
-/// varDecl(isStaticStorageClass())
-/// matches the variable declaration i.
+/// The matcher \matcher{functionDecl(isStaticStorageClass())}
+/// matches \match{static void f() {}}.
+/// The matcher \matcher{varDecl(isStaticStorageClass())}
+/// matches \match{static int i = 0}.
AST_POLYMORPHIC_MATCHER(isStaticStorageClass,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl)) {
@@ -5420,56 +7141,77 @@ AST_POLYMORPHIC_MATCHER(isStaticStorageClass,
/// Matches deleted function declarations.
///
-/// Given:
+/// Given
/// \code
/// void Func();
/// void DeletedFunc() = delete;
/// \endcode
-/// functionDecl(isDeleted())
-/// matches the declaration of DeletedFunc, but not Func.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(isDeleted())}
+/// matches \match{void DeletedFunc()},
+/// but does not match \nomatch{void Func()}.
AST_MATCHER(FunctionDecl, isDeleted) {
return Node.isDeleted();
}
/// Matches defaulted function declarations.
///
-/// Given:
+/// Given
/// \code
/// class A { ~A(); };
/// class B { ~B() = default; };
/// \endcode
-/// functionDecl(isDefaulted())
-/// matches the declaration of ~B, but not ~A.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(isDefaulted())}
+/// matches \match{~B() = default},
+/// but does not match \nomatch{~A()}.
AST_MATCHER(FunctionDecl, isDefaulted) {
return Node.isDefaulted();
}
/// Matches weak function declarations.
///
-/// Given:
+/// Given
/// \code
-/// void foo() __attribute__((__weakref__("__foo")));
-/// void bar();
+/// static void f();
+/// void g() __attribute__((weak));
/// \endcode
-/// functionDecl(isWeak())
-/// matches the weak declaration "foo", but not "bar".
+/// The matcher \matcher{functionDecl(isWeak())}
+/// matches the weak declaration
+/// \match{void g() __attribute__((weak))},
+/// but does not match \nomatch{static void foo_v1()}.
AST_MATCHER(FunctionDecl, isWeak) { return Node.isWeak(); }
/// Matches functions that have a dynamic exception specification.
///
-/// Given:
+/// Given
/// \code
-/// void f();
-/// void g() noexcept;
-/// void h() noexcept(true);
-/// void i() noexcept(false);
-/// void j() throw();
-/// void k() throw(int);
-/// void l() throw(...);
-/// \endcode
-/// functionDecl(hasDynamicExceptionSpec()) and
-/// functionProtoType(hasDynamicExceptionSpec())
-/// match the declarations of j, k, and l, but not f, g, h, or i.
+/// void f(int);
+/// void g(int) noexcept;
+/// void h(int) noexcept(true);
+/// void i(int) noexcept(false);
+/// void j(int) throw();
+/// void k(int) throw(int);
+/// void l(int) throw(...);
+/// \endcode
+/// \compile_args{-std=c++11-14}
+/// The matcher \matcher{functionDecl(hasDynamicExceptionSpec())}
+/// matches the declarations \match{void j(int) throw()},
+/// \match{void k(int) throw(int)}
+/// and \match{void l(int) throw(...)},
+/// but does not match \nomatch{void f(int)}, \nomatch{void g(int) noexcept},
+/// \nomatch{void h(int) noexcept(true)}
+/// or \nomatch{void i(int) noexcept(true)}.
+/// The matcher
+/// \matcher{functionProtoType(hasDynamicExceptionSpec())} matches
+/// the type \match{type=typestr$void (int) throw()} of \c j ,
+/// the type \match{type=typestr$void (int) throw(int)} of \c k and
+/// the type \match{type=typestr$void (int) throw(...)} of \c l .
+/// It does not match
+/// the type \nomatch{type=typestr$void (int) noexcept} of \c f ,
+/// the type \nomatch{type=typestr$void (int) noexcept} of \c g ,
+/// the type \nomatch{type=typestr$void (int) noexcept(int)} of \c h or
+/// the type \nomatch{type=typestr$void (int) noexcept(...)} of \c i .
AST_POLYMORPHIC_MATCHER(hasDynamicExceptionSpec,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
FunctionProtoType)) {
@@ -5480,16 +7222,29 @@ AST_POLYMORPHIC_MATCHER(hasDynamicExceptionSpec,
/// Matches functions that have a non-throwing exception specification.
///
-/// Given:
+/// Given
/// \code
-/// void f();
-/// void g() noexcept;
-/// void h() throw();
-/// void i() throw(int);
-/// void j() noexcept(false);
+/// void f(int);
+/// void g(int) noexcept;
+/// void h(int) noexcept(false);
+/// void i(int) throw();
+/// void j(int) throw(int);
/// \endcode
-/// functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
-/// match the declarations of g, and h, but not f, i or j.
+/// \compile_args{-std=c++11-14}
+/// The matcher \matcher{functionDecl(isNoThrow())}
+/// matches the declaration \match{void g(int) noexcept}
+/// and \match{void i(int) throw()},
+/// but does not match \nomatch{void f(int)},
+/// \nomatch{void h(int) noexcept(false)}
+/// or \nomatch{void j(int) throw(int)}.
+/// The matcher
+/// \matcher{functionProtoType(isNoThrow())}
+/// matches the type \match{type=typestr$void (int) throw()} of \c i
+/// and the type \match{type=typestr$void (int) noexcept} of \c g,
+/// but does not match
+/// the type \nomatch{type=typestr$void (int)} of \c f ,
+/// the type \nomatch{type=typestr$void (int) noexcept(false)} of \c h or
+/// the type \nomatch{type=typestr$void (int) throw(int)} of \c j .
AST_POLYMORPHIC_MATCHER(isNoThrow,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
FunctionProtoType)) {
@@ -5511,17 +7266,20 @@ AST_POLYMORPHIC_MATCHER(isNoThrow,
/// Matches consteval function declarations and if consteval/if ! consteval
/// statements.
///
-/// Given:
+/// Given
/// \code
/// consteval int a();
/// void b() { if consteval {} }
/// void c() { if ! consteval {} }
/// void d() { if ! consteval {} else {} }
/// \endcode
-/// functionDecl(isConsteval())
-/// matches the declaration of "int a()".
-/// ifStmt(isConsteval())
-/// matches the if statement in "void b()", "void c()", "void d()".
+/// \compile_args{-std=c++23-or-later}
+/// The matcher \matcher{functionDecl(isConsteval())}
+/// matches \match{consteval int a()}.
+/// The matcher \matcher{ifStmt(isConsteval())}
+/// matches the if statements
+/// \match{if consteval {}}, \match{if ! consteval {}} and
+/// \match{if ! consteval {} else {}}.
AST_POLYMORPHIC_MATCHER(isConsteval,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, IfStmt)) {
return Node.isConsteval();
@@ -5530,18 +7288,19 @@ AST_POLYMORPHIC_MATCHER(isConsteval,
/// Matches constexpr variable and function declarations,
/// and if constexpr.
///
-/// Given:
+/// Given
/// \code
/// constexpr int foo = 42;
/// constexpr int bar();
/// void baz() { if constexpr(1 > 0) {} }
/// \endcode
-/// varDecl(isConstexpr())
-/// matches the declaration of foo.
-/// functionDecl(isConstexpr())
-/// matches the declaration of bar.
-/// ifStmt(isConstexpr())
-/// matches the if statement in baz.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{varDecl(isConstexpr())}
+/// matches \match{constexpr int foo = 42}.
+/// The matcher \matcher{functionDecl(isConstexpr())}
+/// matches \match{constexpr int bar()}.
+/// The matcher \matcher{ifStmt(isConstexpr())}
+/// matches \match{if constexpr(1 > 0) {}}.
AST_POLYMORPHIC_MATCHER(isConstexpr,
AST_POLYMORPHIC_SUPPORTED_TYPES(VarDecl,
FunctionDecl,
@@ -5551,15 +7310,19 @@ AST_POLYMORPHIC_MATCHER(isConstexpr,
/// Matches constinit variable declarations.
///
-/// Given:
+/// Given
/// \code
/// constinit int foo = 42;
/// constinit const char* bar = "bar";
/// int baz = 42;
/// [[clang::require_constant_initialization]] int xyz = 42;
/// \endcode
-/// varDecl(isConstinit())
-/// matches the declaration of `foo` and `bar`, but not `baz` and `xyz`.
+/// \compile_args{-std=c++20-or-later}
+/// The matcher \matcher{varDecl(isConstinit())}
+/// matches the declaration of \match{constinit int foo = 42}
+/// and \match{constinit const char* bar = "bar"},
+/// but does not match \nomatch{int baz = 42} or
+/// \nomatch{[[clang::require_constant_initialization]] int xyz = 42}.
AST_MATCHER(VarDecl, isConstinit) {
if (const auto *CIA = Node.getAttr<ConstInitAttr>())
return CIA->isConstinit();
@@ -5568,8 +7331,11 @@ AST_MATCHER(VarDecl, isConstinit) {
/// Matches selection statements with initializer.
///
-/// Given:
+/// Given
/// \code
+/// struct vec { int* begin(); int* end(); };
+/// int foobar();
+/// vec& get_range();
/// void foo() {
/// if (int i = foobar(); i > 0) {}
/// switch (int i = foobar(); i) {}
@@ -5581,12 +7347,17 @@ AST_MATCHER(VarDecl, isConstinit) {
/// for (auto& x : get_range()) {}
/// }
/// \endcode
-/// ifStmt(hasInitStatement(anything()))
-/// matches the if statement in foo but not in bar.
-/// switchStmt(hasInitStatement(anything()))
-/// matches the switch statement in foo but not in bar.
-/// cxxForRangeStmt(hasInitStatement(anything()))
-/// matches the range for statement in foo but not in bar.
+/// \compile_args{-std=c++20-or-later}
+/// The matcher \matcher{ifStmt(hasInitStatement(anything()))}
+/// matches the if statement \match{if (int i = foobar(); i > 0) {}}
+/// in foo but not \nomatch{if (foobar() > 0) {}} in bar.
+/// The matcher \matcher{switchStmt(hasInitStatement(anything()))}
+/// matches the switch statement \match{switch (int i = foobar(); i) {}}
+/// in foo but not \nomatch{switch (foobar()) {}} in bar.
+/// The matcher \matcher{cxxForRangeStmt(hasInitStatement(anything()))}
+/// matches the range for statement
+/// \match{for (auto& a = get_range(); auto& x : a) {}} in foo
+/// but not \nomatch{for (auto& x : get_range()) {}} in bar.
AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, SwitchStmt,
CXXForRangeStmt),
@@ -5598,10 +7369,15 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
/// Matches the condition expression of an if statement, for loop,
/// switch statement or conditional operator.
///
-/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+/// Given
/// \code
+/// void foo() {
/// if (true) {}
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{ifStmt(hasCondition(cxxBoolLiteral(equals(true))))}
+/// \match{if (true) {}}
AST_POLYMORPHIC_MATCHER_P(
hasCondition,
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt, WhileStmt, DoStmt,
@@ -5614,11 +7390,15 @@ AST_POLYMORPHIC_MATCHER_P(
/// Matches the then-statement of an if statement.
///
-/// Examples matches the if statement
-/// (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
+/// Given
/// \code
+/// void foo() {
/// if (false) true; else false;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{ifStmt(hasThen(cxxBoolLiteral(equals(true))))}
+/// \match{if (false) true; else false}
AST_MATCHER_P(IfStmt, hasThen, internal::Matcher<Stmt>, InnerMatcher) {
const Stmt *const Then = Node.getThen();
return (Then != nullptr && InnerMatcher.matches(*Then, Finder, Builder));
@@ -5626,11 +7406,15 @@ AST_MATCHER_P(IfStmt, hasThen, internal::Matcher<Stmt>, InnerMatcher) {
/// Matches the else-statement of an if statement.
///
-/// Examples matches the if statement
-/// (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
+/// Given
/// \code
+/// void foo() {
/// if (false) false; else true;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{ifStmt(hasElse(cxxBoolLiteral(equals(true))))}
+/// \match{if (false) false; else true}
AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
const Stmt *const Else = Node.getElse();
return (Else != nullptr && InnerMatcher.matches(*Else, Finder, Builder));
@@ -5644,10 +7428,12 @@ AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
/// \code
/// class X { int a; int b; };
/// \endcode
-/// cxxRecordDecl(
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(
/// has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
-/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
-/// matches the class \c X, as \c a and \c b have the same type.
+/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))}
+/// matches \match{class X { int a; int b; }}, as \c a and \c b have the same
+/// type.
///
/// Note that when multiple matches are involved via \c forEach* matchers,
/// \c equalsBoundNodes acts as a filter.
@@ -5677,14 +7463,19 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
///
/// Given
/// \code
+/// struct A {};
+/// A* GetAPointer();
+/// void foo() {
/// if (A* a = GetAPointer()) {}
+/// }
/// \endcode
-/// hasConditionVariableStatement(...)
-/// matches 'A* a = GetAPointer()'.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{ifStmt(hasConditionVariableStatement(declStmt()))}
+/// \match{if (A* a = GetAPointer()) {}}
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
internal::Matcher<DeclStmt>, InnerMatcher) {
- const DeclStmt* const DeclarationStatement =
- Node.getConditionVariableDeclStmt();
+ const DeclStmt *const DeclarationStatement =
+ Node.getConditionVariableDeclStmt();
return DeclarationStatement != nullptr &&
InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
}
@@ -5696,11 +7487,11 @@ AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
/// int i[5];
/// void f() { i[1] = 42; }
/// \endcode
-/// arraySubscriptExpression(hasIndex(integerLiteral()))
-/// matches \c i[1] with the \c integerLiteral() matching \c 1
-AST_MATCHER_P(ArraySubscriptExpr, hasIndex,
- internal::Matcher<Expr>, InnerMatcher) {
- if (const Expr* Expression = Node.getIdx())
+/// The matcher \matcher{arraySubscriptExpr(hasIndex(integerLiteral()))}
+/// matches \match{i[1]} with the \c integerLiteral() matching \c 1
+AST_MATCHER_P(ArraySubscriptExpr, hasIndex, internal::Matcher<Expr>,
+ InnerMatcher) {
+ if (const Expr *Expression = Node.getIdx())
return InnerMatcher.matches(*Expression, Finder, Builder);
return false;
}
@@ -5712,9 +7503,9 @@ AST_MATCHER_P(ArraySubscriptExpr, hasIndex,
/// int i[5];
/// void f() { i[1] = 42; }
/// \endcode
-/// arraySubscriptExpression(hasBase(implicitCastExpr(
-/// hasSourceExpression(declRefExpr()))))
-/// matches \c i[1] with the \c declRefExpr() matching \c i
+/// The matcher \matcher{arraySubscriptExpr(hasBase(implicitCastExpr(
+/// hasSourceExpression(declRefExpr()))))}
+/// matches \match{i[1]} with the \c declRefExpr() matching \c i
AST_MATCHER_P(ArraySubscriptExpr, hasBase,
internal::Matcher<Expr>, InnerMatcher) {
if (const Expr* Expression = Node.getBase())
@@ -5729,23 +7520,25 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
///
/// Given
/// \code
+/// void foo() {
/// for (;;) {}
+/// }
/// \endcode
-/// forStmt(hasBody(compoundStmt()))
-/// matches 'for (;;) {}'
-/// with compoundStmt()
-/// matching '{}'
+/// The matcher \matcher{forStmt(hasBody(compoundStmt().bind("body")))}
+/// matches \match{for (;;) {}}
+/// with \matcher{type=sub$compoundStmt()}
+/// matching \match{sub=body${}}
///
/// Given
/// \code
/// void f();
/// void f() {}
/// \endcode
-/// functionDecl(hasBody(compoundStmt()))
-/// matches 'void f() {}'
-/// with compoundStmt()
-/// matching '{}'
-/// but does not match 'void f();'
+/// The matcher \matcher{functionDecl(hasBody(compoundStmt().bind("compound")))}
+/// \match{void f() {}}
+/// with \matcher{type=sub$compoundStmt()}
+/// matching \match{sub=compound${}},
+/// but it does not match \nomatch{void f();}.
AST_POLYMORPHIC_MATCHER_P(
hasBody,
AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, WhileStmt, CXXForRangeStmt,
@@ -5768,31 +7561,28 @@ AST_POLYMORPHIC_MATCHER_P(
/// void f() {}
/// void g();
/// \endcode
-/// functionDecl(hasAnyBody(compoundStmt()))
-/// matches both 'void f();'
-/// and 'void f() {}'
-/// with compoundStmt()
-/// matching '{}'
-/// but does not match 'void g();'
-AST_MATCHER_P(FunctionDecl, hasAnyBody,
- internal::Matcher<Stmt>, InnerMatcher) {
+/// The matcher \matcher{functionDecl(hasAnyBody(compoundStmt().bind("body")))}
+/// matches \match{void f() {}} and the declaration \match{void f()},
+/// with \matcher{type=sub$compoundStmt()} matching \match{sub=body${}}, but it
+/// does not match \nomatch{void g()}.
+AST_MATCHER_P(FunctionDecl, hasAnyBody, internal::Matcher<Stmt>, InnerMatcher) {
const Stmt *const Statement = Node.getBody();
return (Statement != nullptr &&
InnerMatcher.matches(*Statement, Finder, Builder));
}
-
/// Matches compound statements where at least one substatement matches
/// a given matcher. Also matches StmtExprs that have CompoundStmt as children.
///
/// Given
/// \code
-/// { {}; 1+2; }
+/// void foo() { { {}; 1+2; } }
/// \endcode
-/// hasAnySubstatement(compoundStmt())
-/// matches '{ {}; 1+2; }'
-/// with compoundStmt()
-/// matching '{}'
+/// The matcher
+/// \matcher{compoundStmt(hasAnySubstatement(compoundStmt().bind("compound")))}
+/// \match{{ {}; 1+2; }} and \match{{ { {}; 1+2; } }}
+/// with \matcher{type=sub$compoundStmt()}
+/// matching \match{sub=compound${}} and \match{sub=compound${ {}; 1+2; }}.
AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
AST_POLYMORPHIC_SUPPORTED_TYPES(CompoundStmt,
StmtExpr),
@@ -5808,10 +7598,12 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
///
/// Example: Given
/// \code
+/// void foo() {
/// { for (;;) {} }
+/// }
/// \endcode
-/// compoundStmt(statementCountIs(0)))
-/// matches '{}'
+/// The matcher \matcher{compoundStmt(statementCountIs(0))}
+/// \match{{}}
/// but does not match the outer compound statement.
AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
return Node.size() == N;
@@ -5821,24 +7613,31 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
///
/// Given
/// \code
+/// void f(char, bool, double, int);
+/// void foo() {
/// f('\0', false, 3.14, 42);
+/// }
/// \endcode
-/// characterLiteral(equals(0))
-/// matches '\0'
-/// cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-/// match false
-/// floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-/// match 3.14
-/// integerLiteral(equals(42))
-/// matches 42
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{characterLiteral(equals(0U))} matches \match{'\0'}.
+/// The matchers \matcher{cxxBoolLiteral(equals(false))} and
+/// \matcher{cxxBoolLiteral(equals(0))} match \match{false}.
+/// The matcher \matcher{floatLiteral(equals(3.14))} matches \match{3.14}.
+/// The matcher \matcher{integerLiteral(equals(42))} matches \match{42}.
///
/// Note that you cannot directly match a negative numeric literal because the
/// minus sign is not part of the literal: It is a unary operator whose operand
/// is the positive numeric literal. Instead, you must use a unaryOperator()
/// matcher to match the minus sign:
///
-/// unaryOperator(hasOperatorName("-"),
-/// hasUnaryOperand(integerLiteral(equals(13))))
+/// Given
+/// \code
+/// int val = -1;
+/// \endcode
+///
+/// The matcher \matcher{unaryOperator(hasOperatorName("-"),
+/// hasUnaryOperand(integerLiteral(equals(1))))}
+/// matches \match{-1}.
///
/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -5882,19 +7681,26 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
/// Matches the operator Name of operator expressions and fold expressions
/// (binary or unary).
///
-/// Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+/// Given
/// \code
-/// !(a || b)
+//// void foo(bool a, bool b) {
+/// !(a || b);
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{binaryOperator(hasOperatorName("||"))}
+/// matches \match{a || b}
///
-/// Example matches `(0 + ... + args)`
-/// (matcher = cxxFoldExpr(hasOperatorName("+")))
+/// Given
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
/// \endcode
+/// \compile_args{-std=c++17-or-later}
+/// The matcher \matcher{cxxFoldExpr(hasOperatorName("+"))}
+/// matches \match{(0 + ... + args)}.
AST_POLYMORPHIC_MATCHER_P(
hasOperatorName,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -5909,9 +7715,28 @@ AST_POLYMORPHIC_MATCHER_P(
/// Matches operator expressions (binary or unary) that have any of the
/// specified names.
///
-/// hasAnyOperatorName("+", "-")
-/// Is equivalent to
-/// anyOf(hasOperatorName("+"), hasOperatorName("-"))
+/// It provides a compact way of writing if an operator has any of the specified
+/// names:
+/// The matcher
+/// \c hasAnyOperatorName("+", "-")
+/// Is equivalent to
+/// \c{anyOf(hasOperatorName("+"), hasOperatorName("-"))}
+///
+/// Given
+/// \code
+//// void foo(bool a, bool b) {
+/// !(a || b);
+/// }
+///
+//// void bar(bool a, bool b) {
+/// a && b;
+/// }
+/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{binaryOperator(hasAnyOperatorName("||", "&&"))}
+/// matches \match{a || b} and \match{a && b}.
+/// The matcher \matcher{unaryOperator(hasAnyOperatorName("-", "!"))}
+/// matches \match{!(a || b)}.
extern const internal::VariadicFunction<
internal::PolymorphicMatcher<internal::HasAnyOperatorNameMatcher,
AST_POLYMORPHIC_SUPPORTED_TYPES(
@@ -5923,18 +7748,24 @@ extern const internal::VariadicFunction<
/// Matches all kinds of assignment operators.
///
-/// Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+/// Given
/// \code
+/// void foo(int a, int b) {
/// if (a == b)
/// a += b;
+/// }
/// \endcode
+/// The matcher \matcher{binaryOperator(isAssignmentOperator())}
+/// matches \match{a += b}.
///
-/// Example 2: matches s1 = s2
-/// (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+/// Given
/// \code
/// struct S { S& operator=(const S&); };
/// void x() { S s1, s2; s1 = s2; }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxOperatorCallExpr(isAssignmentOperator())}
+/// matches \match{s1 = s2}.
AST_POLYMORPHIC_MATCHER(
isAssignmentOperator,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -5944,18 +7775,24 @@ AST_POLYMORPHIC_MATCHER(
/// Matches comparison operators.
///
-/// Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+/// Given
/// \code
+/// void foo(int a, int b) {
/// if (a == b)
/// a += b;
+/// }
/// \endcode
+/// The matcher \matcher{binaryOperator(isComparisonOperator())}
+/// matches \match{a == b}
///
-/// Example 2: matches s1 < s2
-/// (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+/// Given
/// \code
/// struct S { bool operator<(const S& other); };
/// void x(S s1, S s2) { bool b1 = s1 < s2; }
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxOperatorCallExpr(isComparisonOperator())}
+/// matches \match{s1 < s2}
AST_POLYMORPHIC_MATCHER(
isComparisonOperator,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -5965,10 +7802,17 @@ AST_POLYMORPHIC_MATCHER(
/// Matches the left hand side of binary operator expressions.
///
-/// Example matches a (matcher = binaryOperator(hasLHS()))
+/// Given
/// \code
-/// a || b
+/// void foo(bool a, bool b) {
+/// a || b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{binaryOperator(hasLHS(expr().bind("lhs")))}
+/// matches \match{a || b},
+/// with \matcher{type=sub$expr()}
+/// matching \match{sub=lhs$a}.
AST_POLYMORPHIC_MATCHER_P(
hasLHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -5982,10 +7826,17 @@ AST_POLYMORPHIC_MATCHER_P(
/// Matches the right hand side of binary operator expressions.
///
-/// Example matches b (matcher = binaryOperator(hasRHS()))
+/// Given
/// \code
-/// a || b
+/// void foo(bool a, bool b) {
+/// a || b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{binaryOperator(hasRHS(expr().bind("rhs")))}
+/// matches \match{a || b},
+/// with \matcher{type=sub$expr()}
+/// matching \match{sub=rhs$b}.
AST_POLYMORPHIC_MATCHER_P(
hasRHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -5999,6 +7850,32 @@ AST_POLYMORPHIC_MATCHER_P(
/// Matches if either the left hand side or the right hand side of a
/// binary operator or fold expression matches.
+///
+/// Given
+/// \code
+/// struct S {};
+/// bool operator ==(const S&, const S&);
+///
+/// void f(int a, const S&lhs, const S&rhs) {
+/// a + 0;
+/// lhs == rhs;
+/// lhs != rhs;
+/// }
+///
+/// template <typename ...Ts>
+/// auto sum(Ts... args) {
+/// return (0 + ... + args);
+/// }
+/// \endcode
+/// \compile_args{-std=c++20-or-later}
+///
+/// The matcher \matcher{binaryOperator(hasEitherOperand(integerLiteral()))}
+/// matches \match{a + 0}.
+/// The matcher \matcher{cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+/// parmVarDecl(hasName("lhs"))))))} matches \match{lhs == rhs} and
+/// \match{lhs != rhs}.
+/// The matcher \matcher{cxxFoldExpr(hasEitherOperand(integerLiteral()))}
+/// matches \match{(0 + ... + args)}.
AST_POLYMORPHIC_MATCHER_P(
hasEitherOperand,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -6012,14 +7889,20 @@ AST_POLYMORPHIC_MATCHER_P(
/// Matches if both matchers match with opposite sides of the binary operator
/// or fold expression.
///
-/// Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-/// integerLiteral(equals(2)))
+/// Given
/// \code
-/// 1 + 2 // Match
-/// 2 + 1 // Match
-/// 1 + 1 // No match
-/// 2 + 2 // No match
+/// void foo() {
+/// 1 + 2; // Match
+/// 2 + 1; // Match
+/// 1 + 1; // No match
+/// 2 + 2; // No match
+/// }
/// \endcode
+/// The matcher \matcher{binaryOperator(hasOperands(integerLiteral(equals(1)),
+/// integerLiteral(equals(2))))}
+/// matches \match{1 + 2} and \match{2 + 1},
+/// but does not match \nomatch{1 + 1}
+/// or \nomatch{2 + 2}.
AST_POLYMORPHIC_MATCHER_P2(
hasOperands,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
@@ -6033,11 +7916,15 @@ AST_POLYMORPHIC_MATCHER_P2(
/// Matches if the operand of a unary operator matches.
///
-/// Example matches true (matcher = hasUnaryOperand(
-/// cxxBoolLiteral(equals(true))))
/// \code
-/// !true
+/// void foo() {
+/// !true;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher
+/// \matcher{unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))}
+/// matches \match{!true}.
AST_POLYMORPHIC_MATCHER_P(hasUnaryOperand,
AST_POLYMORPHIC_SUPPORTED_TYPES(UnaryOperator,
CXXOperatorCallExpr),
@@ -6050,18 +7937,27 @@ AST_POLYMORPHIC_MATCHER_P(hasUnaryOperand,
/// Matches if the cast's source expression
/// or opaque value's source expression matches the given matcher.
///
-/// Example 1: matches "a string"
-/// (matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
+/// Given
/// \code
-/// class URL { URL(string); };
-/// URL url = "a string";
+/// struct URL { URL(const char*); };
+/// URL url = "a string";
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{castExpr(hasSourceExpression(cxxConstructExpr()))}
+/// matches \match{"a string"}.
///
-/// Example 2: matches 'b' (matcher =
-/// opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
+/// Given
/// \code
-/// int a = b ?: 1;
+/// void foo(bool b) {
+/// int a = b ?: 1;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher
+/// \matcher{opaqueValueExpr(hasSourceExpression(
+/// implicitCastExpr(has(
+/// implicitCastExpr(has(declRefExpr()))))))}
+/// matches \match{count=2$b} twice, for the condition and the true expression.
AST_POLYMORPHIC_MATCHER_P(hasSourceExpression,
AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr,
OpaqueValueExpr),
@@ -6074,11 +7970,12 @@ AST_POLYMORPHIC_MATCHER_P(hasSourceExpression,
/// Matches casts that has a given cast kind.
///
-/// Example: matches the implicit cast around \c 0
-/// (matcher = castExpr(hasCastKind(CK_NullToPointer)))
+/// Given
/// \code
/// int *p = 0;
/// \endcode
+/// The matcher \matcher{castExpr(hasCastKind(CK_NullToPointer))}
+/// matches the implicit cast around \match{0}
///
/// If the matcher is use from clang-query, CastKind parameter
/// should be passed as a quoted string. e.g., hasCastKind("CK_NullToPointer").
@@ -6090,14 +7987,30 @@ AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) {
///
/// (Note: Clang's AST refers to other conversions as "casts" too, and calls
/// actual casts "explicit" casts.)
-AST_MATCHER_P(ExplicitCastExpr, hasDestinationType,
- internal::Matcher<QualType>, InnerMatcher) {
+///
+/// \code
+/// unsigned int a = (unsigned int)0;
+/// \endcode
+///
+/// The matcher \matcher{explicitCastExpr(hasDestinationType(
+/// qualType(isUnsignedInteger())))} matches \match{(unsigned int)0}.
+AST_MATCHER_P(ExplicitCastExpr, hasDestinationType, internal::Matcher<QualType>,
+ InnerMatcher) {
const QualType NodeType = Node.getTypeAsWritten();
return InnerMatcher.matches(NodeType, Finder, Builder);
}
/// Matches implicit casts whose destination type matches a given
/// matcher.
+///
+/// Given
+/// \code
+/// unsigned int a = 0;
+/// \endcode
+///
+/// The matcher
+/// \matcher{implicitCastExpr(hasImplicitDestinationType(
+/// qualType(isUnsignedInteger())))} matches \match{0}.
AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType,
internal::Matcher<QualType>, InnerMatcher) {
return InnerMatcher.matches(Node.getType(), Finder, Builder);
@@ -6107,50 +8020,66 @@ AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType,
///
/// Example matches S, but not C, U or E.
/// \code
-/// struct S {};
-/// class C {};
-/// union U {};
+/// struct S;
+/// class C;
+/// union U;
/// enum E {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{tagDecl(isStruct())} matches \match{struct S},
+/// but does not match \nomatch{class C}, \nomatch{union U} or
+/// \nomatch{enum E {}}.
AST_MATCHER(TagDecl, isStruct) {
return Node.isStruct();
}
/// Matches TagDecl object that are spelled with "union."
///
-/// Example matches U, but not C, S or E.
+/// Given
/// \code
-/// struct S {};
-/// class C {};
-/// union U {};
+/// struct S;
+/// class C;
+/// union U;
/// enum E {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{tagDecl(isUnion())} matches \match{union U},
+/// but does not match \nomatch{struct S}, \nomatch{class C} or
+/// \nomatch{enum E {}}.
AST_MATCHER(TagDecl, isUnion) {
return Node.isUnion();
}
/// Matches TagDecl object that are spelled with "class."
///
-/// Example matches C, but not S, U or E.
-/// \code
-/// struct S {};
-/// class C {};
-/// union U {};
+/// Given
+/// \code
+/// struct S;
+/// class C;
+/// union U;
/// enum E {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{tagDecl(isClass())} matches \match{class C},
+/// but does not match \nomatch{struct S}, \nomatch{union U} or
+/// \nomatch{enum E {}}.
AST_MATCHER(TagDecl, isClass) {
return Node.isClass();
}
/// Matches TagDecl object that are spelled with "enum."
///
-/// Example matches E, but not C, S or U.
+/// Given
/// \code
-/// struct S {};
-/// class C {};
-/// union U {};
+/// struct S;
+/// class C;
+/// union U;
/// enum E {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{tagDecl(isEnum())} matches \match{enum E {}},
+/// but does not match \nomatch{struct S}, \nomatch{class C} or
+/// \nomatch{union U}.
AST_MATCHER(TagDecl, isEnum) {
return Node.isEnum();
}
@@ -6158,14 +8087,29 @@ AST_MATCHER(TagDecl, isEnum) {
/// Matches the true branch expression of a conditional operator.
///
/// Example 1 (conditional ternary operator): matches a
+/// Given
/// \code
-/// condition ? a : b
+/// void foo(bool condition, int a, int b) {
+/// condition ? a : b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher
+/// \matcher{conditionalOperator(hasTrueExpression(expr().bind("true")))}
+/// matches \match{condition ? a : b},
+/// with \matcher{type=sub$expr()} matching \match{sub=true$a}.
///
/// Example 2 (conditional binary operator): matches opaqueValueExpr(condition)
+/// Given
/// \code
-/// condition ?: b
+/// void foo(bool condition, int a, int b) {
+/// condition ?: b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher \matcher{binaryConditionalOperator(hasTrueExpression(expr()))}
+/// matches \match{condition ?: b},
+/// with \matcher{type=sub$expr()} matching \match{sub=true$conditoin}.
AST_MATCHER_P(AbstractConditionalOperator, hasTrueExpression,
internal::Matcher<Expr>, InnerMatcher) {
const Expr *Expression = Node.getTrueExpr();
@@ -6178,9 +8122,20 @@ AST_MATCHER_P(AbstractConditionalOperator, hasTrueExpression,
///
/// Example matches b
/// \code
-/// condition ? a : b
-/// condition ?: b
+/// void foo(bool condition, int a, int b) {
+/// condition ? a : b;
+/// condition ?: b;
+/// }
/// \endcode
+/// \compile_args{-std=c++,c23-or-later}
+/// The matcher
+/// \matcher{conditionalOperator(hasFalseExpression(expr().bind("false")))}
+/// matches \match{condition ? a : b},
+/// with \matcher{type=sub$expr()} matching \match{sub=false$b}.
+/// The matcher
+/// \matcher{binaryConditionalOperator(hasFalseExpression(expr().bind("false")))}
+/// matches \match{condition ?: b},
+/// with \matcher{type=sub$expr()} matching \match{sub=false$b}.
AST_MATCHER_P(AbstractConditionalOperator, hasFalseExpression,
internal::Matcher<Expr>, InnerMatcher) {
const Expr *Expression = Node.getFalseExpr();
@@ -6198,6 +8153,16 @@ AST_MATCHER_P(AbstractConditionalOperator, hasFalseExpression,
/// extern int vb; // Doesn't match, as it doesn't define the variable.
/// void fa() {}
/// void fb(); // Doesn't match, as it has no body.
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{tagDecl(isDefinition())}
+/// matches \match{class A {}}.
+/// The matcher \matcher{varDecl(isDefinition())}
+/// matches \match{int va}.
+/// The matcher \matcher{functionDecl(isDefinition())}
+/// matches \match{void fa() {}}.
+///
+/// \code
/// @interface X
/// - (void)ma; // Doesn't match, interface is declaration.
/// @end
@@ -6205,6 +8170,9 @@ AST_MATCHER_P(AbstractConditionalOperator, hasFalseExpression,
/// - (void)ma {}
/// @end
/// \endcode
+/// \compile_args{-ObjC}
+/// The matcher \matcher{objcMethodDecl(isDefinition())}
+/// matches \match{- (void)ma {}}
///
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>,
/// Matcher<ObjCMethodDecl>
@@ -6225,6 +8193,12 @@ AST_POLYMORPHIC_MATCHER(isDefinition,
/// template <typename... Ts> void h(Ts...);
/// void i();
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{functionDecl(isVariadic())}
+/// matches \match{void f(...)},
+/// but does not match \nomatch{void g(int)},
+/// \nomatch{template <typename... Ts> void h(Ts...)},
+/// or \nomatch{void i()}.
AST_MATCHER(FunctionDecl, isVariadic) {
return Node.isVariadic();
}
@@ -6236,16 +8210,17 @@ AST_MATCHER(FunctionDecl, isVariadic) {
/// FIXME: What other kind of declarations would we need to generalize
/// this to?
///
-/// Example matches A() in the last line
-/// (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl(
-/// ofClass(hasName("A"))))))
+/// Given
/// \code
/// class A {
/// public:
/// A();
+/// void foo();
/// };
-/// A a = A();
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(ofClass(hasName("A")))}
+/// matches \match{A()} and \match{void foo()}.
AST_MATCHER_P(CXXMethodDecl, ofClass,
internal::Matcher<CXXRecordDecl>, InnerMatcher) {
@@ -6265,10 +8240,14 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
/// class B : public A { void f(); };
/// class C : public B { void f(); };
/// \endcode
-/// cxxMethodDecl(ofClass(hasName("C")),
-/// forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
-/// matches once, with "b" binding "A::f" and "d" binding "C::f" (Note
-/// that B::f is not overridden by C::f).
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(ofClass(hasName("C")),
+/// forEachOverridden(cxxMethodDecl().bind("b")))}
+/// matches \match{void f()} of \c C ,
+/// with \matcher{type=sub$cxxMethodDecl()} matching
+/// \match{sub=b$virtual void f()} of \c A ,
+/// but the matcher does not match \nomatch{void f()} of \c B because
+/// it is not overridden by C::f.
///
/// The check can produce multiple matches in case of multiple inheritance, e.g.
/// \code
@@ -6276,10 +8255,14 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
/// class A2 { virtual void f(); };
/// class C : public A1, public A2 { void f(); };
/// \endcode
-/// cxxMethodDecl(ofClass(hasName("C")),
-/// forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
-/// matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and
-/// once with "b" binding "A2::f" and "d" binding "C::f".
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(ofClass(hasName("C")),
+/// forEachOverridden(cxxMethodDecl().bind("b")))}
+/// matches \match{void f()} of \c C with the inner
+/// \matcher{type=sub$cxxMethodDecl()} matching \match{sub=b$virtual void f()}
+/// inside of \c A1 , and \match{void f()} of \c C with the inner
+/// \matcher{type=sub$cxxMethodDecl()} matching \match{sub=b$virtual void f()}
+/// inside of \c A2.
AST_MATCHER_P(CXXMethodDecl, forEachOverridden,
internal::Matcher<CXXMethodDecl>, InnerMatcher) {
BoundNodesTreeBuilder Result;
@@ -6300,20 +8283,27 @@ AST_MATCHER_P(CXXMethodDecl, forEachOverridden,
/// Matches declarations of virtual methods and C++ base specifers that specify
/// virtual inheritance.
///
-/// Example:
+/// Given
/// \code
/// class A {
/// public:
/// virtual void x(); // matches x
/// };
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(isVirtual())}
+/// matches \match{virtual void x()}.
///
-/// Example:
+/// Given
/// \code
-/// class Base {};
-/// class DirectlyDerived : virtual Base {}; // matches Base
-/// class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+/// struct Base {};
+/// struct DirectlyDerived : virtual Base {}; // matches Base
+/// struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))}
+/// matches \match{struct DirectlyDerived : virtual Base {}}.
///
/// Usable as: Matcher<CXXMethodDecl>, Matcher<CXXBaseSpecifier>
AST_POLYMORPHIC_MATCHER(isVirtual,
@@ -6335,7 +8325,10 @@ AST_POLYMORPHIC_MATCHER(isVirtual,
/// void x();
/// };
/// \endcode
-/// matches A::x but not B::x
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(isVirtualAsWritten())}
+/// matches \match{virtual void x()} of \c A,
+/// but does not match \notmatch{void x()} of \c B .
AST_MATCHER(CXXMethodDecl, isVirtualAsWritten) {
return Node.isVirtualAsWritten();
}
@@ -6346,7 +8339,7 @@ AST_MATCHER(CXXConstructorDecl, isInheritingConstructor) {
/// Matches if the given method or class declaration is final.
///
-/// Given:
+/// Given
/// \code
/// class A final {};
///
@@ -6358,7 +8351,13 @@ AST_MATCHER(CXXConstructorDecl, isInheritingConstructor) {
/// void f() final;
/// };
/// \endcode
-/// matches A and C::f, but not B, C, or B::f
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(isFinal())}
+/// matches \match{class A final {}},
+/// but does not match \nomatch{type=name$B} or \nomatch{type=name$C}.
+/// The matcher \matcher{cxxMethodDecl(isFinal())}
+/// matches \match{void f() final} in \c C ,
+/// but it does not match \nomatch{virtual void f()} in \c B .
AST_POLYMORPHIC_MATCHER(isFinal,
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl,
CXXMethodDecl)) {
@@ -6374,7 +8373,9 @@ AST_POLYMORPHIC_MATCHER(isFinal,
/// virtual void x() = 0;
/// };
/// \endcode
-/// matches A::x
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(isPure())}
+/// matches \match{virtual void x() = 0}
AST_MATCHER(CXXMethodDecl, isPure) { return Node.isPureVirtual(); }
/// Matches if the given method declaration is const.
@@ -6386,8 +8387,10 @@ AST_MATCHER(CXXMethodDecl, isPure) { return Node.isPureVirtual(); }
/// void bar();
/// };
/// \endcode
+/// \compile_args{-std=c++}
///
-/// cxxMethodDecl(isConst()) matches A::foo() but not A::bar()
+/// The matcher \matcher{cxxMethodDecl(isConst())}
+/// matches \match{void foo() const} but not \nomatch{void bar()}.
AST_MATCHER(CXXMethodDecl, isConst) {
return Node.isConst();
}
@@ -6402,9 +8405,11 @@ AST_MATCHER(CXXMethodDecl, isConst) {
/// A &operator=(A &&);
/// };
/// \endcode
+/// \compile_args{-std=c++}
///
-/// cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not
-/// the second one.
+/// The matcher \matcher{cxxMethodDecl(isCopyAssignmentOperator())}
+/// matches \match{A &operator=(const A &)}
+/// but does not match \nomatch{A &operator=(A &&)}
AST_MATCHER(CXXMethodDecl, isCopyAssignmentOperator) {
return Node.isCopyAssignmentOperator();
}
@@ -6419,9 +8424,11 @@ AST_MATCHER(CXXMethodDecl, isCopyAssignmentOperator) {
/// A &operator=(A &&);
/// };
/// \endcode
+/// \compile_args{-std=c++}
///
-/// cxxMethodDecl(isMoveAssignmentOperator()) matches the second method but not
-/// the first one.
+/// The matcher \matcher{cxxMethodDecl(isMoveAssignmentOperator())}
+/// matches \match{A &operator=(A &&)}
+/// but does not match \nomatch{A &operator=(const A &)}
AST_MATCHER(CXXMethodDecl, isMoveAssignmentOperator) {
return Node.isMoveAssignmentOperator();
}
@@ -6436,10 +8443,12 @@ AST_MATCHER(CXXMethodDecl, isMoveAssignmentOperator) {
/// };
/// class B : public A {
/// public:
-/// virtual void x();
+/// void x() override;
/// };
/// \endcode
-/// matches B::x
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxMethodDecl(isOverride())}
+/// matches \match{void x() override}
AST_MATCHER(CXXMethodDecl, isOverride) {
return Node.size_overridden_methods() > 0 || Node.hasAttr<OverrideAttr>();
}
@@ -6454,7 +8463,10 @@ AST_MATCHER(CXXMethodDecl, isOverride) {
/// S(S &&) = delete; // #3
/// };
/// \endcode
-/// cxxConstructorDecl(isUserProvided()) will match #1, but not #2 or #3.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(isUserProvided())}
+/// will match \match{S()}, but not \notmatch{S(const S &) = default} or
+/// \notmatch{S(S &&) = delete}
AST_MATCHER(CXXMethodDecl, isUserProvided) {
return Node.isUserProvided();
}
@@ -6474,15 +8486,26 @@ AST_MATCHER(CXXMethodDecl, isUserProvided) {
/// };
/// template <class T>
/// class Z {
-/// void x() { this->m; }
+/// void x() {
+/// this->m;
+/// this->t;
+/// this->t->m;
+/// }
+/// int m;
+/// T* t;
/// };
/// \endcode
-/// memberExpr(isArrow())
-/// matches this->x, x, y.x, a, this->b
-/// cxxDependentScopeMemberExpr(isArrow())
-/// matches this->m
-/// unresolvedMemberExpr(isArrow())
-/// matches this->f<T>, f<T>
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{memberExpr(isArrow())}
+/// matches \match{this->x}, \match{x}, \match{a},
+/// \match{this->b}, \match{this->m} and two times \match{count=2$this->t},
+/// once for the standalone member expression, and once for the member
+/// expression that later accesses \c m .
+/// Additionally, it does not match \nomatch{this->t->t}.
+/// The matcher \matcher{cxxDependentScopeMemberExpr(isArrow())}
+/// matches \match{this->t->m}, but not \nomatch{this->m} or \nomatch{this->t}.
+/// The matcher \matcher{unresolvedMemberExpr(isArrow())}
+/// matches \match{this->f<T>}, \match{f<T>}
AST_POLYMORPHIC_MATCHER(
isArrow, AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, UnresolvedMemberExpr,
CXXDependentScopeMemberExpr)) {
@@ -6497,8 +8520,8 @@ AST_POLYMORPHIC_MATCHER(
/// void b(long);
/// void c(double);
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isInteger())))
-/// matches "a(int)", "b(long)", but not "c(double)".
+/// The matcher \matcher{functionDecl(hasAnyParameter(hasType(isInteger())))}
+/// \match{void a(int)}, \match{void b(long)}, but not \nomatch{void c(double)}.
AST_MATCHER(QualType, isInteger) {
return Node->isIntegerType();
}
@@ -6511,8 +8534,10 @@ AST_MATCHER(QualType, isInteger) {
/// void b(unsigned long);
/// void c(double);
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isUnsignedInteger())))
-/// matches "b(unsigned long)", but not "a(int)" and "c(double)".
+/// The matcher
+/// \matcher{functionDecl(hasAnyParameter(hasType(isUnsignedInteger())))}
+/// matches \match{void b(unsigned long)},
+/// but it does not match \nomatch{void a(int)} and \nomatch{void c(double)}.
AST_MATCHER(QualType, isUnsignedInteger) {
return Node->isUnsignedIntegerType();
}
@@ -6525,8 +8550,10 @@ AST_MATCHER(QualType, isUnsignedInteger) {
/// void b(unsigned long);
/// void c(double);
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isSignedInteger())))
-/// matches "a(int)", but not "b(unsigned long)" and "c(double)".
+/// The matcher
+/// \matcher{functionDecl(hasAnyParameter(hasType(isSignedInteger())))} matches
+/// \match{void a(int)}, but not \notmatch{void b(unsigned long)} or
+/// \notmatch{void c(double)}.
AST_MATCHER(QualType, isSignedInteger) {
return Node->isSignedIntegerType();
}
@@ -6539,8 +8566,12 @@ AST_MATCHER(QualType, isSignedInteger) {
/// void b(wchar_t);
/// void c(double);
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isAnyCharacter())))
-/// matches "a(char)", "b(wchar_t)", but not "c(double)".
+/// \compile_args{-std=c++}
+///
+/// The matcher
+/// \matcher{functionDecl(hasAnyParameter(hasType(isAnyCharacter())))}
+/// \match{void a(char)}, \match{void b(wchar_t)}, but not
+/// \notmatch{void c(double)}.
AST_MATCHER(QualType, isAnyCharacter) {
return Node->isAnyCharacterType();
}
@@ -6559,8 +8590,9 @@ AST_MATCHER(QualType, isAnyCharacter) {
///
/// int j;
/// \endcode
-/// varDecl(hasType(isAnyPointer()))
-/// matches "int *i" and "Foo *f", but not "int j".
+/// \compile_args{-ObjC}
+/// The matcher \matcher{varDecl(hasType(isAnyPointer()))}
+/// \match{int *i} and \match{Foo *f}, but not \nomatch{int j}.
AST_MATCHER(QualType, isAnyPointer) {
return Node->isAnyPointerType();
}
@@ -6574,12 +8606,12 @@ AST_MATCHER(QualType, isAnyPointer) {
/// void b(int const);
/// void c(const int);
/// void d(const int*);
-/// void e(int const) {};
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isConstQualified())))
-/// matches "void b(int const)", "void c(const int)" and
-/// "void e(int const) {}". It does not match d as there
-/// is no top-level const on the parameter type "const int *".
+/// The matcher
+/// \matcher{functionDecl(hasAnyParameter(hasType(isConstQualified())))}
+/// matches \match{void b(int const)} and \match{void c(const int)}.
+/// It does not match \notmatch{void d(const int*)} as there
+/// is no top-level \c const on the parameter type \c{const int *}.
AST_MATCHER(QualType, isConstQualified) {
return Node.isConstQualified();
}
@@ -6593,12 +8625,12 @@ AST_MATCHER(QualType, isConstQualified) {
/// void b(int volatile);
/// void c(volatile int);
/// void d(volatile int*);
-/// void e(int volatile) {};
/// \endcode
-/// functionDecl(hasAnyParameter(hasType(isVolatileQualified())))
-/// matches "void b(int volatile)", "void c(volatile int)" and
-/// "void e(int volatile) {}". It does not match d as there
-/// is no top-level volatile on the parameter type "volatile int *".
+/// The matcher
+/// \matcher{functionDecl(hasAnyParameter(hasType(isVolatileQualified())))}
+/// matches \match{void b(int volatile)} and \match{void c(volatile int)}.
+/// It does not match \notmatch{void d(volatile int*)} as there
+/// is no top-level volatile on the parameter type "volatile int *".
AST_MATCHER(QualType, isVolatileQualified) {
return Node.isVolatileQualified();
}
@@ -6609,13 +8641,16 @@ AST_MATCHER(QualType, isVolatileQualified) {
/// Given
/// \code
/// typedef const int const_int;
-/// const_int i;
-/// int *const j;
+/// const_int i = 0;
+/// int *const j = nullptr;
/// int *volatile k;
/// int m;
/// \endcode
-/// \c varDecl(hasType(hasLocalQualifiers())) matches only \c j and \c k.
-/// \c i is const-qualified but the qualifier is not local.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{varDecl(hasType(hasLocalQualifiers()))} matches
+/// \match{int *const j = nullptr} and \match{int *volatile k},
+/// bot not \notmatch{const_int i} because the const qualifier is not local.
AST_MATCHER(QualType, hasLocalQualifiers) {
return Node.hasLocalQualifiers();
}
@@ -6625,13 +8660,15 @@ AST_MATCHER(QualType, hasLocalQualifiers) {
///
/// Given
/// \code
-/// struct { int first, second; } first, second;
-/// int i(second.first);
-/// int j(first.second);
+/// struct { int first = 0, second = 1; } first, second;
+/// int i = second.first;
+/// int j = first.second;
/// \endcode
-/// memberExpr(member(hasName("first")))
-/// matches second.first
-/// but not first.second (because the member name there is "second").
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{memberExpr(member(hasName("first")))}
+/// matches \match{second.first}
+/// but not \notmatch{first.second}.
AST_MATCHER_P(MemberExpr, member,
internal::Matcher<ValueDecl>, InnerMatcher) {
return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
@@ -6648,11 +8685,14 @@ AST_MATCHER_P(MemberExpr, member,
/// int f(X x) { x.m; return m; }
/// };
/// \endcode
-/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
-/// matches `x.m`, but not `m`; however,
-/// memberExpr(hasObjectExpression(hasType(pointsTo(
-// cxxRecordDecl(hasName("X"))))))
-/// matches `m` (aka. `this->m`), but not `x.m`.
+/// \compile_args{-std=c++}
+///
+/// The matcher
+/// \matcher{memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))}
+/// matches \match{x.m}, but not \nomatch{m}; however,
+/// The matcher \matcher{memberExpr(hasObjectExpression(hasType(pointsTo(
+/// cxxRecordDecl(hasName("X"))))))}
+/// matches \match{m} (aka. this->m), but not \nomatch{x.m}.
AST_POLYMORPHIC_MATCHER_P(
hasObjectExpression,
AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, UnresolvedMemberExpr,
@@ -6674,8 +8714,9 @@ AST_POLYMORPHIC_MATCHER_P(
/// namespace X { void b(); }
/// using X::b;
/// \endcode
-/// usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
-/// matches \code using X::b \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{usingDecl(hasAnyUsingShadowDecl(hasName("b")))}
+/// matches \match{using X::b}
AST_MATCHER_P(BaseUsingDecl, hasAnyUsingShadowDecl,
internal::Matcher<UsingShadowDecl>, InnerMatcher) {
return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(),
@@ -6692,9 +8733,11 @@ AST_MATCHER_P(BaseUsingDecl, hasAnyUsingShadowDecl,
/// using X::a;
/// using X::b;
/// \endcode
-/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
-/// matches \code using X::b \endcode
-/// but not \code using X::a \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))}
+/// matches \match{using X::b}
+/// but not \notmatch{using X::a}
AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
internal::Matcher<NamedDecl>, InnerMatcher) {
return InnerMatcher.matches(*Node.getTargetDecl(), Finder, Builder);
@@ -6705,26 +8748,44 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
///
/// Given
/// \code
-/// template <typename T> class X {}; class A {}; X<A> x;
+/// template <typename T> class X {};
+/// class A {};
+/// X<A> x;
/// \endcode
-/// or
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("::X"),
+/// isTemplateInstantiation())}
+/// matches \match{type=typestr$class X<class A>}.
/// \code
-/// template <typename T> class X {}; class A {}; template class X<A>;
+/// template <typename T> class X {};
+/// class A {};
+/// template class X<A>;
/// \endcode
-/// or
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("::X"),
+/// isTemplateInstantiation())}
+/// matches \match{template class X<A>}
/// \code
-/// template <typename T> class X {}; class A {}; extern template class X<A>;
+/// template <typename T> class X {};
+/// class A {};
+/// extern template class X<A>;
/// \endcode
-/// cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
-/// matches the template instantiation of X<A>.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("::X"),
+/// isTemplateInstantiation())}
+/// matches \match{extern template class X<A>}
///
/// But given
/// \code
-/// template <typename T> class X {}; class A {};
-/// template <> class X<A> {}; X<A> x;
+/// template <typename T> class X {};
+/// class A {};
+/// template <> class X<A> {};
+/// X<A> x;
/// \endcode
-/// cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
-/// does not match, as X<A> is an explicit template specialization.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("::X"),
+/// isTemplateInstantiation())}
+/// \nomatch{} does not match, as X<A> is an explicit template specialization.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
AST_POLYMORPHIC_MATCHER(isTemplateInstantiation,
@@ -6743,11 +8804,15 @@ AST_POLYMORPHIC_MATCHER(isTemplateInstantiation,
/// Given
/// \code
/// template<typename T> void A(T t) { T i; }
-/// A(0);
-/// A(0U);
+/// void foo() {
+/// A(0);
+/// A(0U);
+/// }
/// \endcode
-/// functionDecl(isInstantiated())
-/// matches 'A(int) {...};' and 'A(unsigned) {...}'.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{functionDecl(isInstantiated())}
+/// matches the two instantiations of \match{count=2$void A(T t) { T i; }} that
+/// are generated for \c int , and for \c{unsigned int}.
AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) {
auto IsInstantiation = decl(anyOf(cxxRecordDecl(isTemplateInstantiation()),
functionDecl(isTemplateInstantiation()),
@@ -6760,15 +8825,19 @@ AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) {
/// Given
/// \code
/// int j;
-/// template<typename T> void A(T t) { T i; j += 42;}
-/// A(0);
-/// A(0U);
-/// \endcode
-/// declStmt(isInTemplateInstantiation())
-/// matches 'int i;' and 'unsigned i'.
-/// unless(stmt(isInTemplateInstantiation()))
-/// will NOT match j += 42; as it's shared between the template definition and
-/// instantiation.
+/// template<typename T> void A(T t) { T i; }
+/// void foo() {
+/// A(0);
+/// A(0U);
+/// }
+/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{declStmt(isInTemplateInstantiation())}
+/// matches \match{count=2$T i;} twice, once for \c int and once for
+/// \c{unsigned int}.
+/// The matcher \matcher{declStmt(unless(isInTemplateInstantiation()))} will
+/// match \match{T i;} once inside the template definition, but not for any of
+/// the instantiated bodies.
AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) {
return stmt(hasAncestor(decl(anyOf(cxxRecordDecl(isTemplateInstantiation()),
functionDecl(isTemplateInstantiation()),
@@ -6783,8 +8852,9 @@ AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) {
/// template<typename T> void A(T t) { }
/// template<> void A(int N) { }
/// \endcode
-/// functionDecl(isExplicitTemplateSpecialization())
-/// matches the specialization A<int>().
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{functionDecl(isExplicitTemplateSpecialization())}
+/// matches the specialization \match{template<> void A(int N) { }}.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization,
@@ -6795,6 +8865,13 @@ AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization,
/// Matches \c TypeLocs for which the given inner
/// QualType-matcher matches.
+///
+/// \code
+/// int a = 10;
+/// \endcode
+///
+/// The matcher \matcher{typeLoc(loc(qualType(isInteger())))}
+/// matches the \match{int} of \c a .
AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
internal::Matcher<QualType>, InnerMatcher, 0) {
return internal::BindableMatcher<TypeLoc>(
@@ -6807,8 +8884,11 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
/// \code
/// const int x = 0;
/// \endcode
-/// qualifiedTypeLoc()
-/// matches `const int`.
+///
+/// The matcher \matcher{qualifiedTypeLoc()}
+/// matches the type of the variable declaration \c x . However, the
+/// current implementation of \c QualifiedTypeLoc does not store the source
+/// locations for the qualifiers of the type \match{int}.
extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, QualifiedTypeLoc>
qualifiedTypeLoc;
@@ -6817,11 +8897,14 @@ extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, QualifiedTypeLoc>
///
/// Given
/// \code
-/// int* const x;
-/// const int y;
+/// int* const x = nullptr;
+/// const int y = 0;
/// \endcode
-/// qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc()))
-/// matches the `TypeLoc` of the variable declaration of `x`, but not `y`.
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+///
+/// The matcher \matcher{qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc()))}
+/// matches the type \match{int*} of the variable declaration \c{x}, but
+/// not \c{y}.
AST_MATCHER_P(QualifiedTypeLoc, hasUnqualifiedLoc, internal::Matcher<TypeLoc>,
InnerMatcher) {
return InnerMatcher.matches(Node.getUnqualifiedLoc(), Finder, Builder);
@@ -6834,8 +8917,11 @@ AST_MATCHER_P(QualifiedTypeLoc, hasUnqualifiedLoc, internal::Matcher<TypeLoc>,
/// int f() { return 5; }
/// void g() {}
/// \endcode
-/// functionDecl(hasReturnTypeLoc(loc(asString("int"))))
-/// matches the declaration of `f`, but not `g`.
+/// The matcher
+/// \matcher{functionDecl(hasReturnTypeLoc(typeLoc(loc(asString("int")))))}
+/// matches the declaration of \match{int f() { return 5; }} with
+/// \matcher{type=sub$typeLoc(loc(asString("int")))} matching the spelling of
+/// \match{sub=loc$int}, but the matcher does not match \notmatch{void g() {}}.
AST_MATCHER_P(FunctionDecl, hasReturnTypeLoc, internal::Matcher<TypeLoc>,
ReturnMatcher) {
auto Loc = Node.getFunctionTypeLoc();
@@ -6848,8 +8934,8 @@ AST_MATCHER_P(FunctionDecl, hasReturnTypeLoc, internal::Matcher<TypeLoc>,
/// \code
/// int* x;
/// \endcode
-/// pointerTypeLoc()
-/// matches `int*`.
+/// The matcher \matcher{pointerTypeLoc()}
+/// matches \match{int*}.
extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, PointerTypeLoc>
pointerTypeLoc;
@@ -6860,8 +8946,8 @@ extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, PointerTypeLoc>
/// \code
/// int* x;
/// \endcode
-/// pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))
-/// matches `int*`.
+/// The matcher \matcher{pointerTypeLoc(hasPointeeLoc(loc(asString("int"))))}
+/// matches \match{int*}.
AST_MATCHER_P(PointerTypeLoc, hasPointeeLoc, internal::Matcher<TypeLoc>,
PointeeMatcher) {
return PointeeMatcher.matches(Node.getPointeeLoc(), Finder, Builder);
@@ -6875,8 +8961,10 @@ AST_MATCHER_P(PointerTypeLoc, hasPointeeLoc, internal::Matcher<TypeLoc>,
/// int& l = x;
/// int&& r = 3;
/// \endcode
-/// referenceTypeLoc()
-/// matches `int&` and `int&&`.
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{referenceTypeLoc()}
+/// matches \match{int&} and \match{int&&}.
extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ReferenceTypeLoc>
referenceTypeLoc;
@@ -6888,8 +8976,10 @@ extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ReferenceTypeLoc>
/// int x = 3;
/// int& xx = x;
/// \endcode
-/// referenceTypeLoc(hasReferentLoc(loc(asString("int"))))
-/// matches `int&`.
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{referenceTypeLoc(hasReferentLoc(loc(asString("int"))))}
+/// matches \match{int&}.
AST_MATCHER_P(ReferenceTypeLoc, hasReferentLoc, internal::Matcher<TypeLoc>,
ReferentMatcher) {
return ReferentMatcher.matches(Node.getPointeeLoc(), Finder, Builder);
@@ -6902,8 +8992,11 @@ AST_MATCHER_P(ReferenceTypeLoc, hasReferentLoc, internal::Matcher<TypeLoc>,
/// template <typename T> class C {};
/// C<char> var;
/// \endcode
-/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc())))
-/// matches `C<char> var`.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+/// templateSpecializationTypeLoc(typeLoc())))))}
+/// matches \match{C<char> var}.
extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
@@ -6918,9 +9011,11 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// template<typename T> class A {};
/// A<int> a;
/// \endcode
-/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
-/// hasTypeLoc(loc(asString("int")))))))
-/// matches `A<int> a`.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+/// templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+/// hasTypeLoc(loc(asString("int")))))))))} matches \match{A<int> a}.
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -6943,9 +9038,12 @@ AST_POLYMORPHIC_MATCHER_P(
/// 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`.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
+/// templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+/// hasTypeLoc(loc(asString("double")))))))))}
+/// matches \match{A<double, int> b}, but not \notmatch{A<int, double> c}.
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
@@ -6964,8 +9062,8 @@ AST_POLYMORPHIC_MATCHER_P2(
/// struct s {};
/// struct s ss;
/// \endcode
-/// elaboratedTypeLoc()
-/// matches the `TypeLoc` of the variable declaration of `ss`.
+/// The matcher \matcher{elaboratedTypeLoc()}
+/// matches the type \match{struct s} of \c ss.
extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>
elaboratedTypeLoc;
@@ -6981,8 +9079,10 @@ extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>
/// class D {};
/// class D d;
/// \endcode
-/// elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc()));
-/// matches the `TypeLoc` of the variable declaration of `c`, but not `d`.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc()))}
+/// matches \match{class C<int>}, but not \notmatch{ckass D}
AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, internal::Matcher<TypeLoc>,
InnerMatcher) {
return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder);
@@ -6994,8 +9094,9 @@ AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, internal::Matcher<TypeLoc>,
/// \code
/// struct S { bool func(); };
/// \endcode
-/// functionDecl(returns(booleanType()))
-/// matches "bool func();"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(returns(booleanType()))}
+/// \match{bool func()}.
AST_MATCHER(Type, booleanType) {
return Node.isBooleanType();
}
@@ -7006,8 +9107,10 @@ AST_MATCHER(Type, booleanType) {
/// \code
/// struct S { void func(); };
/// \endcode
-/// functionDecl(returns(voidType()))
-/// matches "void func();"
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{functionDecl(returns(voidType()))}
+/// \match{void func()}.
AST_MATCHER(Type, voidType) {
return Node.isVoidType();
}
@@ -7019,14 +9122,13 @@ using AstTypeMatcher = internal::VariadicDynCastAllOfMatcher<Type, NodeType>;
///
/// Given
/// \code
-/// struct A {};
-/// A a;
+/// enum E { Ok };
+/// enum E e;
/// int b;
/// float c;
-/// bool d;
/// \endcode
-/// builtinType()
-/// matches "int b", "float c" and "bool d"
+/// The matcher \matcher{varDecl(hasType(builtinType()))}
+/// matches \match{int b} and \match{float c}.
extern const AstTypeMatcher<BuiltinType> builtinType;
/// Matches all kinds of arrays.
@@ -7037,8 +9139,9 @@ extern const AstTypeMatcher<BuiltinType> builtinType;
/// int b[4];
/// void f() { int c[a[0]]; }
/// \endcode
-/// arrayType()
-/// matches "int a[]", "int b[4]" and "int c[a[0]]";
+/// The matcher \matcher{arrayType()}
+/// \match{type=typestr$int[4]}, \match{type=typestr$int[a[0]]} and
+/// \match{type=typestr$int[]};
extern const AstTypeMatcher<ArrayType> arrayType;
/// Matches C99 complex types.
@@ -7047,8 +9150,8 @@ extern const AstTypeMatcher<ArrayType> arrayType;
/// \code
/// _Complex float f;
/// \endcode
-/// complexType()
-/// matches "_Complex float f"
+/// The matcher \matcher{complexType()}
+/// \match{type=typestr$_Complex float}
extern const AstTypeMatcher<ComplexType> complexType;
/// Matches any real floating-point type (float, double, long double).
@@ -7058,8 +9161,9 @@ extern const AstTypeMatcher<ComplexType> complexType;
/// int i;
/// float f;
/// \endcode
-/// realFloatingPointType()
-/// matches "float f" but not "int i"
+/// The matcher \matcher{type(realFloatingPointType())}
+/// matches \match{type=typestr$float}
+/// but does not match \nomatch{type=typestr$int}.
AST_MATCHER(Type, realFloatingPointType) {
return Node.isRealFloatingType();
}
@@ -7073,8 +9177,10 @@ AST_MATCHER(Type, realFloatingPointType) {
/// A a[7];
/// int b[7];
/// \endcode
-/// arrayType(hasElementType(builtinType()))
-/// matches "int b[7]"
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{arrayType(hasElementType(builtinType()))}
+/// \match{type=typestr$int[7]}
///
/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasElementType, getElement,
@@ -7085,14 +9191,14 @@ AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasElementType, getElement,
///
/// Given
/// \code
-/// void() {
+/// void foo() {
/// int a[2];
/// int b[] = { 2, 3 };
/// int c[b[0]];
/// }
/// \endcode
-/// constantArrayType()
-/// matches "int a[2]"
+/// The matcher \matcher{constantArrayType()}
+/// \match{type=typestr$int[2]}
extern const AstTypeMatcher<ConstantArrayType> constantArrayType;
/// Matches nodes that have the specified size.
@@ -7106,10 +9212,11 @@ extern const AstTypeMatcher<ConstantArrayType> constantArrayType;
/// wchar_t *ws = L"abcd";
/// char *w = "a";
/// \endcode
-/// constantArrayType(hasSize(42))
-/// matches "int a[42]" and "int b[2 * 21]"
-/// stringLiteral(hasSize(4))
-/// matches "abcd", L"abcd"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{constantArrayType(hasSize(42))}
+/// matches \match{type=typestr;count=2$int[42]} twice.
+/// The matcher \matcher{stringLiteral(hasSize(4))}
+/// matches \match{"abcd"} and \match{L"abcd"}.
AST_POLYMORPHIC_MATCHER_P(hasSize,
AST_POLYMORPHIC_SUPPORTED_TYPES(ConstantArrayType,
StringLiteral),
@@ -7126,8 +9233,9 @@ AST_POLYMORPHIC_MATCHER_P(hasSize,
/// T data[Size];
/// };
/// \endcode
-/// dependentSizedArrayType()
-/// matches "T data[Size]"
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{dependentSizedArrayType()}
+/// \match{type=typestr$T[Size]}
extern const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType;
/// Matches C++ extended vector type where either the type or size is
@@ -7140,8 +9248,9 @@ extern const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType;
/// typedef T __attribute__((ext_vector_type(Size))) type;
/// };
/// \endcode
-/// dependentSizedExtVectorType()
-/// matches "T __attribute__((ext_vector_type(Size)))"
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{dependentSizedExtVectorType()}
+/// \match{type=typestr$T __attribute__((ext_vector_type(Size)))}
extern const AstTypeMatcher<DependentSizedExtVectorType>
dependentSizedExtVectorType;
@@ -7153,8 +9262,8 @@ extern const AstTypeMatcher<DependentSizedExtVectorType>
/// int b[42];
/// void f(int c[]) { int d[a[0]]; };
/// \endcode
-/// incompleteArrayType()
-/// matches "int a[]" and "int c[]"
+/// The matcher \matcher{incompleteArrayType()}
+/// \match{type=typestr$int[]} and \match{type=typestr$int[]}
extern const AstTypeMatcher<IncompleteArrayType> incompleteArrayType;
/// Matches C arrays with a specified size that is not an
@@ -7163,13 +9272,13 @@ extern const AstTypeMatcher<IncompleteArrayType> incompleteArrayType;
/// Given
/// \code
/// void f() {
-/// int a[] = { 2, 3 }
+/// int a[] = { 2, 3 };
/// int b[42];
/// int c[a[0]];
/// }
/// \endcode
-/// variableArrayType()
-/// matches "int c[a[0]]"
+/// The matcher \matcher{variableArrayType()}
+/// \match{type=typestr$int[a[0]]}
extern const AstTypeMatcher<VariableArrayType> variableArrayType;
/// Matches \c VariableArrayType nodes that have a specific size
@@ -7181,9 +9290,10 @@ extern const AstTypeMatcher<VariableArrayType> variableArrayType;
/// int a[b];
/// }
/// \endcode
-/// variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
-/// varDecl(hasName("b")))))))
-/// matches "int a[b]"
+/// The matcher
+/// \matcher{variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+/// varDecl(hasName("b")))))))}
+/// matches \match{type=typestr$int[b]}
AST_MATCHER_P(VariableArrayType, hasSizeExpr,
internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.getSizeExpr(), Finder, Builder);
@@ -7195,8 +9305,8 @@ AST_MATCHER_P(VariableArrayType, hasSizeExpr,
/// \code
/// _Atomic(int) i;
/// \endcode
-/// atomicType()
-/// matches "_Atomic(int) i"
+/// The matcher \matcher{atomicType()}
+/// \match{type=typestr$_Atomic(int)}
extern const AstTypeMatcher<AtomicType> atomicType;
/// Matches atomic types with a specific value type.
@@ -7206,8 +9316,8 @@ extern const AstTypeMatcher<AtomicType> atomicType;
/// _Atomic(int) i;
/// _Atomic(float) f;
/// \endcode
-/// atomicType(hasValueType(isInteger()))
-/// matches "_Atomic(int) i"
+/// The matcher \matcher{atomicType(hasValueType(isInteger()))}
+/// \match{type=typestr$_Atomic(int)}.
///
/// Usable as: Matcher<AtomicType>
AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasValueType, getValue,
@@ -7215,26 +9325,32 @@ AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasValueType, getValue,
/// Matches types nodes representing C++11 auto types.
///
-/// Given:
+/// Given
/// \code
-/// auto n = 4;
-/// int v[] = { 2, 3 }
-/// for (auto i : v) { }
+/// void foo() {
+/// auto n = 4;
+/// int v[] = { 2, 3 };
+/// for (auto i : v) { };
+/// }
/// \endcode
-/// autoType()
-/// matches "auto n" and "auto i"
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{autoType()}
+/// matches the \match{type=typestr;count=5$auto} of \c n and \c i ,
+/// as well as the auto types for the implicitly generated code of the range-for
+/// loop (for the range, the begin iterator and the end iterator).
extern const AstTypeMatcher<AutoType> autoType;
/// Matches types nodes representing C++11 decltype(<expr>) types.
///
-/// Given:
+/// Given
/// \code
/// short i = 1;
/// int j = 42;
/// decltype(i + j) result = i + j;
/// \endcode
-/// decltypeType()
-/// matches "decltype(i + j)"
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{decltypeType()}
+/// \match{type=typestr$decltype(i + j)}
extern const AstTypeMatcher<DecltypeType> decltypeType;
/// Matches \c AutoType nodes where the deduced type is a specific type.
@@ -7247,8 +9363,10 @@ extern const AstTypeMatcher<DecltypeType> decltypeType;
/// auto a = 1;
/// auto b = 2.0;
/// \endcode
-/// autoType(hasDeducedType(isInteger()))
-/// matches "auto a"
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{varDecl(hasType(autoType(hasDeducedType(isInteger()))))}
+/// matches \match{auto a = 1}, but does not match \nomatch{auto b = 2.0}.
///
/// Usable as: Matcher<AutoType>
AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
@@ -7261,8 +9379,11 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
/// decltype(1) a = 1;
/// decltype(2.0) b = 2.0;
/// \endcode
-/// decltypeType(hasUnderlyingType(isInteger()))
-/// matches the type of "a"
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{decltypeType(hasUnderlyingType(isInteger()))}
+/// matches the type \match{type=typestr$decltype(1)} of the variable
+/// declaration of \c a .
///
/// Usable as: Matcher<DecltypeType>, Matcher<UsingType>
AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType,
@@ -7276,8 +9397,12 @@ AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType,
/// int (*f)(int);
/// void g();
/// \endcode
-/// functionType()
-/// matches "int (*f)(int)" and the type of "g".
+/// The matcher \matcher{functionType()}
+/// \match{type=typestr$int (int)} and the type of
+/// \match{std=c++,c23-or-later;type=typestr$void (void)} in C++ and in C23 and
+/// later. Before C23, the function type for \c f will be matched the same way,
+/// but the function type for \c g will match
+/// \match{std=c17-or-earlier;type=typestr$void ()}.
extern const AstTypeMatcher<FunctionType> functionType;
/// Matches \c FunctionProtoType nodes.
@@ -7287,9 +9412,11 @@ extern const AstTypeMatcher<FunctionType> functionType;
/// int (*f)(int);
/// void g();
/// \endcode
-/// functionProtoType()
-/// matches "int (*f)(int)" and the type of "g" in C++ mode.
-/// In C mode, "g" is not matched because it does not contain a prototype.
+/// The matcher \matcher{functionProtoType()}
+/// matches the type \match{type=typestr$int (int)} of 'f' and the type
+/// \match{std=c++,c23-or-later;type=typestr$void (void)} of 'g' in C++ mode.
+/// In C, the type \nomatch{std=c;type=typestr$void ()} of 'g' is not
+/// matched because it does not contain a prototype.
extern const AstTypeMatcher<FunctionProtoType> functionProtoType;
/// Matches \c ParenType nodes.
@@ -7300,8 +9427,9 @@ extern const AstTypeMatcher<FunctionProtoType> functionProtoType;
/// int *array_of_ptrs[4];
/// \endcode
///
-/// \c varDecl(hasType(pointsTo(parenType()))) matches \c ptr_to_array but not
-/// \c array_of_ptrs.
+/// The matcher \matcher{varDecl(hasType(pointsTo(parenType())))}
+/// matches \match{int (*ptr_to_array)[4]}, but not
+/// \nomatch{int *array_of_ptrs[4]}.
extern const AstTypeMatcher<ParenType> parenType;
/// Matches \c ParenType nodes where the inner type is a specific type.
@@ -7312,8 +9440,10 @@ extern const AstTypeMatcher<ParenType> parenType;
/// int (*ptr_to_func)(int);
/// \endcode
///
-/// \c varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
-/// \c ptr_to_func but not \c ptr_to_array.
+/// The matcher
+/// \matcher{varDecl(hasType(pointsTo(parenType(innerType(functionType())))))}
+/// matches \match{int (*ptr_to_func)(int)} but not
+/// \nomatch{int (*ptr_to_array)[4]}.
///
/// Usable as: Matcher<ParenType>
AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType,
@@ -7328,11 +9458,12 @@ extern const AstTypeMatcher<BlockPointerType> blockPointerType;
/// Matches member pointer types.
/// Given
/// \code
-/// struct A { int i; }
-/// A::* ptr = A::i;
+/// struct A { int i; };
+/// int A::* ptr = &A::i;
/// \endcode
-/// memberPointerType()
-/// matches "A::* ptr"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{memberPointerType()}
+/// matches \match{type=typestr$int struct A::*}.
extern const AstTypeMatcher<MemberPointerType> memberPointerType;
/// Matches pointer types, but does not match Objective-C object pointer
@@ -7340,16 +9471,24 @@ extern const AstTypeMatcher<MemberPointerType> memberPointerType;
///
/// Given
/// \code
-/// int *a;
-/// int &b = *a;
-/// int c = 5;
+/// typedef int* int_ptr;
+/// void foo(char *str,
+/// int val,
+/// int *val_ptr,
+/// int_ptr not_a_ptr,
+/// int_ptr *ptr);
+/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{parmVarDecl(hasType(pointerType()))}
+/// matches \match{char *str}, \match{int *val_ptr} and
+/// \match{int_ptr *ptr}.
///
+/// \code
/// @interface Foo
/// @end
/// Foo *f;
/// \endcode
-/// pointerType()
-/// matches "int *a", but does not match "Foo *f".
+/// \compile_args{-ObjC}
extern const AstTypeMatcher<PointerType> pointerType;
/// Matches an Objective-C object pointer type, which is
diff erent from
@@ -7363,8 +9502,10 @@ extern const AstTypeMatcher<PointerType> pointerType;
/// @end
/// Foo *f;
/// \endcode
-/// pointerType()
-/// matches "Foo *f", but does not match "int *a".
+/// \compile_args{-ObjC}
+/// The matcher \matcher{pointerType()}
+/// matches \match{type=typestr$Foo *}, but does not match
+/// \nomatch{type=typestr$int *}.
extern const AstTypeMatcher<ObjCObjectPointerType> objcObjectPointerType;
/// Matches both lvalue and rvalue reference types.
@@ -7379,13 +9520,18 @@ extern const AstTypeMatcher<ObjCObjectPointerType> objcObjectPointerType;
/// auto &&f = 2;
/// int g = 5;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c referenceType() matches the types of \c b, \c c, \c d, \c e, and \c f.
+/// The matcher \matcher{referenceType()} matches the type
+/// \match{type=typestr$int &} of \c b , the type \match{type=typestr$int &&} of
+/// \c c, the type
+/// \match{type=typestr$auto &} \c d, and the type
+/// \match{type=typestr;count=2$auto &&} of \c e and \c f.
extern const AstTypeMatcher<ReferenceType> referenceType;
/// Matches lvalue reference types.
///
-/// Given:
+/// Given
/// \code
/// int *a;
/// int &b = *a;
@@ -7395,14 +9541,17 @@ extern const AstTypeMatcher<ReferenceType> referenceType;
/// auto &&f = 2;
/// int g = 5;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c lValueReferenceType() matches the types of \c b, \c d, and \c e. \c e is
-/// matched since the type is deduced as int& by reference collapsing rules.
+/// The matcher \matcher{lValueReferenceType()} matches the type
+/// \match{type=typestr$int &} of \c b and the type \match{type=typestr$auto &}
+/// of \c d.
+/// FIXME: figure out why auto changechange matches twice
extern const AstTypeMatcher<LValueReferenceType> lValueReferenceType;
/// Matches rvalue reference types.
///
-/// Given:
+/// Given
/// \code
/// int *a;
/// int &b = *a;
@@ -7412,9 +9561,11 @@ extern const AstTypeMatcher<LValueReferenceType> lValueReferenceType;
/// auto &&f = 2;
/// int g = 5;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c rValueReferenceType() matches the types of \c c and \c f. \c e is not
-/// matched as it is deduced to int& by reference collapsing rules.
+/// The matcher \matcher{rValueReferenceType()} matches the type
+/// \match{type=typestr$int &&} of \c c and the type
+/// \match{type=typestr;count=2$auto &&} of \c e and \c f.
extern const AstTypeMatcher<RValueReferenceType> rValueReferenceType;
/// Narrows PointerType (and similar) matchers to those where the
@@ -7423,11 +9574,15 @@ extern const AstTypeMatcher<RValueReferenceType> rValueReferenceType;
/// Given
/// \code
/// int *a;
-/// int const *b;
-/// float const *f;
+/// const int *b;
+/// int * const c = nullptr;
+/// const float *f;
/// \endcode
-/// pointerType(pointee(isConstQualified(), isInteger()))
-/// matches "int const *b"
+/// \compile_args{-std=c++11-or-later,c23-or-later}
+/// The matcher \matcher{pointerType(pointee(isConstQualified(), isInteger()))}
+/// matches \match{type=typestr$const int *},
+/// but does not match \nomatch{type=typestr$int * const}
+/// or \nomatch{type=typestr$const float *}.
///
/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
/// Matcher<PointerType>, Matcher<ReferenceType>
@@ -7441,9 +9596,10 @@ AST_TYPELOC_TRAVERSE_MATCHER_DECL(
/// Given
/// \code
/// typedef int X;
+/// X x = 0;
/// \endcode
-/// typedefType()
-/// matches "typedef int X"
+/// The matcher \matcher{typedefType()}
+/// matches \match{type=typestr$X}.
extern const AstTypeMatcher<TypedefType> typedefType;
/// Matches qualified types when the qualifier is applied via a macro.
@@ -7454,8 +9610,12 @@ extern const AstTypeMatcher<TypedefType> typedefType;
/// typedef void (CDECL *X)();
/// typedef void (__attribute__((cdecl)) *Y)();
/// \endcode
-/// macroQualifiedType()
-/// matches the type of the typedef declaration of \c X but not \c Y.
+/// The matcher \matcher{macroQualifiedType()}
+/// matches the type \match{type=typestr;std=c++,c23-or-later$CDECL void
+/// (void)} of the typedef declaration of \c X , unless when in C98-C17, there
+/// \match{type=typestr;std=c17-or-earlier$CDECL void ()},
+/// but it does not match the type
+/// \nomatch{type=typestr$__attribute((cdecl)) void ()} of \c Y .
extern const AstTypeMatcher<MacroQualifiedType> macroQualifiedType;
/// Matches enum types.
@@ -7468,9 +9628,11 @@ extern const AstTypeMatcher<MacroQualifiedType> macroQualifiedType;
/// C c;
/// S s;
/// \endcode
-//
-/// \c enumType() matches the type of the variable declarations of both \c c and
-/// \c s.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{enumType()} matches the type
+/// \match{type=typestr$enum C} of \c c ,
+/// and the type \match{type=typestr$enum S} of \c s .
extern const AstTypeMatcher<EnumType> enumType;
/// Matches template specialization types.
@@ -7480,12 +9642,16 @@ extern const AstTypeMatcher<EnumType> enumType;
/// template <typename T>
/// class C { };
///
-/// template class C<int>; // A
-/// C<char> var; // B
+/// template class C<int>;
+/// C<int> intvar;
+/// C<char> charvar;
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
///
-/// \c templateSpecializationType() matches the type of the explicit
-/// instantiation in \c A and the type of the variable declaration in \c B.
+/// The matcher \matcher{templateSpecializationType()} matches the type
+/// \match{type=typestr$C<int>} of the explicit instantiation in \c A and the
+/// type \match{type=typestr$C<char>} of the variable declaration in
+/// \c B.
extern const AstTypeMatcher<TemplateSpecializationType>
templateSpecializationType;
@@ -7499,19 +9665,23 @@ extern const AstTypeMatcher<TemplateSpecializationType>
///
/// C c(123);
/// \endcode
-/// \c deducedTemplateSpecializationType() matches the type in the declaration
-/// of the variable \c c.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++17-or-later}
+/// The matcher \matcher{deducedTemplateSpecializationType()} matches the type
+/// \match{type=typestr$C} of the declaration of the variable \c c.
extern const AstTypeMatcher<DeducedTemplateSpecializationType>
deducedTemplateSpecializationType;
/// Matches types nodes representing unary type transformations.
///
-/// Given:
+/// Given
/// \code
-/// typedef __underlying_type(T) type;
+/// template <typename T> struct A {
+/// typedef __underlying_type(T) type;
+/// };
/// \endcode
-/// unaryTransformType()
-/// matches "__underlying_type(T)"
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{unaryTransformType()}
+/// matches \match{type=typestr$__underlying_type(T)}
extern const AstTypeMatcher<UnaryTransformType> unaryTransformType;
/// Matches record types (e.g. structs, classes).
@@ -7524,24 +9694,34 @@ extern const AstTypeMatcher<UnaryTransformType> unaryTransformType;
/// C c;
/// S s;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c recordType() matches the type of the variable declarations of both \c c
-/// and \c s.
+/// The matcher \matcher{recordType()} matches the type
+/// \match{type=typestr;count=3$class C} of the variable declaration of \c c and
+/// matches the type \match{type=typestr;count=3$struct S} of the variable
+/// declaration of \c s.
+/// Both of these types are matched three times, once for the type of the
+/// variable, once for the definition of the class, and once for the type of the
+/// implicit class declaration.
extern const AstTypeMatcher<RecordType> recordType;
/// Matches tag types (record and enum types).
///
/// Given
/// \code
-/// enum E {};
+/// enum E { Ok };
/// class C {};
///
/// E e;
/// C c;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c tagType() matches the type of the variable declarations of both \c e
-/// and \c c.
+/// The matcher \matcher{tagType()} matches the type
+/// \match{type=typestr$enum E} of variable \c e and the type
+/// \match{type=typestr;count=3;std=c++$class C} three times, once for the type
+/// of the variable \c c , once for the type of the class definition and once of
+/// the type in the implicit class declaration.
extern const AstTypeMatcher<TagType> tagType;
/// Matches types specified with an elaborated type keyword or with a
@@ -7556,16 +9736,22 @@ extern const AstTypeMatcher<TagType> tagType;
/// }
/// class C {};
///
-/// class C c;
+/// C c;
/// N::M::D d;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c elaboratedType() matches the type of the variable declarations of both
-/// \c c and \c d.
+/// The matcher \matcher{elaboratedType()} matches the type
+/// \match{type=typestr;count=3$C} three times. Once for the type of the
+/// variable \c c, once for the type of the class definition and once for the
+/// type in the implicit class declaration. For \c{class D}, it matches
+/// \match{type=typestr$N::M::D} of variable \c d and its class definition and
+/// implicit class declaration \match{type=typestr;count=2$D} one time
+/// respectively.
extern const AstTypeMatcher<ElaboratedType> elaboratedType;
/// Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-/// matches \c InnerMatcher if the qualifier exists.
+/// matches \c InnerMatcher if the qualifier exists.
///
/// Given
/// \code
@@ -7576,9 +9762,12 @@ extern const AstTypeMatcher<ElaboratedType> elaboratedType;
/// }
/// N::M::D d;
/// \endcode
+/// \compile_args{-std=c++}
///
-/// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
-/// matches the type of the variable declaration of \c d.
+/// The matcher
+/// \matcher{elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))))}
+/// matches the type \match{type=typestr$N::M::D} of the variable declaration
+/// of \c d.
AST_MATCHER_P(ElaboratedType, hasQualifier,
internal::Matcher<NestedNameSpecifier>, InnerMatcher) {
if (const NestedNameSpecifier *Qualifier = Node.getQualifier())
@@ -7593,15 +9782,15 @@ AST_MATCHER_P(ElaboratedType, hasQualifier,
/// \code
/// namespace N {
/// namespace M {
-/// class D {};
+/// enum E { Ok };
/// }
/// }
-/// N::M::D d;
+/// N::M::E e = N::M::Ok;
/// \endcode
+/// \compile_args{-std=c++}
///
-/// \c elaboratedType(namesType(recordType(
-/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
-/// declaration of \c d.
+/// The matcher \matcher{elaboratedType(namesType(enumType()))}
+/// matches the type \match{type=typestr$N::M::E} of the declaration of \c e .
AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
InnerMatcher) {
return InnerMatcher.matches(Node.getNamedType(), Finder, Builder);
@@ -7615,8 +9804,10 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
/// using a::S;
/// S s;
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// \c usingType() matches the type of the variable declaration of \c s.
+/// The matcher \matcher{usingType()} matches the type \match{type=typestr$a::S}
+/// of the variable declaration of \c s.
extern const AstTypeMatcher<UsingType> usingType;
/// Matches types that represent the result of substituting a type for a
@@ -7626,11 +9817,18 @@ extern const AstTypeMatcher<UsingType> usingType;
/// \code
/// template <typename T>
/// void F(T t) {
+/// T local;
/// int i = 1 + t;
/// }
+/// void f() {
+/// F(0);
+/// }
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
///
-/// \c substTemplateTypeParmType() matches the type of 't' but not '1'
+/// The matcher \matcher{varDecl(hasType(substTemplateTypeParmType()))}
+/// matches \match{T t} and \match{T local} for the substituted template type
+/// \c int in the instantiation of \c F .
extern const AstTypeMatcher<SubstTemplateTypeParmType>
substTemplateTypeParmType;
@@ -7644,46 +9842,67 @@ extern const AstTypeMatcher<SubstTemplateTypeParmType>
/// int i;
/// double j = F(i);
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
///
-/// \c substTemplateTypeParmType(hasReplacementType(type())) matches int
+/// The matcher \matcher{substTemplateTypeParmType(hasReplacementType(type()))}
+/// matches \match{type=typestr$int}.
AST_TYPE_TRAVERSE_MATCHER(
hasReplacementType, getReplacementType,
AST_POLYMORPHIC_SUPPORTED_TYPES(SubstTemplateTypeParmType));
/// Matches template type parameter types.
///
-/// Example matches T, but not int.
-/// (matcher = templateTypeParmType())
+/// Given
/// \code
/// template <typename T> void f(int i);
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher \matcher{templateTypeParmType()} matches \match{type=typestr$T},
+/// but does not match \nomatch{type=typestr$int}.
extern const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType;
/// Matches injected class name types.
///
-/// Example matches S s, but not S<T> s.
-/// (matcher = parmVarDecl(hasType(injectedClassNameType())))
+/// Given
/// \code
/// template <typename T> struct S {
/// void f(S s);
/// void g(S<T> s);
/// };
/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++}
+/// The matcher
+/// \matcher{parmVarDecl(hasType(elaboratedType(namesType(injectedClassNameType()))))}
+/// matches \match{S s}, but not \notmatch{S<T> s}
extern const AstTypeMatcher<InjectedClassNameType> injectedClassNameType;
/// Matches decayed type
-/// Example matches i[] in declaration of f.
-/// (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
-/// Example matches i[1].
-/// (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
/// \code
/// void f(int i[]) {
/// i[1] = 0;
/// }
/// \endcode
+/// The matcher
+/// \matcher{valueDecl(hasType(decayedType(hasDecayedType(pointerType()))))}
+/// matches \match{int i[]} in declaration of \c{f}.
+/// The matcher
+/// \matcher{expr(hasType(decayedType(hasDecayedType(pointerType()))))}
+/// matches \match{count=2$i} twice, once for the \c DeclRefExpr and oncde for
+/// the cast from an l- to an r-value in \c{i[1]}.
+///
extern const AstTypeMatcher<DecayedType> decayedType;
/// Matches the decayed type, whoes decayed type matches \c InnerMatcher
+///
+/// Given
+/// \code
+/// void f(int i[]) {
+/// i[1] = 0;
+/// }
+/// \endcode
+///
+/// The matcher \matcher{parmVarDecl(hasType(decayedType()))}
+/// matches \match{int i[]}.
AST_MATCHER_P(DecayedType, hasDecayedType, internal::Matcher<QualType>,
InnerType) {
return InnerType.matches(Node.getDecayedType(), Finder, Builder);
@@ -7700,9 +9919,10 @@ AST_MATCHER_P(DecayedType, hasDecayedType, internal::Matcher<QualType>,
/// }
/// }
/// \endcode
+/// \compile_args{-std=c++}
///
-/// \c cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
-/// declaration of \c class \c D.
+/// The matcher \matcher{cxxRecordDecl(hasDeclContext(namedDecl(hasName("M"))))}
+/// matches the definition of \match{class D {}}.
AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) {
const DeclContext *DC = Node.getDeclContext();
if (!DC) return false;
@@ -7720,17 +9940,49 @@ AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) {
/// }
/// ns::A a;
/// \endcode
-/// nestedNameSpecifier()
-/// matches "ns::" and both "A::"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{nestedNameSpecifier()}
+/// matches \match{type=name$ns} and both spellings of
+/// \match{type=name;count=2$A} in \c A::f() and \c ns::A .
extern const internal::VariadicAllOfMatcher<NestedNameSpecifier>
nestedNameSpecifier;
/// Same as \c nestedNameSpecifier but matches \c NestedNameSpecifierLoc.
+///
+/// Given
+/// \code
+/// namespace ns {
+/// struct A { static void f(); };
+/// void A::f() {}
+/// void g() { A::f(); }
+/// }
+/// ns::A a;
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{nestedNameSpecifierLoc()} matches
+/// \match{count=2$A::} twice for the spellings in \c A::f() and \c ns::A ,
+/// and \match{ns::} once.
extern const internal::VariadicAllOfMatcher<NestedNameSpecifierLoc>
nestedNameSpecifierLoc;
/// Matches \c NestedNameSpecifierLocs for which the given inner
/// NestedNameSpecifier-matcher matches.
+///
+/// Given
+/// \code
+/// namespace ns {
+/// struct A { static void f(); };
+/// void A::f() {}
+/// void g() { A::f(); }
+/// }
+/// ns::A a;
+/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{nestedNameSpecifierLoc(loc(specifiesType(
+/// hasDeclaration(namedDecl(hasName("A"))))))} matches \match{count=2$A::}
+/// twice for the spellings in \c A::f() and \c ns::A .
AST_MATCHER_FUNCTION_P_OVERLOAD(
internal::BindableMatcher<NestedNameSpecifierLoc>, loc,
internal::Matcher<NestedNameSpecifier>, InnerMatcher, 1) {
@@ -7747,10 +9999,11 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(
/// struct A { struct B { struct C {}; }; };
/// A::B::C c;
/// \endcode
-/// nestedNameSpecifier(specifiesType(
+/// \compile_args{-std=c++}
+/// The matcher \matcher{nestedNameSpecifier(specifiesType(
/// hasDeclaration(cxxRecordDecl(hasName("A")))
-/// ))
-/// matches "A::"
+/// ))}
+/// matches the spelling of \match{type=name$A} in \c A::B::C .
AST_MATCHER_P(NestedNameSpecifier, specifiesType,
internal::Matcher<QualType>, InnerMatcher) {
if (!Node.getAsType())
@@ -7766,9 +10019,10 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType,
/// struct A { struct B { struct C {}; }; };
/// A::B::C c;
/// \endcode
-/// nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
-/// hasDeclaration(cxxRecordDecl(hasName("A")))))))
-/// matches "A::"
+/// \compile_args{-std=c++}
+/// The matcher \matcher{nestedNameSpecifierLoc(specifiesTypeLoc(loc(qualType(
+/// hasDeclaration(cxxRecordDecl(hasName("A")))))))}
+/// matches \match{A::}
AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
internal::Matcher<TypeLoc>, InnerMatcher) {
return Node && Node.getNestedNameSpecifier()->getAsType() &&
@@ -7782,8 +10036,10 @@ AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
/// struct A { struct B { struct C {}; }; };
/// A::B::C c;
/// \endcode
-/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
-/// matches "A::"
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{nestedNameSpecifier(hasPrefix(specifiesType(asString(
+/// "struct A"))))} matches \match{type=typestr$struct A::B}
AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
internal::Matcher<NestedNameSpecifier>, InnerMatcher,
0) {
@@ -7800,8 +10056,10 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
/// struct A { struct B { struct C {}; }; };
/// A::B::C c;
/// \endcode
-/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
-/// matches "A::"
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString(
+/// "struct A")))))} matches \match{A::B::}.
AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
internal::Matcher<NestedNameSpecifierLoc>, InnerMatcher,
1) {
@@ -7819,8 +10077,10 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
/// namespace ns { struct A {}; }
/// ns::A a;
/// \endcode
-/// nestedNameSpecifier(specifiesNamespace(hasName("ns")))
-/// matches "ns::"
+/// \compile_args{-std=c++}
+/// The matcher
+/// \matcher{nestedNameSpecifier(specifiesNamespace(hasName("ns")))} matches
+/// the spelling of \match{type=name$ns} in \c ns::A .
AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
internal::Matcher<NamespaceDecl>, InnerMatcher) {
if (!Node.getAsNamespace())
@@ -7842,8 +10102,10 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
/// #pragma omp declare simd
/// int min();
/// \endcode
-/// attr()
-/// matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line.
+/// \compile_args{-fdeclspec;-fopenmp}
+/// The matcher \matcher{attr()}
+/// matches \match{nodiscard}, \match{nonnull}, \match{noinline}, and
+/// \match{declare simd}.
extern const internal::VariadicAllOfMatcher<Attr> attr;
/// Overloads for the \c equalsNode matcher.
@@ -7876,12 +10138,19 @@ AST_MATCHER_P_OVERLOAD(Type, equalsNode, const Type*, Other, 2) {
///
/// Given
/// \code
-/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+/// void foo() {
+/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+/// }
/// \endcode
-/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
-/// matches four times, with "c" binding each of "case 1:", "case 2:",
-/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)",
-/// "switch (1)", "switch (2)" and "switch (2)".
+/// The matcher
+/// \matcher{switchStmt(forEachSwitchCase(caseStmt().bind("c")))}
+/// matches four times, matching
+/// \match{count=2$switch (1) { case 1: case 2: default: switch (2) { case 3:
+/// case 4: ; } }} twice and
+/// \match{count=2$switch (2) { case 3: case 4: ; }} twice, with
+/// \matcher{type=sub$caseStmt()} matching each of \match{sub=c$case 1:},
+/// \match{sub=c$case 2:}, \match{sub=c$case 3:}
+/// and \match{sub=c$case 4:}.
AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
InnerMatcher) {
BoundNodesTreeBuilder Result;
@@ -7909,10 +10178,12 @@ AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
/// \code
/// class A { A() : i(42), j(42) {} int i; int j; };
/// \endcode
-/// cxxConstructorDecl(forEachConstructorInitializer(
-/// forField(decl().bind("x"))
-/// ))
-/// will trigger two matches, binding for 'i' and 'j' respectively.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(forEachConstructorInitializer(
+/// forField(fieldDecl().bind("x"))))}
+/// matches the constructor of \match{count=2$A() : i(42), j(42) {}} twice, with
+/// \matcher{type=sub$fieldDecl()} matching \match{sub=field$i} and
+/// \match{sub=field$j} respectively.
AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
BoundNodesTreeBuilder Result;
@@ -7940,7 +10211,10 @@ AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
/// S(S &&); // #3
/// };
/// \endcode
-/// cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(isCopyConstructor())}
+/// matches \match{S(const S &)},
+/// but does not match \nomatch{S()} or \nomatch{S(S &&)}.
AST_MATCHER(CXXConstructorDecl, isCopyConstructor) {
return Node.isCopyConstructor();
}
@@ -7955,7 +10229,10 @@ AST_MATCHER(CXXConstructorDecl, isCopyConstructor) {
/// S(S &&); // #3
/// };
/// \endcode
-/// cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(isMoveConstructor())}
+/// matches \match{S(S &&)}
+/// but does not match \nomatch{S();} or \nomatch{S(S &&);}
AST_MATCHER(CXXConstructorDecl, isMoveConstructor) {
return Node.isMoveConstructor();
}
@@ -7970,7 +10247,10 @@ AST_MATCHER(CXXConstructorDecl, isMoveConstructor) {
/// S(S &&); // #3
/// };
/// \endcode
-/// cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxConstructorDecl(isDefaultConstructor())}
+/// matches \match{S()}
+/// but does not match \nomatch{S(const S &);} or \nomatch{S(S &&);}.
AST_MATCHER(CXXConstructorDecl, isDefaultConstructor) {
return Node.isDefaultConstructor();
}
@@ -7986,8 +10266,10 @@ AST_MATCHER(CXXConstructorDecl, isDefaultConstructor) {
/// };
/// S::S() : S(0) {} // #4
/// \endcode
-/// cxxConstructorDecl(isDelegatingConstructor()) will match #3 and #4, but not
-/// #1 or #2.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{cxxConstructorDecl(isDelegatingConstructor())}
+/// matches \match{S(S &&) : S() {}} and \match{S::S() : S(0) {}},
+/// but does not match \nomatch{S()} or \nomatch{S(int)}.
AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) {
return Node.isDelegatingConstructor();
}
@@ -8004,16 +10286,28 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) {
/// explicit S(double); // #2
/// operator int(); // #3
/// explicit operator bool(); // #4
-/// explicit(false) S(bool) // # 7
-/// explicit(true) S(char) // # 8
-/// explicit(b) S(S) // # 9
+/// explicit(false) S(bool); // # 7
+/// explicit(true) S(char); // # 8
+/// explicit(b) S(float); // # 9
/// };
-/// S(int) -> S<true> // #5
-/// explicit S(double) -> S<false> // #6
-/// \endcode
-/// cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9.
-/// cxxConversionDecl(isExplicit()) will match #4, but not #3.
-/// cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+/// S(int) -> S<true>; // #5
+/// explicit S(double) -> S<false>; // #6
+/// \endcode
+/// \compile_args{-fno-delayed-template-parsing;-std=c++20-or-later}
+/// The matcher \matcher{cxxConstructorDecl(isExplicit())}
+/// matches \match{explicit S(double)}
+/// and \match{explicit(true) S(char)}
+/// but does not match \nomatch{S(int);}, \nomatch{explicit(false) S(bool);} or
+/// \nomatch{explicit(b) S(float)}
+/// The matcher \matcher{cxxConversionDecl(isExplicit())}
+/// matches \match{explicit operator bool()}
+/// but does not match \nomatch{operator int()}.
+/// The matcher \matcher{cxxDeductionGuideDecl(isExplicit())}
+/// matches the deduction guide \match{explicit S(double) -> S<false>},
+/// the implicit copy deduction candiate
+/// \match{type=typestr$auto (double) -> S<b>} and
+/// the implicitly generated deduction guide for \match{explicit(true) S(char)},
+/// but does not match \nomatch{S(int) -> S<true>}.
AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES(
CXXConstructorDecl, CXXConversionDecl,
CXXDeductionGuideDecl)) {
@@ -8031,16 +10325,28 @@ AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES(
/// explicit S(double); // #2
/// operator int(); // #3
/// explicit operator bool(); // #4
-/// explicit(false) S(bool) // # 7
-/// explicit(true) S(char) // # 8
-/// explicit(b) S(S) // # 9
+/// explicit(false) S(bool); // # 7
+/// explicit(true) S(char); // # 8
+/// explicit(b) S(float); // # 9
/// };
-/// S(int) -> S<true> // #5
-/// explicit S(double) -> S<false> // #6
+/// S(int) -> S<true>; // #5
+/// explicit S(double) -> S<false>; // #6
/// \endcode
-/// cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2.
-/// cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4.
-/// cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6.
+/// \compile_args{-fno-delayed-template-parsing;-std=c++20-or-later}
+/// The matcher
+/// \matcher{cxxConstructorDecl(hasExplicitSpecifier(constantExpr()))} matches
+/// \match{explicit(false) S(bool)} and \match{explicit(true) S(char)},
+/// but does not match \nomatch{explicit(b) S(float)}, \nomatch{S(int)} or
+/// \nomatch{explicit S(double)}.
+/// The matcher
+/// \matcher{cxxConversionDecl(hasExplicitSpecifier(constantExpr()))} does not
+/// match \nomatch{operator int()} or \nomatch{explicit operator bool()}.
+/// Matcher
+/// The matcher
+/// \matcher{cxxDeductionGuideDecl(hasExplicitSpecifier(declRefExpr()))}
+/// matches the implicitly generated deduction guide
+/// \match{type=typestr$auto (float) -> S<b>} of the constructor
+/// \c{explicit(b) S(float)}.
AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher<Expr>,
InnerMatcher) {
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(&Node);
@@ -8064,9 +10370,13 @@ AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher<Expr>,
/// }
/// inline int Foo = 5;
/// \endcode
-/// functionDecl(isInline()) will match ::f().
-/// namespaceDecl(isInline()) will match n::m.
-/// varDecl(isInline()) will match Foo;
+/// \compile_args{-std=c++}
+/// The matcher \matcher{functionDecl(isInline())} matches
+/// \match{inline void f()}.
+/// The matcher \matcher{namespaceDecl(isInline())} matches
+/// \match{inline namespace m {}}.
+/// The matcher \matcher{varDecl(isInline())} matches
+/// \match{inline int Foo = 5}.
AST_POLYMORPHIC_MATCHER(isInline, AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl,
FunctionDecl,
VarDecl)) {
@@ -8089,7 +10399,9 @@ AST_POLYMORPHIC_MATCHER(isInline, AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl,
/// namespace {} // #1
/// }
/// \endcode
-/// namespaceDecl(isAnonymous()) will match #1 but not ::n.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{namespaceDecl(isAnonymous())}
+/// matches \match{namespace {}}, but not \nomatch{namespace n}.
AST_MATCHER(NamespaceDecl, isAnonymous) {
return Node.isAnonymousNamespace();
}
@@ -8114,7 +10426,9 @@ AST_MATCHER(NamespaceDecl, isAnonymous) {
/// }
/// }
/// \endcode
-/// cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("vector"), isInStdNamespace())}
+/// matches \match{class vector {}} inside of namespace std.
AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); }
/// Matches declarations in an anonymous namespace.
@@ -8131,12 +10445,16 @@ AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); }
/// namespace {
/// class vector {}; // #2
/// namespace foo {
-/// class vector{}; // #3
+/// class vector {}; // #3
/// }
/// }
/// \endcode
-/// cxxRecordDecl(hasName("vector"), isInAnonymousNamespace()) will match
-/// #1, #2 and #3.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasName("vector"),
+/// isInAnonymousNamespace())}
+/// matches \match{type=name;count=6$vector},
+/// two times for the definition and the implicit class declaration
+/// for each of the three definitions of \c vector .
AST_MATCHER(Decl, isInAnonymousNamespace) {
return Node.isInAnonymousNamespace();
}
@@ -8146,10 +10464,13 @@ AST_MATCHER(Decl, isInAnonymousNamespace) {
///
/// Given
/// \code
-/// switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+/// void foo() {
+/// switch (1) { case 1: break; case 1+1: break; case 3 ... 4: break; }
+/// }
/// \endcode
-/// caseStmt(hasCaseConstant(integerLiteral()))
-/// matches "case 1:"
+/// The matcher
+/// \matcher{caseStmt(hasCaseConstant(constantExpr(has(integerLiteral()))))}
+/// matches \match{case 1: break}.
AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
InnerMatcher) {
if (Node.getRHS())
@@ -8162,11 +10483,14 @@ AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
///
/// Given
/// \code
-/// __attribute__((device)) void f() { ... }
+/// __attribute__((device)) void f() {}
/// \endcode
-/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
-/// f. If the matcher is used from clang-query, attr::Kind parameter should be
-/// passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+/// \compile_args{--cuda-gpu-arch=sm_70;-std=c++}
+/// The matcher \matcher{decl(hasAttr(clang::attr::CUDADevice))}
+/// matches \match{__attribute__((device)) void f() {}}.
+/// If the matcher is used from clang-query, attr::Kind
+/// parameter should be passed as a quoted string. e.g.,
+/// \c hasAttr("attr::CUDADevice").
AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
for (const auto *Attr : Node.attrs()) {
if (Attr->getKind() == AttrKind)
@@ -8179,12 +10503,14 @@ AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
///
/// Given
/// \code
-/// return a + b;
+/// int foo(int a, int b) {
+/// return a + b;
+/// }
/// \endcode
-/// hasReturnValue(binaryOperator())
-/// matches 'return a + b'
-/// with binaryOperator()
-/// matching 'a + b'
+/// The matcher
+/// \matcher{returnStmt(hasReturnValue(binaryOperator().bind("op")))} matches
+/// \match{return a + b}, with \matcher{type=sub$binaryOperator()} matching
+/// \match{sub=op$a + b}.
AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>,
InnerMatcher) {
if (const auto *RetValue = Node.getRetValue())
@@ -8194,18 +10520,25 @@ AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>,
/// Matches CUDA kernel call expression.
///
-/// Example matches,
+/// Given
/// \code
-/// kernel<<<i,j>>>();
+/// __global__ void kernel() {}
+/// void f() {
+/// kernel<<<32, 32>>>();
+/// }
/// \endcode
+/// \compile_args{--cuda-gpu-arch=sm_70;-std=c++}
+/// The matcher \matcher{cudaKernelCallExpr()}
+/// matches \match{kernel<<<32, 32>>>()}
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
cudaKernelCallExpr;
/// Matches expressions that resolve to a null pointer constant, such as
/// GNU's __null, C++11's nullptr, or C's NULL macro.
///
-/// Given:
+/// Given
/// \code
+/// #define NULL 0
/// void *v1 = NULL;
/// void *v2 = nullptr;
/// void *v3 = __null; // GNU extension
@@ -8213,9 +10546,14 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
/// int *ip = 0;
/// int i = 0;
/// \endcode
-/// expr(nullPointerConstant())
-/// matches the initializer for v1, v2, v3, cp, and ip. Does not match the
-/// initializer for i.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{expr(nullPointerConstant())}
+/// matches the initializer \match{NULL} of v1,
+/// matches the initializer \match{nullptr} of v2,
+/// matches the initializer \match{__null} of v3,
+/// matches the initializer \match{0} of cp and
+/// matches the initializer \match{0} of ip,
+/// but does not match the initializer \nomatch{i} of i.
AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
return anyOf(
gnuNullExpr(), cxxNullPtrLiteralExpr(),
@@ -8224,7 +10562,7 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
/// Matches the DecompositionDecl the binding belongs to.
///
-/// For example, in:
+/// Given
/// \code
/// void foo()
/// {
@@ -8234,12 +10572,10 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
/// f = 42;
/// }
/// \endcode
-/// The matcher:
-/// \code
-/// bindingDecl(hasName("f"),
-/// forDecomposition(decompositionDecl())
-/// \endcode
-/// matches 'f' in 'auto &[f, s, t]'.
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{bindingDecl(hasName("f"),
+/// forDecomposition(decompositionDecl()))}
+/// matches \match{type=name$f} in \c{auto &[f, s, t]}.
AST_MATCHER_P(BindingDecl, forDecomposition, internal::Matcher<ValueDecl>,
InnerMatcher) {
if (const ValueDecl *VD = Node.getDecomposedDecl())
@@ -8249,7 +10585,7 @@ AST_MATCHER_P(BindingDecl, forDecomposition, internal::Matcher<ValueDecl>,
/// Matches the Nth binding of a DecompositionDecl.
///
-/// For example, in:
+/// Given
/// \code
/// void foo()
/// {
@@ -8259,12 +10595,10 @@ AST_MATCHER_P(BindingDecl, forDecomposition, internal::Matcher<ValueDecl>,
/// f = 42;
/// }
/// \endcode
-/// The matcher:
-/// \code
-/// decompositionDecl(hasBinding(0,
-/// bindingDecl(hasName("f").bind("fBinding"))))
-/// \endcode
-/// matches the decomposition decl with 'f' bound to "fBinding".
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{decompositionDecl(hasBinding(0,
+/// bindingDecl(hasName("f")).bind("fBinding")))}
+/// matches \match{auto &[f, s, t] = arr} with 'f' bound to "fBinding".
AST_MATCHER_P2(DecompositionDecl, hasBinding, unsigned, N,
internal::Matcher<BindingDecl>, InnerMatcher) {
if (Node.bindings().size() <= N)
@@ -8284,11 +10618,10 @@ AST_MATCHER_P2(DecompositionDecl, hasBinding, unsigned, N,
/// f = 42;
/// }
/// \endcode
-/// The matcher:
-/// \code
-/// decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
-/// \endcode
-/// matches the decomposition decl with 'f' bound to "fBinding".
+/// \compile_args{-std=c++11-or-later}
+/// The matcher
+/// \matcher{decompositionDecl(hasAnyBinding(bindingDecl(hasName("f")).bind("fBinding")))}
+/// matches \match{auto &[f, s, t] = arr} with 'f' bound to "fBinding".
AST_MATCHER_P(DecompositionDecl, hasAnyBinding, internal::Matcher<BindingDecl>,
InnerMatcher) {
return llvm::any_of(Node.bindings(), [&](const auto *Binding) {
@@ -8300,19 +10633,23 @@ AST_MATCHER_P(DecompositionDecl, hasAnyBinding, internal::Matcher<BindingDecl>,
///
/// Deprecated. Use forCallable() to correctly handle the situation when
/// the declaration is not a function (but a block or an Objective-C method).
-/// forFunction() not only fails to take non-functions into account but also
-/// may match the wrong declaration in their presence.
+/// The matcher \c forFunction() not only fails to take non-functions
+/// into account but also may match the wrong declaration in their presence.
///
-/// Given:
+/// Given
/// \code
-/// F& operator=(const F& o) {
-/// std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
-/// return *this;
-/// }
+/// struct F {
+/// F& operator=(const F& other) {
+/// []() { return 42 == 42; };
+/// return *this;
+/// }
+/// };
/// \endcode
-/// returnStmt(forFunction(hasName("operator=")))
-/// matches 'return *this'
-/// but does not match 'return v > 0'
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{returnStmt(forFunction(hasName("operator=")))}
+/// matches \match{return *this}
+/// but does not match \nomatch{return 42 == 42}.
AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
InnerMatcher) {
const auto &Parents = Finder->getASTContext().getParents(Node);
@@ -8340,30 +10677,34 @@ AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
/// Matches declaration of the function, method, or block the statement
/// belongs to.
///
-/// Given:
+/// Given
/// \code
-/// F& operator=(const F& o) {
-/// std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
-/// return *this;
-/// }
+/// struct F {
+/// F& operator=(const F& other) {
+/// []() { return 42 == 42; };
+/// return *this;
+/// }
+/// };
/// \endcode
-/// returnStmt(forCallable(functionDecl(hasName("operator="))))
-/// matches 'return *this'
-/// but does not match 'return v > 0'
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{returnStmt(forFunction(hasName("operator=")))}
+/// matches \match{return *this}
+/// but does not match \nomatch{return 42 == 42}.
///
-/// Given:
+/// Given
/// \code
-/// -(void) foo {
+/// void foo {
/// int x = 1;
/// dispatch_sync(queue, ^{ int y = 2; });
/// }
/// \endcode
-/// declStmt(forCallable(objcMethodDecl()))
-/// matches 'int x = 1'
-/// but does not match 'int y = 2'.
-/// whereas declStmt(forCallable(blockDecl()))
-/// matches 'int y = 2'
-/// but does not match 'int x = 1'.
+/// \compile_args{-ObjC}
+/// The matcher \matcher{declStmt(forCallable(objcMethodDecl()))}
+/// matches \match{int x = 1}
+/// but does not match \nomatch{int y = 2}.
+/// The matcher \matcher{declStmt(forCallable(blockDecl()))}
+/// matches \match{int y = 2}
+/// but does not match \nomatch{int x = 1}.
AST_MATCHER_P(Stmt, forCallable, internal::Matcher<Decl>, InnerMatcher) {
const auto &Parents = Finder->getASTContext().getParents(Node);
@@ -8405,73 +10746,93 @@ AST_MATCHER_P(Stmt, forCallable, internal::Matcher<Decl>, InnerMatcher) {
/// Matches a declaration that has external formal linkage.
///
-/// Example matches only z (matcher = varDecl(hasExternalFormalLinkage()))
+/// Given
/// \code
/// void f() {
-/// int x;
-/// static int y;
+/// int a;
+/// static int b;
/// }
-/// int z;
+/// int c;
+/// static int d;
/// \endcode
+/// The matcher \matcher{varDecl(hasExternalFormalLinkage())}
+/// matches \match{int c},
+/// but not \nomatch{int a}, \nomatch{static int b} or \nomatch{int d}.
///
-/// Example matches f() because it has external formal linkage despite being
-/// unique to the translation unit as though it has internal likage
-/// (matcher = functionDecl(hasExternalFormalLinkage()))
-///
+/// Given
/// \code
-/// namespace {
-/// void f() {}
-/// }
+/// namespace {
+/// void f() {}
+/// }
+/// void g() {}
+/// static void h() {}
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{functionDecl(hasExternalFormalLinkage())}
+/// matches \match{void g() {}}, but not \nomatch{void f() {}} or
+/// \nomatch{static void h() {}}.
AST_MATCHER(NamedDecl, hasExternalFormalLinkage) {
return Node.hasExternalFormalLinkage();
}
/// Matches a declaration that has default arguments.
///
-/// Example matches y (matcher = parmVarDecl(hasDefaultArgument()))
+/// Given
/// \code
-/// void x(int val) {}
-/// void y(int val = 0) {}
+/// void x(int val) {}
+/// void y(int val = 0) {}
/// \endcode
+/// \compile_args{-std=c++}
+///
+/// The matcher \matcher{parmVarDecl(hasDefaultArgument())}
+/// matches \match{int val = 0}.
///
/// Deprecated. Use hasInitializer() instead to be able to
/// match on the contents of the default argument. For example:
///
+/// Given
/// \code
-/// void x(int val = 7) {}
-/// void y(int val = 42) {}
+/// void x(int val = 7) {}
+/// void y(int val = 42) {}
/// \endcode
-/// parmVarDecl(hasInitializer(integerLiteral(equals(42))))
-/// matches the parameter of y
+/// \compile_args{-std=c++}
///
-/// A matcher such as
-/// parmVarDecl(hasInitializer(anything()))
-/// is equivalent to parmVarDecl(hasDefaultArgument()).
+/// The matcher
+/// \matcher{parmVarDecl(hasInitializer(integerLiteral(equals(42))))},
+/// matches \match{int val = 42}.
AST_MATCHER(ParmVarDecl, hasDefaultArgument) {
return Node.hasDefaultArg();
}
/// Matches array new expressions.
///
-/// Given:
+/// Given
/// \code
+/// struct MyClass { int x; };
/// MyClass *p1 = new MyClass[10];
/// \endcode
-/// cxxNewExpr(isArray())
-/// matches the expression 'new MyClass[10]'.
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxNewExpr(isArray())}
+/// matches \match{new MyClass[10]}.
AST_MATCHER(CXXNewExpr, isArray) {
return Node.isArray();
}
/// Matches placement new expression arguments.
///
-/// Given:
+/// Given
/// \code
-/// MyClass *p1 = new (Storage, 16) MyClass();
+/// void *operator new(decltype(sizeof(void*)), int, void*);
+/// struct MyClass { int x; };
+/// unsigned char Storage[sizeof(MyClass) * 10];
+/// MyClass *p1 = new (16, Storage) MyClass();
/// \endcode
-/// cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
-/// matches the expression 'new (Storage, 16) MyClass()'.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{cxxNewExpr(hasPlacementArg(0,
+/// integerLiteral(equals(16))))}
+/// matches \match{new (16, Storage) MyClass()}.
AST_MATCHER_P2(CXXNewExpr, hasPlacementArg, unsigned, Index,
internal::Matcher<Expr>, InnerMatcher) {
return Node.getNumPlacementArgs() > Index &&
@@ -8480,12 +10841,17 @@ AST_MATCHER_P2(CXXNewExpr, hasPlacementArg, unsigned, Index,
/// Matches any placement new expression arguments.
///
-/// Given:
+/// Given
/// \code
+/// void* operator new(decltype(sizeof(void*)), void*);
+/// struct MyClass { int x; };
+/// unsigned char Storage[sizeof(MyClass) * 10];
/// MyClass *p1 = new (Storage) MyClass();
/// \endcode
-/// cxxNewExpr(hasAnyPlacementArg(anything()))
-/// matches the expression 'new (Storage, 16) MyClass()'.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher \matcher{cxxNewExpr(hasAnyPlacementArg(anything()))}
+/// matches \match{new (Storage) MyClass()}.
AST_MATCHER_P(CXXNewExpr, hasAnyPlacementArg, internal::Matcher<Expr>,
InnerMatcher) {
return llvm::any_of(Node.placement_arguments(), [&](const Expr *Arg) {
@@ -8495,12 +10861,18 @@ AST_MATCHER_P(CXXNewExpr, hasAnyPlacementArg, internal::Matcher<Expr>,
/// Matches array new expressions with a given array size.
///
-/// Given:
+/// Given
/// \code
+/// void* operator new(decltype(sizeof(void*)));
+/// struct MyClass { int x; };
/// MyClass *p1 = new MyClass[10];
/// \endcode
-/// cxxNewExpr(hasArraySize(integerLiteral(equals(10))))
-/// matches the expression 'new MyClass[10]'.
+/// \compile_args{-std=c++11-or-later}
+///
+/// The matcher
+/// \matcher{cxxNewExpr(hasArraySize(
+/// ignoringImplicit(integerLiteral(equals(10)))))}
+/// matches \match{new MyClass[10]}.
AST_MATCHER_P(CXXNewExpr, hasArraySize, internal::Matcher<Expr>, InnerMatcher) {
return Node.isArray() && *Node.getArraySize() &&
InnerMatcher.matches(**Node.getArraySize(), Finder, Builder);
@@ -8508,33 +10880,42 @@ AST_MATCHER_P(CXXNewExpr, hasArraySize, internal::Matcher<Expr>, InnerMatcher) {
/// Matches a class declaration that is defined.
///
-/// Example matches x (matcher = cxxRecordDecl(hasDefinition()))
+/// Given
/// \code
/// class x {};
/// class y;
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{cxxRecordDecl(hasDefinition())}
+/// matches \match{class x {}}
AST_MATCHER(CXXRecordDecl, hasDefinition) {
return Node.hasDefinition();
}
/// Matches C++11 scoped enum declaration.
///
-/// Example matches Y (matcher = enumDecl(isScoped()))
+/// Given
/// \code
/// enum X {};
/// enum class Y {};
/// \endcode
+/// \compile_args{-std=c++}
+/// The matcher \matcher{enumDecl(isScoped())}
+/// matches \match{enum class Y {}}
AST_MATCHER(EnumDecl, isScoped) {
return Node.isScoped();
}
/// Matches a function declared with a trailing return type.
///
-/// Example matches Y (matcher = functionDecl(hasTrailingReturn()))
+/// Given
/// \code
/// int X() {}
/// auto Y() -> int {}
/// \endcode
+/// \compile_args{-std=c++11-or-later}
+/// The matcher \matcher{functionDecl(hasTrailingReturn())}
+/// matches \match{auto Y() -> int {}}.
AST_MATCHER(FunctionDecl, hasTrailingReturn) {
if (const auto *F = Node.getType()->getAs<FunctionProtoType>())
return F->hasTrailingReturn();
@@ -8553,7 +10934,6 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
/// appear in the C++17 AST.
///
/// Given
-///
/// \code
/// struct H {};
/// H G();
@@ -8561,9 +10941,11 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
/// H D = G();
/// }
/// \endcode
+/// \compile_args{-std=c++11-or-later}
///
-/// ``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
-/// matches ``H D = G()`` in C++11 through C++17 (and beyond).
+/// The matcher
+/// \matcher{varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))}
+/// matches \match{H D = G()}.
AST_MATCHER_P(Expr, ignoringElidableConstructorCall, internal::Matcher<Expr>,
InnerMatcher) {
// E tracks the node that we are examining.
@@ -8594,15 +10976,21 @@ AST_MATCHER_P(Expr, ignoringElidableConstructorCall, internal::Matcher<Expr>,
/// Matches any ``#pragma omp`` executable directive.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// #pragma omp parallel default(none)
-/// #pragma omp taskyield
+/// void foo() {
+/// #pragma omp parallel
+/// {}
+/// #pragma omp parallel default(none)
+/// {
+/// #pragma omp taskyield
+/// }
+/// }
/// \endcode
-///
-/// ``ompExecutableDirective()`` matches ``omp parallel``,
-/// ``omp parallel default(none)`` and ``omp taskyield``.
+/// \compile_args{-fopenmp}
+/// The matcher \matcher{ompExecutableDirective()}
+/// matches \match{#pragma omp parallel},
+/// \match{#pragma omp parallel default(none)}
+/// and \match{#pragma omp taskyield}.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective>
ompExecutableDirective;
@@ -8610,15 +10998,18 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective>
/// i.e., directives that can't have a structured block.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// {}
-/// #pragma omp taskyield
+/// void foo() {
+/// #pragma omp parallel
+/// {
+/// #pragma omp taskyield
+/// }
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompExecutableDirective(isStandaloneDirective()))`` matches
-/// ``omp taskyield``.
+/// The matcher \matcher{ompExecutableDirective(isStandaloneDirective())}
+/// matches \match{#pragma omp taskyield}.
AST_MATCHER(OMPExecutableDirective, isStandaloneDirective) {
return Node.isStandaloneDirective();
}
@@ -8629,15 +11020,20 @@ AST_MATCHER(OMPExecutableDirective, isStandaloneDirective) {
/// If it is, it will never match.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// ;
-/// #pragma omp parallel
-/// {}
+/// void foo() {
+/// #pragma omp parallel
+/// ;
+/// #pragma omp parallel
+/// {}
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompExecutableDirective(hasStructuredBlock(nullStmt()))`` will match ``;``
+/// The matcher
+/// \matcher{ompExecutableDirective(hasStructuredBlock(nullStmt().bind("stmt")))}
+/// matches \match{#pragma omp parallel},
+/// with \matcher{type=sub$stmtt()} matching \match{sub=stmt${}}.
AST_MATCHER_P(OMPExecutableDirective, hasStructuredBlock,
internal::Matcher<Stmt>, InnerMatcher) {
if (Node.isStandaloneDirective())
@@ -8648,14 +11044,18 @@ AST_MATCHER_P(OMPExecutableDirective, hasStructuredBlock,
/// Matches any clause in an OpenMP directive.
///
/// Given
-///
/// \code
+/// void foo() {
/// #pragma omp parallel
+/// ;
/// #pragma omp parallel default(none)
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompExecutableDirective(hasAnyClause(anything()))`` matches
-/// ``omp parallel default(none)``.
+/// The matcher \matcher{ompExecutableDirective(hasAnyClause(anything()))}
+/// matches \match{#pragma omp parallel default(none)}.
AST_MATCHER_P(OMPExecutableDirective, hasAnyClause,
internal::Matcher<OMPClause>, InnerMatcher) {
ArrayRef<OMPClause *> Clauses = Node.clauses();
@@ -8667,33 +11067,53 @@ AST_MATCHER_P(OMPExecutableDirective, hasAnyClause,
/// Matches OpenMP ``default`` clause.
///
/// Given
-///
/// \code
-/// #pragma omp parallel default(none)
-/// #pragma omp parallel default(shared)
-/// #pragma omp parallel default(private)
-/// #pragma omp parallel default(firstprivate)
-/// #pragma omp parallel
+/// void foo() {
+/// #pragma omp parallel default(none)
+/// ;
+/// #pragma omp parallel default(shared)
+/// ;
+/// #pragma omp parallel default(private)
+/// ;
+/// #pragma omp parallel default(firstprivate)
+/// ;
+/// #pragma omp parallel
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``,
-/// `` default(private)`` and ``default(firstprivate)``
+/// The matcher
+/// \matcher{ompExecutableDirective(hasAnyClause(ompDefaultClause()))} matches
+/// \match{#pragma omp parallel default(none)},
+/// \match{#pragma omp parallel default(shared)},
+/// \match{#pragma omp parallel default(private)} and
+/// \match{#pragma omp parallel default(firstprivate)}.
extern const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPDefaultClause>
ompDefaultClause;
/// Matches if the OpenMP ``default`` clause has ``none`` kind specified.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// #pragma omp parallel default(none)
-/// #pragma omp parallel default(shared)
-/// #pragma omp parallel default(private)
-/// #pragma omp parallel default(firstprivate)
+/// void foo() {
+/// #pragma omp parallel
+/// ;
+/// #pragma omp parallel default(none)
+/// ;
+/// #pragma omp parallel default(shared)
+/// ;
+/// #pragma omp parallel default(private)
+/// ;
+/// #pragma omp parallel default(firstprivate)
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+/// The matcher
+/// \matcher{ompExecutableDirective(hasAnyClause(ompDefaultClause(isNoneKind())))}
+/// matches only \match{#pragma omp parallel default(none)}.
AST_MATCHER(OMPDefaultClause, isNoneKind) {
return Node.getDefaultKind() == llvm::omp::OMP_DEFAULT_none;
}
@@ -8701,16 +11121,25 @@ AST_MATCHER(OMPDefaultClause, isNoneKind) {
/// Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// #pragma omp parallel default(none)
+/// void foo() {
+/// #pragma omp parallel
+/// ;
+/// #pragma omp parallel default(none)
+/// ;
/// #pragma omp parallel default(shared)
+/// ;
/// #pragma omp parallel default(private)
+/// ;
/// #pragma omp parallel default(firstprivate)
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
+/// The matcher
+/// \matcher{ompExecutableDirective(hasAnyClause(ompDefaultClause(isSharedKind())))}
+/// matches \match{#pragma omp parallel default(shared)}.
AST_MATCHER(OMPDefaultClause, isSharedKind) {
return Node.getDefaultKind() == llvm::omp::OMP_DEFAULT_shared;
}
@@ -8719,17 +11148,25 @@ AST_MATCHER(OMPDefaultClause, isSharedKind) {
/// specified.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
+/// void foo() {
+/// #pragma omp parallel
+/// ;
/// #pragma omp parallel default(none)
+/// ;
/// #pragma omp parallel default(shared)
+/// ;
/// #pragma omp parallel default(private)
+/// ;
/// #pragma omp parallel default(firstprivate)
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompDefaultClause(isPrivateKind())`` matches only
-/// ``default(private)``.
+/// The matcher
+/// \matcher{ompExecutableDirective(hasAnyClause(ompDefaultClause(isPrivateKind())))}
+/// matches \match{#pragma omp parallel default(private)}.
AST_MATCHER(OMPDefaultClause, isPrivateKind) {
return Node.getDefaultKind() == llvm::omp::OMP_DEFAULT_private;
}
@@ -8738,17 +11175,25 @@ AST_MATCHER(OMPDefaultClause, isPrivateKind) {
/// specified.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// #pragma omp parallel default(none)
-/// #pragma omp parallel default(shared)
-/// #pragma omp parallel default(private)
-/// #pragma omp parallel default(firstprivate)
+/// void foo() {
+/// #pragma omp parallel
+/// ;
+/// #pragma omp parallel default(none)
+/// ;
+/// #pragma omp parallel default(shared)
+/// ;
+/// #pragma omp parallel default(private)
+/// ;
+/// #pragma omp parallel default(firstprivate)
+/// ;
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// ``ompDefaultClause(isFirstPrivateKind())`` matches only
-/// ``default(firstprivate)``.
+/// The matcher
+/// \matcher{ompExecutableDirective(hasAnyClause(ompDefaultClause(isFirstPrivateKind())))}
+/// matches \match{#pragma omp parallel default(firstprivate)}.
AST_MATCHER(OMPDefaultClause, isFirstPrivateKind) {
return Node.getDefaultKind() == llvm::omp::OMP_DEFAULT_firstprivate;
}
@@ -8757,15 +11202,23 @@ AST_MATCHER(OMPDefaultClause, isFirstPrivateKind) {
/// clause kind.
///
/// Given
-///
/// \code
-/// #pragma omp parallel
-/// #pragma omp parallel for
-/// #pragma omp for
+/// void foo() {
+/// #pragma omp parallel
+/// ;
+/// #pragma omp parallel for
+/// for (int i = 0; i < 10; ++i) {}
+/// #pragma omp for
+/// for (int i = 0; i < 10; ++i) {}
+/// }
/// \endcode
+/// \compile_args{-fopenmp}
///
-/// `ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches
-/// ``omp parallel`` and ``omp parallel for``.
+/// The matcher
+/// \matcher{ompExecutableDirective(isAllowedToContainClauseKind(
+/// OpenMPClauseKind::OMPC_default))}
+/// matches \match{#pragma omp parallel}
+/// and \match{#pragma omp parallel for}.
///
/// If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter
/// should be passed as a quoted string. e.g.,
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.h b/clang/unittests/ASTMatchers/ASTMatchersTest.h
index ad2f5f355621cd..47bb7737316660 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/clang/unittests/ASTMatchers/ASTMatchersTest.h
@@ -9,12 +9,46 @@
#ifndef LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
#define LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Serialization/PCHContainerOperations.h"
#include "clang/Testing/CommandLineArgs.h"
#include "clang/Testing/TestClangConfig.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/FixIt.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <optional>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -293,7 +327,8 @@ template <typename T>
testing::AssertionResult matchAndVerifyResultConditionally(
const Twine &Code, const T &AMatcher,
std::unique_ptr<BoundNodesCallback> FindResultVerifier, bool ExpectResult,
- ArrayRef<std::string> Args = {}, StringRef Filename = "input.cc") {
+ ArrayRef<std::string> Args = {}, StringRef Filename = "input.cc",
+ const FileContentMappings &VirtualMappedFiles = {}) {
bool VerifiedResult = false;
MatchFinder Finder;
VerifyMatch VerifyVerifiedResult(std::move(FindResultVerifier),
@@ -310,7 +345,9 @@ testing::AssertionResult matchAndVerifyResultConditionally(
// choices that we made above.
llvm::copy(Args, std::back_inserter(CompileArgs));
- if (!runToolOnCodeWithArgs(Factory->create(), Code, CompileArgs, Filename)) {
+ if (!runToolOnCodeWithArgs(
+ Factory->create(), Code, CompileArgs, Filename, "clang-tool",
+ std::make_shared<PCHContainerOperations>(), VirtualMappedFiles)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (!VerifiedResult && ExpectResult) {
@@ -324,7 +361,9 @@ testing::AssertionResult matchAndVerifyResultConditionally(
VerifiedResult = false;
SmallString<256> Buffer;
std::unique_ptr<ASTUnit> AST(buildASTFromCodeWithArgs(
- Code.toStringRef(Buffer), CompileArgs, Filename));
+ Code.toStringRef(Buffer), CompileArgs, Filename, "clang-tool",
+ std::make_shared<PCHContainerOperations>(),
+ tooling::getClangStripDependencyFileAdjuster(), VirtualMappedFiles));
if (!AST.get())
return testing::AssertionFailure()
<< "Parsing error in \"" << Code << "\" while building AST";
@@ -433,6 +472,357 @@ template <typename T> class VerifyIdIsBoundTo : public BoundNodesCallback {
std::string Name;
};
+namespace detail {
+template <typename T>
+using hasDump_t = decltype(std::declval<const T &>().dump());
+template <typename T>
+constexpr bool hasDump = llvm::is_detected<hasDump_t, T>::value;
+
+template <typename T>
+using hasGetSourceRange_t =
+ decltype(std::declval<const T &>().getSourceRange());
+template <typename T>
+constexpr bool hasGetSourceRange =
+ llvm::is_detected<hasGetSourceRange_t, T>::value;
+
+template <typename T, std::enable_if_t<hasGetSourceRange<T>, bool> = true>
+std::optional<std::string> getText(const T *const Node,
+ const ASTContext &Context) {
+ return tooling::fixit::getText(*Node, Context).str();
+}
+inline std::optional<std::string> getText(const Attr *const Attribute,
+ const ASTContext &) {
+ return Attribute->getSpelling();
+}
+inline std::optional<std::string> getText(const void *const,
+ const ASTContext &) {
+ return std::nullopt;
+}
+
+template <typename T>
+auto getSourceRange(const T *const Node)
+ -> std::optional<decltype(Node->getSourceRange())> {
+ return Node->getSourceRange();
+}
+inline std::optional<SourceRange> getSourceRange(const void *const) {
+ return std::nullopt;
+}
+
+template <typename T>
+auto getLocation(const T *const Node)
+ -> std::optional<decltype(Node->getLocation())> {
+ return Node->getLocation();
+}
+inline std::optional<SourceLocation> getLocation(const void *const) {
+ return std::nullopt;
+}
+
+template <typename T>
+auto getBeginLoc(const T *const Node)
+ -> std::optional<decltype(Node->getBeginLoc())> {
+ return Node->getBeginLoc();
+}
+inline std::optional<SourceLocation> getBeginLoc(const void *const) {
+ return std::nullopt;
+}
+
+inline std::optional<SourceLocation>
+getLocOfTagDeclFromType(const Type *const Node) {
+ if (Node->isArrayType())
+ if (const auto *const AType = Node->getPointeeOrArrayElementType()) {
+ return getLocOfTagDeclFromType(AType);
+ }
+ if (const auto *const TDecl = Node->getAsTagDecl()) {
+ return TDecl->getLocation();
+ }
+ return std::nullopt;
+}
+inline std::optional<SourceLocation>
+getLocOfTagDeclFromType(const void *const) {
+ return std::nullopt;
+}
+
+template <typename T>
+auto getExprLoc(const T *const Node)
+ -> std::optional<decltype(Node->getBeginLoc())> {
+ return Node->getBeginLoc();
+}
+inline std::optional<SourceLocation> getExprLoc(const void *const) {
+ return std::nullopt;
+}
+
+// Provides a string for test failures to show what was matched.
+template <typename T>
+static std::optional<std::string>
+getNodeDescription(const T *const Node, const ASTContext *const Context) {
+ if constexpr (std::is_same_v<T, QualType>) {
+ return Node->getAsString();
+ }
+ if constexpr (std::is_base_of_v<NamedDecl, T>) {
+ return Node->getNameAsString();
+ }
+ if constexpr (std::is_base_of_v<Type, T>) {
+ return QualType{Node, 0}.getAsString();
+ }
+
+ return detail::getText(Node, *Context);
+}
+
+template <typename T>
+bool shouldIgnoreNode(const T *const Node, const ASTContext &Context) {
+ if (const auto Range = detail::getSourceRange(Node); Range.has_value()) {
+ if (Range->isInvalid() ||
+ !Context.getSourceManager().isInMainFile(Range->getBegin()))
+ return true;
+ } else if (const auto Loc = detail::getExprLoc(Node); Loc.has_value()) {
+ if (Loc->isInvalid() || !Context.getSourceManager().isInMainFile(*Loc))
+ return true;
+ } else if (const auto Loc = detail::getLocation(Node); Loc.has_value()) {
+ if (Loc->isInvalid() || !Context.getSourceManager().isInMainFile(*Loc))
+ return true;
+ } else if (const auto Loc = detail::getBeginLoc(Node); Loc.has_value()) {
+ if (Loc->isInvalid() || !Context.getSourceManager().isInMainFile(*Loc))
+ return true;
+ } else if (const auto Loc = detail::getLocOfTagDeclFromType(Node);
+ Loc.has_value()) {
+ if (Loc->isInvalid() || !Context.getSourceManager().isInMainFile(*Loc))
+ return true;
+ }
+ return false;
+}
+} // namespace detail
+
+enum class MatchKind {
+ Code,
+ Name,
+ TypeStr,
+};
+
+inline llvm::StringRef toString(const MatchKind Kind) {
+ switch (Kind) {
+ case MatchKind::Code:
+ return "Code";
+ case MatchKind::Name:
+ return "Name";
+ case MatchKind::TypeStr:
+ return "TypeStr";
+ }
+ llvm_unreachable("Unhandled MatchKind");
+}
+
+template <typename T> class VerifyBoundNodeMatch : public BoundNodesCallback {
+public:
+ class Match {
+ public:
+ Match(const MatchKind Kind, std::string MatchString,
+ const size_t MatchCount = 1)
+ : Kind(Kind), MatchString(std::move(MatchString)),
+ RemainingMatches(MatchCount) {}
+
+ bool shouldRemoveMatched() {
+ --RemainingMatches;
+ return RemainingMatches == 0U;
+ }
+
+ template <typename U>
+ static std::optional<std::string>
+ getMatchText(const U *const Node, const ASTContext &Context,
+ const MatchKind Kind, const bool EmitFailures = true) {
+ if constexpr (std::is_same_v<U, NestedNameSpecifier>) {
+ if (const IdentifierInfo *const Info = Node->getAsIdentifier())
+ return Info->getName().str();
+ if (const NamespaceDecl *const NS = Node->getAsNamespace())
+ return getMatchText(NS, Context, Kind, EmitFailures);
+ if (const NamespaceAliasDecl *const Alias = Node->getAsNamespaceAlias())
+ return getMatchText(Alias, Context, Kind, EmitFailures);
+ if (const CXXRecordDecl *const RDecl = Node->getAsRecordDecl())
+ return getMatchText(RDecl, Context, Kind, EmitFailures);
+ if (const Type *const RDecl = Node->getAsType())
+ return getMatchText(RDecl, Context, Kind, EmitFailures);
+ }
+
+ switch (Kind) {
+ case MatchKind::Code:
+ return detail::getText(Node, Context);
+ case MatchKind::Name:
+ return getNameText(Node, EmitFailures);
+ case MatchKind::TypeStr:
+ return getTypeStrText(Node, EmitFailures);
+ }
+
+ return std::nullopt;
+ }
+
+ bool isMatch(const T *const Node, const ASTContext &Context) const {
+ if (const auto OptMatchText = getMatchText(Node, Context, Kind))
+ return *OptMatchText == MatchString;
+
+ return false;
+ }
+
+ std::string getAsString() const {
+ return llvm::formatv("MatchKind: {0}, MatchString: '{1}', "
+ "RemainingMatches: {2}",
+ toString(Kind), MatchString, RemainingMatches)
+ .str();
+ }
+
+ MatchKind getMatchKind() const { return Kind; }
+ llvm::StringRef getMatchString() const { return MatchString; }
+
+ private:
+ template <typename U>
+ static std::optional<std::string>
+ getNameText(const U *const Node, const bool EmitFailures = true) {
+ if constexpr (std::is_base_of_v<Decl, U>) {
+ if (const auto *const NDecl = llvm::dyn_cast<NamedDecl>(Node))
+ return NDecl->getNameAsString();
+ if (EmitFailures)
+ ADD_FAILURE() << "'MatchKind::Name' requires 'U' to be a'NamedDecl'.";
+ }
+
+ if (EmitFailures)
+ ADD_FAILURE() << "'MatchKind::Name' requires 'U' to be a "
+ "'NamedDecl', but 'U' is not derived from 'Decl'.";
+ return std::nullopt;
+ }
+
+ template <typename U>
+ static std::optional<std::string>
+ getTypeStrText(const U *const Node, const bool EmitFailures = true) {
+ if constexpr (std::is_base_of_v<Type, U>)
+ return QualType(Node, 0).getAsString();
+ if constexpr (std::is_base_of_v<Decl, U>) {
+ if (const auto *const TDecl = llvm::dyn_cast<TypeDecl>(Node))
+ return getTypeStrText(TDecl->getTypeForDecl());
+ if (const auto *const VDecl = llvm::dyn_cast<ValueDecl>(Node))
+ return VDecl->getType().getAsString();
+ }
+ if (EmitFailures)
+ ADD_FAILURE() << "Match kind is 'TypeStr', but node of type 'U' is "
+ "not handled.";
+ return std::nullopt;
+ }
+
+ MatchKind Kind;
+ std::string MatchString;
+ size_t RemainingMatches;
+ };
+
+ VerifyBoundNodeMatch(std::string Id, std::vector<Match> Matches)
+ : Id(std::move(Id)), ExpectedMatches(std::move(Matches)),
+ Matches(ExpectedMatches) {}
+
+ bool run(const BoundNodes *const Nodes, ASTContext *const Context) override {
+ const auto *const Node = Nodes->getNodeAs<T>(Id);
+ if (Node == nullptr) {
+ ADD_FAILURE() << "Expected Id '" << Id << "' to be bound to 'T'.";
+ return true;
+ }
+
+ if constexpr (std::is_base_of_v<Decl, T>)
+ if (const auto *const NDecl = llvm::dyn_cast<NamedDecl>(Node))
+ if (const auto *Identifier = NDecl->getIdentifier();
+ Identifier != nullptr && Identifier->getBuiltinID() > 0)
+ return true;
+
+ if (detail::shouldIgnoreNode(Node, *Context)) {
+ return false;
+ }
+
+ const auto Iter = llvm::find_if(Matches, [Node, Context](const Match &M) {
+ return M.isMatch(Node, *Context);
+ });
+ if (Iter == Matches.end()) {
+ const auto NodeText =
+ detail::getNodeDescription(Node, Context).value_or("<unknown>");
+ const auto IsMultilineNodeText = NodeText.find('\n') != std::string::npos;
+ ADD_FAILURE() << "No match of node '" << (IsMultilineNodeText ? "\n" : "")
+ << NodeText << (IsMultilineNodeText ? "\n" : "")
+ << "' was expected.\n"
+ << "No match with remaining matches:"
+ << getMatchComparisonText(Matches, Node, *Context)
+ << "Match strings of Node for possible intended matches:"
+ << getPossibleMatchStrings(Node, *Context)
+ << "Already found matches:"
+ << getMatchesAsString(FoundMatches) << "Expected matches:"
+ << getMatchesAsString(ExpectedMatches);
+ if constexpr (detail::hasDump<T>)
+ Node->dump();
+ return true;
+ }
+
+ if (Iter->shouldRemoveMatched()) {
+ FoundMatches.push_back(*Iter);
+ Matches.erase(Iter);
+ }
+
+ return true;
+ }
+
+ void onEndOfTranslationUnit() override {
+ if (!ExpectedMatches.empty() && Matches.size() == ExpectedMatches.size())
+ ADD_FAILURE() << "No matches were found.\n"
+ << "Expected matches:"
+ << getMatchesAsString(ExpectedMatches);
+ else
+ EXPECT_TRUE(Matches.empty())
+ << "Not all expected matches were found.\n"
+ << "Remaining matches:" << getMatchesAsString(Matches)
+ << "Already found matches:" << getMatchesAsString(FoundMatches)
+ << "Expected matches:" << getMatchesAsString(ExpectedMatches);
+
+ Matches = ExpectedMatches;
+ FoundMatches.clear();
+
+ EXPECT_TRUE(FoundMatches.empty());
+ }
+
+private:
+ static std::string getMatchesAsString(const std::vector<Match> &Matches) {
+ if (Matches.empty())
+ return " none\n";
+ std::string FormattedMatches{"\n"};
+ for (const Match &M : Matches)
+ FormattedMatches += "\t" + M.getAsString() + ",\n";
+
+ return FormattedMatches;
+ }
+ static std::string getMatchComparisonText(const std::vector<Match> &Matches,
+ const T *const Node,
+ const ASTContext &Context) {
+ if (Matches.empty())
+ return " none\n";
+ std::string MatchStrings{"\n"};
+ for (const Match &M : Matches)
+ MatchStrings += llvm::formatv(
+ "\tMatchKind: {0}: '{1}' vs '{2}',\n", toString(M.getMatchKind()),
+ Match::getMatchText(Node, Context, M.getMatchKind(), false)
+ .value_or("<unknown>"),
+ M.getMatchString());
+
+ return MatchStrings;
+ }
+
+ static std::string getPossibleMatchStrings(const T *Node,
+ const ASTContext &Context) {
+ std::string MatchStrings{"\n"};
+ for (const auto Kind :
+ {MatchKind::Code, MatchKind::Name, MatchKind::TypeStr})
+ MatchStrings +=
+ llvm::formatv("\tMatchKind: {0}: '{1}',\n", toString(Kind),
+ Match::getMatchText(Node, Context, Kind, false)
+ .value_or("<unknown>"))
+ .str();
+ return MatchStrings;
+ }
+
+ const std::string Id;
+ const std::vector<Match> ExpectedMatches;
+ std::vector<Match> Matches;
+ std::vector<Match> FoundMatches{};
+};
+
class ASTMatchersTest : public ::testing::Test,
public ::testing::WithParamInterface<TestClangConfig> {
protected:
@@ -453,6 +843,40 @@ class ASTMatchersTest : public ::testing::Test,
}
};
+class ASTMatchersDocTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<TestClangConfig> {
+protected:
+ template <typename T>
+ testing::AssertionResult
+ matches(const Twine &Code, const T &AMatcher,
+ std::unique_ptr<BoundNodesCallback> FindResultVerifier,
+ const ArrayRef<std::string> CompileArgs = {},
+ const FileContentMappings &VirtualMappedFiles = {}) {
+ const TestClangConfig &TestConfig = GetParam();
+
+ auto Args = TestConfig.getCommandLineArgs();
+ Args.insert(Args.end(), CompileArgs.begin(), CompileArgs.end());
+ return clang::ast_matchers::matchAndVerifyResultConditionally(
+ Code, AMatcher, std::move(FindResultVerifier), /*ExpectMatch=*/true,
+ Args, getFilenameForTesting(TestConfig.Language), VirtualMappedFiles);
+ }
+
+ template <typename T>
+ testing::AssertionResult
+ notMatches(const Twine &Code, const T &AMatcher,
+ std::unique_ptr<BoundNodesCallback> FindResultVerifier,
+ const ArrayRef<std::string> CompileArgs = {},
+ const FileContentMappings &VirtualMappedFiles = {}) {
+ const TestClangConfig &TestConfig = GetParam();
+
+ auto Args = TestConfig.getCommandLineArgs();
+ Args.insert(Args.begin(), CompileArgs.begin(), CompileArgs.end());
+ return clang::ast_matchers::matchAndVerifyResultConditionally(
+ Code, AMatcher, std::move(FindResultVerifier), /*ExpectMatch=*/false,
+ Args, getFilenameForTesting(TestConfig.Language), VirtualMappedFiles);
+ }
+};
} // namespace ast_matchers
} // namespace clang
diff --git a/clang/unittests/ASTMatchers/CMakeLists.txt b/clang/unittests/ASTMatchers/CMakeLists.txt
index 6a1e629d81b65b..3370f31cf6f28b 100644
--- a/clang/unittests/ASTMatchers/CMakeLists.txt
+++ b/clang/unittests/ASTMatchers/CMakeLists.txt
@@ -4,11 +4,26 @@ set(LLVM_LINK_COMPONENTS
TargetParser
)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ASTMatchersDocTests.cpp
+ COMMAND
+ ${CLANG_SOURCE_DIR}/utils/generate_ast_matcher_doc_tests.py ARGS
+ --input-file
+ ${CLANG_SOURCE_DIR}/include/clang/ASTMatchers/ASTMatchers.h
+ --output-file
+ ${CMAKE_CURRENT_BINARY_DIR}/ASTMatchersDocTests.cpp
+ MAIN_DEPENDENCY
+ ${CLANG_SOURCE_DIR}/include/clang/ASTMatchers/ASTMatchers.h
+ DEPENDS
+ ${CLANG_SOURCE_DIR}/utils/generate_ast_matcher_doc_tests.py
+)
+
add_clang_unittest(ASTMatchersTests
ASTMatchersInternalTest.cpp
ASTMatchersNodeTest.cpp
ASTMatchersNarrowingTest.cpp
ASTMatchersTraversalTest.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/ASTMatchersDocTests.cpp
GtestMatchersTest.cpp
)
diff --git a/clang/utils/generate_ast_matcher_doc_tests.py b/clang/utils/generate_ast_matcher_doc_tests.py
new file mode 100755
index 00000000000000..2ee40d8a660684
--- /dev/null
+++ b/clang/utils/generate_ast_matcher_doc_tests.py
@@ -0,0 +1,1097 @@
+#!/usr/bin/env python3
+R"""
+TLDR:
+The order for a single code snippet example is:
+
+ \header{a.h}
+ \endheader <- zero or more header
+
+ \code
+ int a = 42;
+ \endcode
+ \compile_args{-std=c++,c23-or-later} <- optional, supports std ranges and
+ whole languages
+
+ \matcher{expr()} <- one or more matchers in succession
+ \match{42} <- one ore more matches in succession
+
+ \matcher{varDecl()} <- new matcher resets the context, the above
+ \match will not count for this new
+ matcher(-group)
+ \match{int a = 42} <- only applies to the previous matcher (no the
+ previous case)
+
+The above block can be repeated inside of a doxygen command for multiple
+code examples.
+
+Language Grammar:
+ [] denotes an optional, and <> denotes user-input
+
+ compile_args j:= \compile_args{[<compile_arg>;]<compile_arg>}
+ matcher_tag_key ::= type
+ match_tag_key ::= type || std || count
+ matcher_tags ::= [matcher_tag_key=<value>;]matcher_tag_key=<value>
+ match_tags ::= [match_tag_key=<value>;]match_tag_key=<value>
+ matcher ::= \matcher{[matcher_tags$]<matcher>}
+ matchers ::= [matcher] matcher
+ match ::= \match{[match_tags$]<match>}
+ matches ::= [match] match
+ case ::= matchers matches
+ cases ::= [case] case
+ header-block ::= \header{<name>} <code> \endheader
+ code-block ::= \code <code> \endcode
+ testcase ::= code-block [compile_args] cases
+
+The 'std' tag and '\compile_args' support specifying a specific
+language version, a whole language and all of it's versions, and thresholds
+(implies ranges). Multiple arguments are passed with a ',' seperator.
+For a language and version to execute a tested matcher, it has to match
+the specified '\compile_args' for the code, and the 'std' tag for the matcher.
+Predicates for the 'std' compiler flag are used with disjunction between
+languages (e.g. 'c || c++') and conjunction for all predicates specific
+to each language (e.g. 'c++11-or-later && c++23-or-earlier').
+
+Examples:
+ - c all available versions of C
+ - c++11 only C++11
+ - c++11-or-later C++11 or later
+ - c++11-or-earlier C++11 or earlier
+ - c++11-or-later,c++23-or-earlier,c all of C and C++ between 11 and
+ 23 (inclusive)
+ - c++11-23,c same as above
+
+Tags:
+
+ Type:
+ Match types are used to select where the string that is used to check if
+ a node matches comes from.
+ Available: code, name, typestr, typeofstr.
+ The default is 'code'.
+
+ Matcher types are used to mark matchers as submatchers with 'sub' or as
+ deactivated using 'none'. Testing submatchers is not implemented.
+
+ Count:
+ Specifying a 'count=n' on a match will result in a test that requires that
+ the specified match will be matched n times. Default is 1.
+
+ Std:
+ A match allows specifying if it matches only in specific language versions.
+ This may be needed when the AST
diff ers between language versions.
+"""
+
+import re
+from argparse import ArgumentParser, Namespace
+from collections import defaultdict
+from enum import Enum
+from functools import reduce
+from pathlib import Path
+from sys import exit
+
+statistics = defaultdict(int)
+
+expected_failure_statistics = {
+ "missing_tests": 10,
+ "skipped_objc": 42,
+ "none_type_matchers": 6,
+}
+
+found_issue = False
+
+
+def parse_arguments() -> Namespace:
+ parser = ArgumentParser(
+ description="extract test cases from the documentation comments of AST"
+ " matchers",
+ )
+
+ parser.add_argument(
+ "--output-file",
+ help="The path to the ASTMatchersDocTest.cpp file where the tests are"
+ " written to.",
+ type=Path,
+ )
+
+ parser.add_argument(
+ "--input-file",
+ help="The path to the ASTMatchers.h file",
+ type=Path,
+ )
+
+ return parser.parse_args()
+
+
+def matcher_to_node_type(matcher: str) -> str:
+ """Converts the written top-level matcher to the node type that the matcher
+ will bind.
+ Contains special cases because not all matcher names can be simply converted
+ to a type by spelling it with uppercase characters in the beginning.
+
+ Args:
+ matcher: The matcher string
+
+ Returns:
+ The type of the node that a match will bind to
+ """
+ if matcher.startswith("traverse"):
+ comma_loc = matcher.find(",")
+ return matcher_to_node_type(matcher[comma_loc + 1 :].strip())
+ if matcher.startswith("cxxBoolLiteral"):
+ return "CXXBoolLiteralExpr"
+ if matcher.startswith("binaryOperation"):
+ return "Expr"
+ if matcher.startswith("invocation"):
+ return "Expr"
+ if matcher.startswith("alignOfExpr"):
+ return "Expr"
+ if matcher.startswith("sizeOfExpr"):
+ return "Expr"
+ if matcher.startswith("floatLiteral"):
+ return "FloatingLiteral"
+ if matcher.startswith("gnuNullExpr"):
+ return "GNUNullExpr"
+ if matcher.startswith("cxx"):
+ return "CXX" + matcher[3 : matcher.find("(")]
+ if matcher.startswith("omp"):
+ return "OMP" + matcher[3 : matcher.find("(")]
+ if matcher.startswith("cuda"):
+ return "CUDA" + matcher[4 : matcher.find("(")]
+ if matcher.startswith("objc"):
+ return "ObjC" + matcher[4 : matcher.find("(")]
+ return matcher[0:1].upper() + matcher[1 : matcher.find("(")]
+
+
+def get_clang_config_constraint_expr(std: str) -> str:
+ """Converts a single argument to 'std' into the corresponding check to be
+ done in the tests.
+
+ Args:
+ std: A single argument to 'std' (e.g. 'c++11-or-later')
+
+ Returns:
+ An expression that checks is the test config enables what the 'std'
+ argument specifies.
+ """
+ if std == "":
+ return ""
+
+ or_later_str = "-or-later"
+ or_earlier_str = "-or-earlier"
+ match = re.match(r"c(\d\d)-?(\d\d)?", std)
+ if match:
+ if len(match.groups()) == 3:
+ return f"Conf.isCOrLater({match.group(1)}) && Conf.isOrEarlier({match.group(2)})"
+ if std.endswith(or_later_str):
+ return f"Conf.isCOrLater({match.group(1)})"
+ if std.endswith(or_earlier_str):
+ return f"Conf.isCOrEarlier({match.group(1)})"
+ return f"Conf.Language == Lang_C{match.group(1)}"
+
+ match = re.match(r"c\+\+(\d\d)-?(\d\d)?", std)
+ if match:
+ if len(match.groups()) == 3:
+ return f"Conf.isCXXOrLater({match.group(1)}) && Conf.isCXXOrEarlier({match.group(2)})"
+ if std.endswith(or_later_str):
+ return f"Conf.isCXXOrLater({match.group(1)})"
+ if std.endswith(or_earlier_str):
+ return f"Conf.isCXXOrEarlier({match.group(1)})"
+ return f"Conf.Language == Lang_CXX{match.group(1)}"
+
+ if std == "c":
+ return "Conf.isC()"
+
+ if std == "c++":
+ return "Conf.isCXX()"
+
+ if std.startswith("-ObjC"):
+ return ""
+
+ return ""
+
+
+class TestLanguage:
+ """Wraps multiple args to 'std' for emitting the config check inside the
+ tests.
+
+ Attributes:
+ raw: The arg to 'std' as written
+ c: The config check expression for C
+ cxx: The config check expression for C++
+ objc: The config check expression for ObjC
+ """
+
+ def __init__(self, std: str) -> None:
+ self.raw = std
+ self.c = ""
+ self.cxx = ""
+ self.objc = ""
+ if std.startswith("-ObjC"):
+ self.objc = std
+ return
+
+ for standard_spec in std.split(","):
+ expr = get_clang_config_constraint_expr(standard_spec)
+ if standard_spec.startswith("c++"):
+ if self.cxx != "":
+ self.cxx += " && "
+ self.cxx += expr
+ elif standard_spec.startswith("c"):
+ if self.c != "":
+ self.c += " && "
+ self.c += expr
+
+ def has_value(self):
+ return self.c != "" or self.cxx != "" or self.objc != ""
+
+ def get_config_check_expr(self):
+ if self.c != "" and self.cxx != "":
+ return f"({self.c}) || ({self.cxx})"
+ if self.c != "":
+ return self.c
+ if self.cxx != "":
+ return self.cxx
+ if self.objc != "":
+ return self.objc
+ return ""
+
+
+class Tags:
+ """Wrapper to parse and store the tags that can be passed to '\\match' and
+ '\\matcher'.
+
+ Attributes:
+ map: The parsed tags by key ('str' -> 'str' map)
+ opt_test_language: The 'std' tag is handled by TestLanguage
+ """
+
+ def __init__(self, tag_string: str) -> None:
+ self.map = defaultdict(
+ lambda: "",
+ [split_first(tag, "=") for tag in tag_string.split(";")],
+ )
+
+ self.opt_test_language = None
+ if "std" in self.map:
+ self.opt_test_language = TestLanguage(self.map["std"])
+ self.map.pop("std")
+
+
+class Matcher:
+ def __init__(self, matcher: str, tags: Tags) -> None:
+ self.matcher = matcher
+ self.tags = tags
+
+ def is_sub_matcher(self) -> bool:
+ return self.tags.map["type"] == "sub"
+
+ def __format__(self, format_spec: str) -> str:
+ return self.matcher.__format__(format_spec)
+
+ def __str__(self) -> str:
+ return f"{self.matcher}"
+
+ def __repr__(self) -> str:
+ return f"{self.matcher}"
+
+
+class Match:
+ def __init__(self, match_str: str, tags: Tags) -> None:
+ self.match_str = match_str.replace("\n", " ")
+ self.tags = tags
+
+ def is_sub_match(self) -> bool:
+ return self.tags.map["sub"] != ""
+
+ def __format__(self, format_spec: str) -> str:
+ return self.match_str.__format__(format_spec)
+
+ def __str__(self) -> str:
+ return f"{self.match_str}"
+
+ def __repr__(self) -> str:
+ return f"{self.match_str}"
+
+ def get_as_cpp_raw_string(self) -> str:
+ return f'R"cpp({self.match_str})cpp"'
+
+
+def get_lang_spec_and_remove_from_list(args: list) -> str:
+ for arg in args:
+ if arg == "-ObjC":
+ args.remove(arg)
+ return arg
+ if arg.startswith("-std="):
+ args.remove(arg)
+ return arg[5:]
+ return ""
+
+
+class CompileArgs:
+ """Represents the '\\compile_args' command and its arguments.
+
+ Attributes:
+ lang_spec: The specified test language
+ args: All other arguments
+ """
+
+ def __init__(self, args: list) -> None:
+ self.lang_spec = TestLanguage(get_lang_spec_and_remove_from_list(args))
+ self.args = args
+
+ if any(("cuda" in arg for arg in self.args)) and not any(
+ "-x" in arg for arg in self.args
+ ):
+ self.args.append("-xcuda")
+ self.args.append("-nocudainc")
+ self.args.append("-nocudalib")
+
+ def is_cuda(self) -> bool:
+ return any("cuda" in cmd for cmd in self.args)
+
+ def is_objc(self) -> bool:
+ return self.lang_spec.objc != ""
+
+
+def get_any_valid_std_specified(lang_spec: str) -> str:
+ """Get any argument to '-std' that satisfies the language specification
+ in 'lang_spec'
+
+ Args:
+ lang_spec: An argument to 'std'
+
+ Returns:
+ Any valid argument to the '-std' compiler flag that satisfies
+ 'lang_spec'
+ """
+ if lang_spec == "":
+ return "c++11"
+
+ first_comma = lang_spec.find(",")
+ if first_comma != -1:
+ lang_spec = lang_spec[:first_comma]
+
+ first_minus = lang_spec.find("-")
+ if first_minus != -1:
+ lang_spec = lang_spec[:first_minus]
+
+ elif lang_spec == "c":
+ lang_spec = "c11"
+ elif lang_spec == "c++":
+ lang_spec = "c++11"
+
+ return lang_spec
+
+
+def get_with_lang_spec(args: CompileArgs) -> list:
+ """Construct compiler arguments from a CompileArgs instance
+
+ Args:
+ args: The arguments to '\\compile_args'
+
+ Returns:
+ A list of compiler arguments that satisfy what is specified in 'args'
+ """
+ if args.lang_spec.objc.startswith("-ObjC"):
+ return [*args.args, args.lang_spec.objc]
+
+ if args.lang_spec.has_value():
+ return [*args.args, "-std=" + get_any_valid_std_specified(args.lang_spec.raw)]
+
+ return args.args
+
+
+cuda_header: str = """
+ typedef unsigned long long size_t;
+ #define __constant__ __attribute__((constant))
+ #define __device__ __attribute__((device))
+ #define __global__ __attribute__((global))
+ #define __host__ __attribute__((host))
+ #define __shared__ __attribute__((shared))
+ struct dim3 {
+ unsigned x, y, z;
+ __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)
+ : x(x), y(y), z(z) {}
+ };
+ typedef struct cudaStream *cudaStream_t;
+ int cudaConfigureCall(dim3 gridSize, dim3 blockSize,
+ size_t sharedSize = 0,
+ cudaStream_t stream = 0);
+ extern "C" unsigned __cudaPushCallConfiguration(
+ dim3 gridDim, dim3 blockDim, size_t sharedMem = 0, void *stream =
+ 0);
+"""
+
+
+class MatchType(Enum):
+ """Available types of a match, specified by using the lowercase version in
+ doxygen: '\\match{type=typestr}'.
+ Specifies what string from the matched node should be used to check for a
+ match.
+
+ Attributes:
+ Invalid: Specified an invalid match type
+ Code: Check if a matched node matches by using it's text
+ (SourceRange -> Lexer)
+ Name: Use the name of the matched node to check if it matches
+ TypeStr: Use the string representation of the matched type to check if
+ it matches
+ """
+
+ Invalid = 0
+ Code = 1
+ Name = 2
+ TypeStr = 3
+
+
+def get_match_type(match: Match) -> MatchType:
+ match_type = match.tags.map["type"]
+ if match_type == "name":
+ return MatchType.Name
+ if match_type == "" or match_type == "code":
+ return MatchType.Code
+ if match_type == "typestr":
+ return MatchType.TypeStr
+ print(f"match {match} has an invalid match type: {match_type}")
+ statistics["match_type_invalid"] += 1
+ return MatchType.Invalid
+
+
+def get_match_count(match: Match) -> str:
+ count = match.tags.map["count"]
+ if count == "":
+ return "1"
+ return count
+
+
+def construct_match(match: Match) -> str:
+ result = ""
+ if match.tags.opt_test_language:
+ result += f"\tif ({match.tags.opt_test_language.get_config_check_expr()})\n\t"
+
+ result += f"\tMatches.emplace_back(MatchKind::{get_match_type(match).name}, {match.get_as_cpp_raw_string()}, {get_match_count(match)});"
+ return result
+
+
+class TestCase:
+ """Represents a single code example and its tests. Tests are added during
+ parsing and finally emitted as C++ test code.
+
+ Attributes:
+ input_file: The file path where the matcher was specified
+ line: The line that the test case starts at
+ cases: The collected cases for this example code
+ code: The example code
+ headers: Headers, if any
+ compile_args: Compile arguments, if any
+ """
+
+ def __init__(self, input_file: Path, line: int):
+ self.input_file = input_file
+ self.line = line
+ self.cases: list[tuple[list[Matcher], list[Match]]] = []
+ self.code: str = ""
+ self.headers: list[tuple[str, str]] = []
+ self.compile_args = None
+
+ def get_last_case(self) -> tuple:
+ return self.cases[-1]
+
+ def add_case(self):
+ self.cases.append(([], []))
+
+ def add_matcher(self, matcher: Matcher):
+ self.get_last_case()[0].append(matcher)
+
+ def add_match(self, match: Match):
+ self.get_last_case()[1].append(match)
+
+ def has_non_lang_spec_compile_args(self) -> bool:
+ return self.compile_args is not None and len(self.compile_args.args) != 0
+
+ def has_headers(self) -> bool:
+ return len(self.headers) != 0
+
+ def get_compile_commands(self) -> str:
+ if self.compile_args is None:
+ return "{}"
+ return "{ " + ",".join([f'"{arg}"' for arg in self.compile_args.args]) + " }"
+
+ def diag(self, message: str):
+ print(f"{self.input_file}:{self.line + 1}: {message}")
+
+ def has_match_with_std_constraint(self) -> bool:
+ return any(
+ (
+ any(match.tags.opt_test_language for match in case[1])
+ for case in self.cases
+ ),
+ )
+
+ def get_formated_headers(self) -> str:
+ return "\n\t".join(
+ f'std::pair{{"{header[0]}", \n\tR"cpp({header[1]})cpp"}},'
+ for header in self.headers
+ )
+
+ def build_test_case(self):
+ self.code = self.code.strip("\n")
+ has_cuda = self.compile_args and self.compile_args.is_cuda()
+ if has_cuda:
+ self.headers.append(("cuda.h", cuda_header))
+
+ res = ""
+ if has_cuda:
+ res += "#if LLVM_HAS_NVPTX_TARGET\n"
+
+ res += f"""TEST_P(ASTMatchersDocTest, docs_{self.line + 1}) {{
+ const StringRef Code = R"cpp(\n"""
+ if has_cuda:
+ res += '\t#include "cuda.h"\n'
+ res += f'{self.code})cpp";\n'
+
+ if self.has_headers():
+ res += f"\tconst FileContentMappings VirtualMappedFiles = {{{self.get_formated_headers()}}};"
+
+ if self.compile_args and self.compile_args.lang_spec.objc != "":
+ statistics["skipped_objc"] += 1
+ return ""
+
+ statistics["code_snippets"] += 1
+
+ statistics["matches"] += reduce(
+ lambda a, b: a + b,
+ (len(v[1]) for v in self.cases),
+ )
+
+ statistics["matchers"] += reduce(
+ lambda a, b: a + b,
+ (len(v[0]) for v in self.cases),
+ )
+
+ if self.compile_args and self.compile_args.lang_spec.has_value():
+ res += f"""
+ const TestClangConfig& Conf = GetParam();
+ const bool ConfigEnablesCheckingCode = {self.compile_args.lang_spec.get_config_check_expr()};
+ if (!ConfigEnablesCheckingCode) return;\n"""
+
+ elif self.has_match_with_std_constraint():
+ res += "\n\tconst TestClangConfig& Conf = GetParam();\n"
+
+ # Don't want to emit a test without any actual tested matchers.
+ # Would result in warnings about unused variables (Code) during the
+ # build.
+ case_has_test = False
+
+ for matchers, matches in self.cases:
+ if len(matchers) == 0:
+ self.diag("test cases have no matchers")
+ continue
+
+ for matcher in matchers:
+ if matcher.matcher.startswith("objc"):
+ statistics["skipped_objc"] += 1
+ continue
+ # FIXME: add support for testing submatchers
+ if matcher.tags.map["type"] == "sub":
+ continue
+ if matcher.tags.map["type"] == "none":
+ statistics["none_type_matchers"] += 1
+ continue
+ matcher_type = matcher_to_node_type(matcher.matcher)
+
+ statistics["tested_matchers"] += 1
+ case_has_test = True
+
+ verifier_type = f"VerifyBoundNodeMatch<{matcher_type}>"
+
+ code_adding_matches = "\n".join(
+ construct_match(match)
+ for match in matches
+ if match.tags.map["sub"] == ""
+ )
+
+ match_function = (
+ "matches" if len(code_adding_matches) != 0 else "notMatches"
+ )
+
+ res += f"""
+ {{
+ SCOPED_TRACE("Test failure from docs_{self.line + 1} originates here.");
+ using Verifier = {verifier_type};
+
+ std::vector<Verifier::Match> Matches;
+{code_adding_matches}
+
+ EXPECT_TRUE({match_function}(
+ Code,
+ {matcher.matcher}.bind("match"),
+ std::make_unique<Verifier>("match", Matches)"""
+
+ if self.has_headers():
+ res += f",\n\t\t{self.get_compile_commands()}"
+ res += ",\n\t\tVirtualMappedFiles"
+ elif self.has_non_lang_spec_compile_args():
+ res += f",\n\t\t{self.get_compile_commands()}"
+
+ res += "));\n\t}\n"
+
+ if not case_has_test:
+ return ""
+
+ res += "}"
+ if has_cuda:
+ res += "\n#endif\n"
+ return res
+
+
+class ParsingContext(Enum):
+ NoneCtx = 0
+ Code = 1
+ Header = 2
+ CompileArgs = 3
+ Matcher = 4
+ Match = 5
+ NoMatch = 6
+
+
+def split_first(data: str, delim: str) -> tuple:
+ pos = data.find(delim)
+ if pos == -1:
+ return (data, "")
+
+ return (data[0:pos], data[pos + 1 :])
+
+
+def find_matching_closing_rbrace(
+ data: str,
+ start_pos: int,
+ braces_to_be_matched: int,
+) -> int:
+ next_lbrace = data.find("{", start_pos)
+ next_rbrace = data.find("}", start_pos)
+ if next_lbrace != -1:
+ if next_lbrace < next_rbrace:
+ return find_matching_closing_rbrace(
+ data,
+ next_lbrace + 1,
+ braces_to_be_matched + 1,
+ )
+ if braces_to_be_matched == 0:
+ return next_rbrace
+ return find_matching_closing_rbrace(
+ data,
+ next_rbrace + 1,
+ braces_to_be_matched - 1,
+ )
+
+ if braces_to_be_matched > 0:
+ return find_matching_closing_rbrace(
+ data,
+ next_rbrace + 1,
+ braces_to_be_matched - 1,
+ )
+
+ return next_rbrace
+
+
+class CommentedMatcher:
+ """Represents a matcher and it's corresponding doxygen comment.
+
+ Attributes:
+ comment: The doxygen comment
+ matcher: The actual matcher code/implementation
+ """
+
+ def __init__(
+ self,
+ comment: list,
+ matcher: list,
+ ):
+ self.comment = comment
+ self.matcher = matcher
+
+
+class BlockParser:
+ """The parser that parses the test cases from a doxygen block.
+
+ Attributes:
+ input_file: The file where the matchers are located
+ cases: All TestCases
+ current_line: The line that the parser is currently on
+ data: The lines in the comment
+ """
+
+ def __init__(self, data: CommentedMatcher, input_file: Path):
+ self.input_file = input_file
+ self.cases = list()
+ self.current_line = data.comment[0][0]
+ self.data = "\n".join([line[1] for line in data.comment])
+ self.diagnostics = list()
+
+ def advance(self) -> ParsingContext:
+ """Find the next doxygen command to be parsed and return the
+ ParsingContext it represents.
+
+ Returns:
+ The ParsingContext of the location the parser arived at.
+ """
+ begin_tags = {
+ "\\code": ParsingContext.Code,
+ "\\header{": ParsingContext.Header,
+ "\\compile_args{": ParsingContext.CompileArgs,
+ "\\matcher{": ParsingContext.Matcher,
+ "\\match{": ParsingContext.Match,
+ "\\nomatch{": ParsingContext.NoMatch,
+ }
+
+ matches = list()
+
+ for tag, ctx in begin_tags.items():
+ match = self.data.find(tag)
+ if match == -1:
+ continue
+ matches.append((match, ctx, tag))
+
+ if len(matches) == 0:
+ return ParsingContext.NoneCtx
+
+ matches.sort()
+
+ loc, ctx, tag = matches[0]
+ loc = loc + len(tag) - 1
+ self.consume_until(loc)
+ return ctx
+
+ def add_case(self, line: int):
+ self.cases.append(TestCase(self.input_file, line))
+
+ def delete_last_test(self):
+ self.cases.pop()
+
+ def get_last_case(self) -> TestCase:
+ return self.cases[-1]
+
+ def add_matcher(self, matcher: Matcher):
+ if matcher.is_sub_matcher():
+ return
+ self.get_last_case().add_matcher(matcher)
+
+ def add_match(self, match: Match):
+ if match.is_sub_match():
+ return
+ self.get_last_case().add_match(match)
+
+ def consume_until(self, pos: int):
+ self.current_line += self.data.count("\n", 0, pos)
+ self.data = self.data[pos + 1 :]
+
+ def visit_code_block(self):
+ code_end = "\\endcode"
+ endcode_loc = self.data.find(code_end)
+ end = endcode_loc + len(code_end)
+
+ self.get_last_case().code = self.data[:endcode_loc].replace("\n", "\n\t")
+
+ self.consume_until(end)
+
+ def visit_header(self):
+ header_end = "\\endheader"
+ endheader_loc = self.data.find(header_end)
+ end = endheader_loc + len(header_end)
+
+ vrbrace_loc = find_matching_closing_rbrace(self.data, 0, 0)
+ header_name = self.data[0:vrbrace_loc]
+
+ self.get_last_case().headers.append(
+ (
+ header_name,
+ self.data[vrbrace_loc + 1 : endheader_loc].replace("\n", "\n\t"),
+ ),
+ )
+
+ self.consume_until(end)
+
+ def visit_compile_args(self):
+ end = find_matching_closing_rbrace(self.data, 0, 0)
+
+ args = self.data[:end]
+ self.consume_until(end)
+
+ self.get_last_case().compile_args = CompileArgs(
+ [split_arg for arg in args.split(";") for split_arg in arg.split(" ")],
+ )
+
+ def build_matcher(self):
+ end = find_matching_closing_rbrace(self.data, 0, 0)
+ tag_separator = self.data.find("$")
+ tags = Tags("")
+ if tag_separator != -1 and tag_separator < end:
+ tags = Tags(self.data[:tag_separator])
+ self.consume_until(tag_separator)
+
+ # find the '}' again, self.data shifted
+ end = find_matching_closing_rbrace(self.data, 0, 0)
+
+ matcher_str = self.data[:end]
+ if matcher_str.count("(") != matcher_str.count(")"):
+ self.diag(
+ f"The matcher {matcher_str} has an unbalanced number of parentheses"
+ )
+ self.consume_until(end)
+ return None
+
+ matcher = Matcher(self.data[:end], tags)
+ self.consume_until(end)
+ return matcher
+
+ def visit_match(self):
+ end = find_matching_closing_rbrace(self.data, 0, 0)
+ tag_separator = self.data.find("$")
+ tags = Tags("")
+ if tag_separator != -1 and tag_separator < end:
+ tags = Tags(self.data[:tag_separator])
+ self.consume_until(tag_separator)
+
+ # find the '}' again, self.data shifted
+ end = find_matching_closing_rbrace(self.data, 0, 0)
+ self.add_match(Match(self.data[:end], tags))
+ self.consume_until(end)
+
+ def diag(self, msg: str):
+ # Save diagnostics instead of emitting them to remove the noise of diagnosed issues,
+ # when the issues are all expected.
+ self.diagnostics.append(f"{self.input_file}:{self.current_line + 1}: {msg}")
+
+ def run(self):
+ ctx = self.advance()
+
+ if ctx == ParsingContext.NoneCtx:
+ self.diag("matcher is missing an example")
+ statistics["missing_tests"] += 1
+ return
+
+ while ctx != ParsingContext.NoneCtx:
+ self.add_case(self.current_line)
+ while ctx == ParsingContext.Header:
+ self.visit_header()
+ ctx = self.advance()
+
+ if ctx != ParsingContext.Code:
+ self.diag(f"expected {ParsingContext.Code}, not {ctx}")
+ statistics["missing_tests"] += 1
+ self.delete_last_test()
+ return
+
+ self.visit_code_block()
+ ctx = self.advance()
+
+ if ctx == ParsingContext.CompileArgs:
+ self.visit_compile_args()
+ compile_args = self.get_last_case().compile_args
+ ctx = self.advance()
+ if compile_args and compile_args.is_objc():
+ self.delete_last_test()
+ statistics["skipped_objc"] += 1
+
+ while ctx != ParsingContext.Code and ctx != ParsingContext.NoneCtx:
+ ctx = self.advance()
+
+ continue
+
+ if ctx != ParsingContext.Matcher:
+ if ctx == ParsingContext.NoneCtx:
+ self.diag(
+ "this code example is missing an example matcher and matches",
+ )
+ else:
+ self.diag(
+ f"expected {ParsingContext.Matcher} after {ParsingContext.Code}, not {ctx}",
+ )
+
+ statistics["missing_tests"] += 1
+ self.delete_last_test()
+ return
+
+ while ctx == ParsingContext.Matcher:
+ matcher = self.build_matcher()
+ if matcher and not matcher.is_sub_matcher():
+ self.get_last_case().add_case()
+
+ if matcher:
+ self.add_matcher(matcher)
+
+ ctx = self.advance()
+ while ctx == ParsingContext.Matcher:
+ matcher = self.build_matcher()
+ if matcher:
+ self.add_matcher(matcher)
+ ctx = self.advance()
+
+ if ctx != ParsingContext.Match and ctx != ParsingContext.NoMatch:
+ if ctx == ParsingContext.NoneCtx:
+ self.diag(
+ "this matcher does not specify what it should or shouldn't match",
+ )
+ else:
+ self.diag(
+ f"expected {ParsingContext.Match} or {ParsingContext.NoMatch} after {ParsingContext.Matcher}, not {ctx}",
+ )
+
+ statistics["matcher_groups_without_matches"] += 1
+ break
+
+ while ctx == ParsingContext.Match or ctx == ParsingContext.NoMatch:
+ if ctx == ParsingContext.Match:
+ self.visit_match()
+ ctx = self.advance()
+
+
+def parse_block(data: CommentedMatcher, input_file: Path) -> BlockParser:
+ parser = BlockParser(data, input_file)
+ parser.run()
+ return parser
+
+
+def parse(data: list, input_file: Path) -> tuple:
+ result: tuple = ([], [])
+
+ for parsed_block in [parse_block(block, input_file) for block in data]:
+ result[0].extend(parsed_block.cases)
+ result[1].extend(parsed_block.diagnostics)
+
+ return result
+
+
+def group_doc_comment_and_followed_code(
+ enumerated_lines: list,
+) -> list:
+ result: list = []
+
+ start_new_group_on_comment = True
+ for line_nr, line in enumerate(enumerated_lines, start=1):
+ if line.startswith("///"):
+ if start_new_group_on_comment:
+ result.append(CommentedMatcher([], []))
+ start_new_group_on_comment = False
+ if len(result) != 0:
+ result[-1].comment.append((line_nr, line[4:].rstrip()))
+ else:
+ start_new_group_on_comment = True
+ if len(result) != 0:
+ result[-1].matcher.append((line_nr, line))
+
+ return result
+
+
+test_file_begin = """
+// unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp - AST matcher unit tests//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTMatchersTest.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Testing/TestClangConfig.h"
+#include "gtest/gtest.h"
+#include <string>
+
+namespace clang {
+namespace ast_matchers {
+"""
+
+test_file_end = """
+static std::vector<TestClangConfig> allTestClangConfigs() {
+ std::vector<TestClangConfig> all_configs;
+ for (TestLanguage lang : {
+#define TESTLANGUAGE(lang, version, std_flag, index) Lang_##lang##version,
+#include "clang/Testing/TestLanguage.def"
+ }) {
+ TestClangConfig config;
+ config.Language = lang;
+
+ // Use an unknown-unknown triple so we don't instantiate the full system
+ // toolchain. On Linux, instantiating the toolchain involves stat'ing
+ // large portions of /usr/lib, and this slows down not only this test, but
+ // all other tests, via contention in the kernel.
+ //
+ // FIXME: This is a hack to work around the fact that there's no way to do
+ // the equivalent of runToolOnCodeWithArgs without instantiating a full
+ // Driver. We should consider having a function, at least for tests, that
+ // invokes cc1.
+ config.Target = "i386-unknown-unknown";
+ all_configs.push_back(config);
+
+ // Windows target is interesting to test because it enables
+ // `-fdelayed-template-parsing`.
+ config.Target = "x86_64-pc-win32-msvc";
+ all_configs.push_back(config);
+ }
+ return all_configs;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ASTMatchersTests, ASTMatchersDocTest,
+ testing::ValuesIn(allTestClangConfigs()),
+ [](const testing::TestParamInfo<TestClangConfig> &Info) {
+ return Info.param.toShortString();
+ });
+} // namespace ast_matchers
+} // namespace clang
+"""
+
+
+def main():
+ args = parse_arguments()
+
+ assert args.input_file.exists()
+
+ comment_blocks = group_doc_comment_and_followed_code(
+ args.input_file.read_text().split("\n"),
+ )
+
+ statistics["doxygen_blocks"] = len(comment_blocks)
+ results = parse(comment_blocks, args.input_file)
+
+ res: str = (
+ "\n\n".join(
+ filter(
+ lambda case: len(case) != 0,
+ [r.build_test_case() for r in results[0]],
+ ),
+ )
+ + "\n"
+ )
+
+ args.output_file.write_text(test_file_begin + res + test_file_end)
+
+ global found_issue
+ for key, value in expected_failure_statistics.items():
+ if value != statistics[key]:
+ print(
+ "Mismatch between expected and actual failure statistic: "
+ f"{key}: expected: {value}, actual: {statistics[key]}. "
+ "Please fix the issue or adjust the expected_failure_statistics"
+ " value if appropriate."
+ )
+ found_issue = True
+
+ if found_issue:
+ for diag in results[1]:
+ print(diag)
+
+ print("Statistics:")
+ for key, value in statistics.items():
+ print(f"\t{key: <30}: {value: >5}")
+
+ exit(1)
+
+
+# FIXME: add support in the html gen script to
diff erentiate between overloads examples
+# FIXME: should verify that all polymorphic ast nodes have a test
+
+
+if __name__ == "__main__":
+ main()
More information about the cfe-commits
mailing list