[ASTMatchers] Add matchers for decomposition decls

Differential Revision: https://reviews.llvm.org/D95739
This commit is contained in:
Stephen Kelly 2021-01-30 15:50:44 +00:00
parent c722575633
commit 467a045601
4 changed files with 180 additions and 0 deletions

View File

@ -591,6 +591,15 @@ accessSpecDecl()
</pre></td></tr>
<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>
<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};
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="blockDecl0"><pre>Matches block declarations.
@ -6011,6 +6020,24 @@ Example matches b (matcher = binaryOperator(hasRHS()))
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="forDecomposition0"><pre>Matches the DecompositionDecl the binding belongs to.
For example, in:
void foo()
{
int arr[3];
auto &amp;[f, s, t] = arr;
f = 42;
}
The matcher:
bindingDecl(hasName("f"),
forDecomposition(decompositionDecl())
matches 'f' in 'auto &amp;[f, s, t]'.
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="hasAnyParameter2"><pre>Matches any parameter of a function or an ObjC method declaration or a
block.
@ -7090,6 +7117,40 @@ Usable as: Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="hasAnyBinding0"><pre>Matches any binding of a DecompositionDecl.
For example, in:
void foo()
{
int arr[3];
auto &amp;[f, s, t] = arr;
f = 42;
}
The matcher:
decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
matches the decomposition decl with 'f' bound to "fBinding".
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="hasBinding0"><pre>Matches the Nth binding of a DecompositionDecl.
For example, in:
void foo()
{
int arr[3];
auto &amp;[f, s, t] = arr;
f = 42;
}
The matcher:
decompositionDecl(hasBinding(0, bindingDecl(hasName("f").bind("fBinding"))))
matches the decomposition decl with 'f' bound to "fBinding".
</pre></td></tr>
<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>
<tr><td colspan="4" class="doc" id="hasBody0"><pre></pre></td></tr>

View File

@ -347,6 +347,16 @@ extern const internal::VariadicAllOfMatcher<Decl> decl;
extern const internal::VariadicDynCastAllOfMatcher<Decl, DecompositionDecl>
decompositionDecl;
/// Matches binding declarations
/// Example matches \c foo and \c bar
/// (matcher = bindingDecl()
///
/// \code
/// auto [foo, bar] = std::make_pair{42, 42};
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher<Decl, BindingDecl>
bindingDecl;
/// Matches a declaration of a linkage specification.
///
/// Given
@ -7379,6 +7389,80 @@ AST_MATCHER(Expr, nullPointerConstant) {
Expr::NPC_ValueDependentIsNull);
}
/// Matches the DecompositionDecl the binding belongs to.
///
/// For example, in:
/// \code
/// void foo()
/// {
/// int arr[3];
/// auto &[f, s, t] = arr;
///
/// f = 42;
/// }
/// \endcode
/// The matcher:
/// \code
/// bindingDecl(hasName("f"),
/// forDecomposition(decompositionDecl())
/// \endcode
/// matches 'f' in 'auto &[f, s, t]'.
AST_MATCHER_P(BindingDecl, forDecomposition, internal::Matcher<ValueDecl>,
InnerMatcher) {
if (const ValueDecl *VD = Node.getDecomposedDecl())
return InnerMatcher.matches(*VD, Finder, Builder);
return false;
}
/// Matches the Nth binding of a DecompositionDecl.
///
/// For example, in:
/// \code
/// void foo()
/// {
/// int arr[3];
/// auto &[f, s, t] = arr;
///
/// f = 42;
/// }
/// \endcode
/// The matcher:
/// \code
/// decompositionDecl(hasBinding(0,
/// bindingDecl(hasName("f").bind("fBinding"))))
/// \endcode
/// matches the decomposition decl with 'f' bound to "fBinding".
AST_MATCHER_P2(DecompositionDecl, hasBinding, unsigned, N,
internal::Matcher<BindingDecl>, InnerMatcher) {
if (Node.bindings().size() <= N)
return false;
return InnerMatcher.matches(*Node.bindings()[N], Finder, Builder);
}
/// Matches any binding of a DecompositionDecl.
///
/// For example, in:
/// \code
/// void foo()
/// {
/// int arr[3];
/// auto &[f, s, t] = arr;
///
/// f = 42;
/// }
/// \endcode
/// The matcher:
/// \code
/// decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding"))))
/// \endcode
/// matches the decomposition decl with 'f' bound to "fBinding".
AST_MATCHER_P(DecompositionDecl, hasAnyBinding, internal::Matcher<BindingDecl>,
InnerMatcher) {
return llvm::any_of(Node.bindings(), [&](const auto *Binding) {
return InnerMatcher.matches(*Binding, Finder, Builder);
});
}
/// Matches declaration of the function the statement belongs to
///
/// Given:

View File

@ -144,6 +144,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(binaryConditionalOperator);
REGISTER_MATCHER(binaryOperator);
REGISTER_MATCHER(binaryOperation);
REGISTER_MATCHER(bindingDecl);
REGISTER_MATCHER(blockDecl);
REGISTER_MATCHER(blockExpr);
REGISTER_MATCHER(blockPointerType);
@ -226,6 +227,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(exprWithCleanups);
REGISTER_MATCHER(fieldDecl);
REGISTER_MATCHER(floatLiteral);
REGISTER_MATCHER(forDecomposition);
REGISTER_MATCHER(forEach);
REGISTER_MATCHER(forEachArgumentWithParam);
REGISTER_MATCHER(forEachArgumentWithParamType);
@ -248,6 +250,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasAncestor);
REGISTER_MATCHER(hasAnyArgument);
REGISTER_MATCHER(hasAnyBase);
REGISTER_MATCHER(hasAnyBinding);
REGISTER_MATCHER(hasAnyClause);
REGISTER_MATCHER(hasAnyConstructorInitializer);
REGISTER_MATCHER(hasAnyDeclaration);
@ -266,6 +269,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasAttr);
REGISTER_MATCHER(hasAutomaticStorageDuration);
REGISTER_MATCHER(hasBase);
REGISTER_MATCHER(hasBinding);
REGISTER_MATCHER(hasBitWidth);
REGISTER_MATCHER(hasBody);
REGISTER_MATCHER(hasCanonicalType);

View File

@ -2129,6 +2129,37 @@ TEST(ASTMatchersTestObjC, ObjCExceptionStmts) {
EXPECT_TRUE(matchesObjC(ObjCString, objcFinallyStmt()));
}
TEST(ASTMatchersTest, DecompositionDecl) {
StringRef Code = R"cpp(
void foo()
{
int arr[3];
auto &[f, s, t] = arr;
f = 42;
}
)cpp";
EXPECT_TRUE(matchesConditionally(
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("f")))), true,
{"-std=c++17"}));
EXPECT_FALSE(matchesConditionally(
Code, decompositionDecl(hasBinding(42, bindingDecl(hasName("f")))), true,
{"-std=c++17"}));
EXPECT_FALSE(matchesConditionally(
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("s")))), true,
{"-std=c++17"}));
EXPECT_TRUE(matchesConditionally(
Code, decompositionDecl(hasBinding(1, bindingDecl(hasName("s")))), true,
{"-std=c++17"}));
EXPECT_TRUE(matchesConditionally(
Code,
bindingDecl(decl().bind("self"), hasName("f"),
forDecomposition(decompositionDecl(
hasAnyBinding(bindingDecl(equalsBoundNode("self")))))),
true, {"-std=c++17"}));
}
TEST(ASTMatchersTestObjC, ObjCAutoreleasePoolStmt) {
StringRef ObjCString = "void f() {"
"@autoreleasepool {"