Writing an AST matcher that matches any callable expression

Currently the modernize-avoid-bind clang-tidy check only supports FunctionDecls. So if you have this:

void foo(int x) {}

struct Foo {
void operator()(int x) {}
};

int main() {
Foo foo;

auto x = std::bind(foo, 3); // Catches this;
auto y = std::bind(Foo{}, 3); // Doesn’t catch this

auto z = std::bind(foo, 3); // Doesn’t catch this

}

I’d like to improve this. Currently the matcher looks like this:

Finder->addMatcher(
callExpr(
callee(namedDecl(hasName("::std::bind"))),
hasArgument(0, declRefExpr(to(functionDecl().bind(“f”))).bind(“ref”)))
.bind(“bind”),
this);

How can I get it to match the other two cases? I managed to get it to match the third case with this:

Finder->addMatcher(
callExpr(
callee(namedDecl(hasName("::std::bind"))),
hasArgument(0,
anyOf(
declRefExpr(to(functionDecl().bind(“f”))).bind(“ref”),
declRefExpr(to(varDecl().bind(“f”)).bind(“ref”)))
.bind(“bind”),
this);

But I can’t get it to match the second case where it’s a temporary object.

The AST looks like this:

-DeclStmt 0x2303a87c288 <line:18:5, col:38>
-VarDecl 0x2303a85b778 <col:5, col:37> col:10 eeeeee 'std::_Binder<std::_Unforced, Bar, int>':'std::_Binder<std::_Unforced, Bar, int>' cinit -ExprWithCleanups 0x2303a87c270 <col:19, col:37> ‘std::_Binder<std::_Unforced, Bar, int>’:‘std::_Binder<std::_Unforced, Bar, int>’
-CXXConstructExpr 0x2303a87c240 <col:19, col:37> 'std::_Binder<std::_Unforced, Bar, int>':'std::_Binder<std::_Unforced, Bar, int>' 'void (std::_Binder<std::_Unforced, Bar, int> &&) noexcept' elidable -MaterializeTemporaryExpr 0x2303a879018 <col:19, col:37> ‘_Binder<std::_Unforced, Bar, int>’:‘std::_Binder<std::_Unforced, Bar, int>’ xvalue
`-CallExpr 0x2303a85c0a0 <col:19, col:37> ‘_Binder<std::_Unforced, Bar, int>’:‘std::_Binder<std::_Unforced, Bar, int>’

-ImplicitCastExpr 0x2303a85c088 <col:19, col:24> ‘_Binder<std::_Unforced, Bar, int> (*)(Bar &&, int &&)’
-DeclRefExpr 0x2303a85bff0 <col:19, col:24> '_Binder<std::_Unforced, Bar, int> (Bar &&, int &&)' lvalue Function 0x2303a85bea8 'bind' '_Binder<std::_Unforced, Bar, int> (Bar &&, int &&)' (FunctionTemplate 0x2303a7462a8 'bind') -MaterializeTemporaryExpr 0x2303a8785d0 <col:29, col:33> 'Bar' xvalue -CXXTemporaryObjectExpr 0x2303a85b860 <col:29, col:33> ‘Bar’ ‘void () noexcept’ zeroing
-MaterializeTemporaryExpr 0x2303a8785e8 <col:36> 'int':'int' xvalue -IntegerLiteral 0x2303a85b970 col:36 ‘int’ 3

But for whatever reason trying to match the first argument against materializeTemporaryExpr() doesn’t seem to work.

I’m also wondering if maybe I don’t need to go through all of this. The first argument to std::bind() is always a callable anyway, so why do I need to match it against anything? Maybe I can just use

Finder->addMatcher(
callExpr(
callee(namedDecl(hasName("::std::bind"))))
.bind(“bind”),

this);

? Suggestions appreciated.