[cfe-dev] Writing an AST matcher that matches any callable expression

Zachary Turner via cfe-dev cfe-dev at lists.llvm.org
Tue Nov 5 14:32:57 PST 2019


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 &&)'
<FunctionToPointerDecay>
    |           | `-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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20191105/9de0fc34/attachment.html>


More information about the cfe-dev mailing list