For context, I’m writing a clang-tidy tool which should match the following (simplified criterias)
uint32_t x = foo();
uint32_t y = 42;
bar(x);
bar(y);
bar(x)
should only be matched, because x is assigned from a function call. I understand I can do this with a two-step match, first looking for VarDecl
s that get assigned from a CallExpr
, but I’m looking for something a little more idiomatic. However, my real-world use case makes it so that bar may take x as an argument, meaning this needs to get wrapped in optionally(...)
(Which means I can’t use allOf(precondition, condition)
. So I set out to create a custom matcher which sort of looks like this:
/// Matches nodes that match another query.
///
/// Given
/// \code
/// uint32_t y = 0;
/// uint32_t x = foo();
/// bar(x);
/// bar(y);
/// \endcode
/// callExpr(hasArgument(0, declRefExpr(matchesMatcher(binaryOperator(hasOperands(declRefExpr(equalsBoundNode("declRef")), callExpr())), "declRef"))))
/// matches 'bar(x);' but not 'bar(y);'.
AST_MATCHER_P2(clang::Stmt, matchesMatcher,
clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, InnerMatcher,
llvm::StringRef, BoundName)
{
using namespace clang::ast_matchers;
auto matchedNodesSet = match(
allOf(
expr(equalsNode(&Node)).bind(BoundName),
InnerMatcher
), Finder->getASTContext());
auto itr = std::find_if(matchedNodesSet.begin(), matchedNodesSet.end(),
[&](BoundNodes const& matchedNodes) {
return matchedNodes.getNodeAs<clang::Stmt>(BoundName) != nullptr;
}
);
return itr != matchedNodesSet.end();
}
However, a couple questions:
- Is there a more idiomatic way to do this, that is already provided out of the box by AST matchers?
- Is this even a correct implementation?