Writing an AST matcher that matches any callable expression

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Writing an AST matcher that matches any callable expression

Tom Stellard via cfe-dev
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.

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev