Skip to content

Commit 467a045

Browse files
committed
[ASTMatchers] Add matchers for decomposition decls
Differential Revision: https://reviews.llvm.org/D95739
1 parent c722575 commit 467a045

File tree

4 files changed

+180
-0
lines changed

4 files changed

+180
-0
lines changed

clang/docs/LibASTMatchersReference.html

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,15 @@ <h2 id="decl-matchers">Node Matchers</h2>
591591
</pre></td></tr>
592592

593593

594+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('bindingDecl0')"><a name="bindingDecl0Anchor">bindingDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>&gt;...</td></tr>
595+
<tr><td colspan="4" class="doc" id="bindingDecl0"><pre>Matches binding declarations
596+
Example matches foo and bar
597+
(matcher = bindingDecl()
598+
599+
auto [foo, bar] = std::make_pair{42, 42};
600+
</pre></td></tr>
601+
602+
594603
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('blockDecl0')"><a name="blockDecl0Anchor">blockDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>&gt;...</td></tr>
595604
<tr><td colspan="4" class="doc" id="blockDecl0"><pre>Matches block declarations.
596605

@@ -6011,6 +6020,24 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
60116020
</pre></td></tr>
60126021

60136022

6023+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>&gt;</td><td class="name" onclick="toggle('forDecomposition0')"><a name="forDecomposition0Anchor">forDecomposition</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt; InnerMatcher</td></tr>
6024+
<tr><td colspan="4" class="doc" id="forDecomposition0"><pre>Matches the DecompositionDecl the binding belongs to.
6025+
6026+
For example, in:
6027+
void foo()
6028+
{
6029+
int arr[3];
6030+
auto &amp;[f, s, t] = arr;
6031+
6032+
f = 42;
6033+
}
6034+
The matcher:
6035+
bindingDecl(hasName("f"),
6036+
forDecomposition(decompositionDecl())
6037+
matches 'f' in 'auto &amp;[f, s, t]'.
6038+
</pre></td></tr>
6039+
6040+
60146041
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BlockDecl.html">BlockDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyParameter2')"><a name="hasAnyParameter2Anchor">hasAnyParameter</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>&gt; InnerMatcher</td></tr>
60156042
<tr><td colspan="4" class="doc" id="hasAnyParameter2"><pre>Matches any parameter of a function or an ObjC method declaration or a
60166043
block.
@@ -7090,6 +7117,40 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
70907117
</pre></td></tr>
70917118

70927119

7120+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1DecompositionDecl.html">DecompositionDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyBinding0')"><a name="hasAnyBinding0Anchor">hasAnyBinding</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>&gt; InnerMatcher</td></tr>
7121+
<tr><td colspan="4" class="doc" id="hasAnyBinding0"><pre>Matches any binding of a DecompositionDecl.
7122+
7123+
For example, in:
7124+
void foo()
7125+
{
7126+
int arr[3];
7127+
auto &amp;[f, s, t] = arr;
7128+
7129+
f = 42;
7130+
}
7131+
The matcher:
7132+
decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
7133+
matches the decomposition decl with 'f' bound to "fBinding".
7134+
</pre></td></tr>
7135+
7136+
7137+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1DecompositionDecl.html">DecompositionDecl</a>&gt;</td><td class="name" onclick="toggle('hasBinding0')"><a name="hasBinding0Anchor">hasBinding</a></td><td>unsigned N, Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BindingDecl.html">BindingDecl</a>&gt; InnerMatcher</td></tr>
7138+
<tr><td colspan="4" class="doc" id="hasBinding0"><pre>Matches the Nth binding of a DecompositionDecl.
7139+
7140+
For example, in:
7141+
void foo()
7142+
{
7143+
int arr[3];
7144+
auto &amp;[f, s, t] = arr;
7145+
7146+
f = 42;
7147+
}
7148+
The matcher:
7149+
decompositionDecl(hasBinding(0, bindingDecl(hasName("f").bind("fBinding"))))
7150+
matches the decomposition decl with 'f' bound to "fBinding".
7151+
</pre></td></tr>
7152+
7153+
70937154
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
70947155
<tr><td colspan="4" class="doc" id="hasBody0"><pre></pre></td></tr>
70957156

clang/include/clang/ASTMatchers/ASTMatchers.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,16 @@ extern const internal::VariadicAllOfMatcher<Decl> decl;
347347
extern const internal::VariadicDynCastAllOfMatcher<Decl, DecompositionDecl>
348348
decompositionDecl;
349349

350+
/// Matches binding declarations
351+
/// Example matches \c foo and \c bar
352+
/// (matcher = bindingDecl()
353+
///
354+
/// \code
355+
/// auto [foo, bar] = std::make_pair{42, 42};
356+
/// \endcode
357+
extern const internal::VariadicDynCastAllOfMatcher<Decl, BindingDecl>
358+
bindingDecl;
359+
350360
/// Matches a declaration of a linkage specification.
351361
///
352362
/// Given
@@ -7379,6 +7389,80 @@ AST_MATCHER(Expr, nullPointerConstant) {
73797389
Expr::NPC_ValueDependentIsNull);
73807390
}
73817391

7392+
/// Matches the DecompositionDecl the binding belongs to.
7393+
///
7394+
/// For example, in:
7395+
/// \code
7396+
/// void foo()
7397+
/// {
7398+
/// int arr[3];
7399+
/// auto &[f, s, t] = arr;
7400+
///
7401+
/// f = 42;
7402+
/// }
7403+
/// \endcode
7404+
/// The matcher:
7405+
/// \code
7406+
/// bindingDecl(hasName("f"),
7407+
/// forDecomposition(decompositionDecl())
7408+
/// \endcode
7409+
/// matches 'f' in 'auto &[f, s, t]'.
7410+
AST_MATCHER_P(BindingDecl, forDecomposition, internal::Matcher<ValueDecl>,
7411+
InnerMatcher) {
7412+
if (const ValueDecl *VD = Node.getDecomposedDecl())
7413+
return InnerMatcher.matches(*VD, Finder, Builder);
7414+
return false;
7415+
}
7416+
7417+
/// Matches the Nth binding of a DecompositionDecl.
7418+
///
7419+
/// For example, in:
7420+
/// \code
7421+
/// void foo()
7422+
/// {
7423+
/// int arr[3];
7424+
/// auto &[f, s, t] = arr;
7425+
///
7426+
/// f = 42;
7427+
/// }
7428+
/// \endcode
7429+
/// The matcher:
7430+
/// \code
7431+
/// decompositionDecl(hasBinding(0,
7432+
/// bindingDecl(hasName("f").bind("fBinding"))))
7433+
/// \endcode
7434+
/// matches the decomposition decl with 'f' bound to "fBinding".
7435+
AST_MATCHER_P2(DecompositionDecl, hasBinding, unsigned, N,
7436+
internal::Matcher<BindingDecl>, InnerMatcher) {
7437+
if (Node.bindings().size() <= N)
7438+
return false;
7439+
return InnerMatcher.matches(*Node.bindings()[N], Finder, Builder);
7440+
}
7441+
7442+
/// Matches any binding of a DecompositionDecl.
7443+
///
7444+
/// For example, in:
7445+
/// \code
7446+
/// void foo()
7447+
/// {
7448+
/// int arr[3];
7449+
/// auto &[f, s, t] = arr;
7450+
///
7451+
/// f = 42;
7452+
/// }
7453+
/// \endcode
7454+
/// The matcher:
7455+
/// \code
7456+
/// decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
7457+
/// \endcode
7458+
/// matches the decomposition decl with 'f' bound to "fBinding".
7459+
AST_MATCHER_P(DecompositionDecl, hasAnyBinding, internal::Matcher<BindingDecl>,
7460+
InnerMatcher) {
7461+
return llvm::any_of(Node.bindings(), [&](const auto *Binding) {
7462+
return InnerMatcher.matches(*Binding, Finder, Builder);
7463+
});
7464+
}
7465+
73827466
/// Matches declaration of the function the statement belongs to
73837467
///
73847468
/// Given:

clang/lib/ASTMatchers/Dynamic/Registry.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ RegistryMaps::RegistryMaps() {
144144
REGISTER_MATCHER(binaryConditionalOperator);
145145
REGISTER_MATCHER(binaryOperator);
146146
REGISTER_MATCHER(binaryOperation);
147+
REGISTER_MATCHER(bindingDecl);
147148
REGISTER_MATCHER(blockDecl);
148149
REGISTER_MATCHER(blockExpr);
149150
REGISTER_MATCHER(blockPointerType);
@@ -226,6 +227,7 @@ RegistryMaps::RegistryMaps() {
226227
REGISTER_MATCHER(exprWithCleanups);
227228
REGISTER_MATCHER(fieldDecl);
228229
REGISTER_MATCHER(floatLiteral);
230+
REGISTER_MATCHER(forDecomposition);
229231
REGISTER_MATCHER(forEach);
230232
REGISTER_MATCHER(forEachArgumentWithParam);
231233
REGISTER_MATCHER(forEachArgumentWithParamType);
@@ -248,6 +250,7 @@ RegistryMaps::RegistryMaps() {
248250
REGISTER_MATCHER(hasAncestor);
249251
REGISTER_MATCHER(hasAnyArgument);
250252
REGISTER_MATCHER(hasAnyBase);
253+
REGISTER_MATCHER(hasAnyBinding);
251254
REGISTER_MATCHER(hasAnyClause);
252255
REGISTER_MATCHER(hasAnyConstructorInitializer);
253256
REGISTER_MATCHER(hasAnyDeclaration);
@@ -266,6 +269,7 @@ RegistryMaps::RegistryMaps() {
266269
REGISTER_MATCHER(hasAttr);
267270
REGISTER_MATCHER(hasAutomaticStorageDuration);
268271
REGISTER_MATCHER(hasBase);
272+
REGISTER_MATCHER(hasBinding);
269273
REGISTER_MATCHER(hasBitWidth);
270274
REGISTER_MATCHER(hasBody);
271275
REGISTER_MATCHER(hasCanonicalType);

clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,37 @@ TEST(ASTMatchersTestObjC, ObjCExceptionStmts) {
21292129
EXPECT_TRUE(matchesObjC(ObjCString, objcFinallyStmt()));
21302130
}
21312131

2132+
TEST(ASTMatchersTest, DecompositionDecl) {
2133+
StringRef Code = R"cpp(
2134+
void foo()
2135+
{
2136+
int arr[3];
2137+
auto &[f, s, t] = arr;
2138+
2139+
f = 42;
2140+
}
2141+
)cpp";
2142+
EXPECT_TRUE(matchesConditionally(
2143+
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("f")))), true,
2144+
{"-std=c++17"}));
2145+
EXPECT_FALSE(matchesConditionally(
2146+
Code, decompositionDecl(hasBinding(42, bindingDecl(hasName("f")))), true,
2147+
{"-std=c++17"}));
2148+
EXPECT_FALSE(matchesConditionally(
2149+
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("s")))), true,
2150+
{"-std=c++17"}));
2151+
EXPECT_TRUE(matchesConditionally(
2152+
Code, decompositionDecl(hasBinding(1, bindingDecl(hasName("s")))), true,
2153+
{"-std=c++17"}));
2154+
2155+
EXPECT_TRUE(matchesConditionally(
2156+
Code,
2157+
bindingDecl(decl().bind("self"), hasName("f"),
2158+
forDecomposition(decompositionDecl(
2159+
hasAnyBinding(bindingDecl(equalsBoundNode("self")))))),
2160+
true, {"-std=c++17"}));
2161+
}
2162+
21322163
TEST(ASTMatchersTestObjC, ObjCAutoreleasePoolStmt) {
21332164
StringRef ObjCString = "void f() {"
21342165
"@autoreleasepool {"

0 commit comments

Comments
 (0)