c++clangclang-ast-matchers

Clang MatchResult has no AST nodes bound?


I'm writing my first AST Matcher to detect pointer-to-integral conversions but the size of the BoundedNodes in the MatchResult is 0. How is this possible? Why would the AST Matcher call my callback even with an empty MatchResult? Is it possible for a piece of code to match a certain Matcher without appearing as a node in the AST?

This is my whole code:

class PtoICallback : public clang::ast_matchers::MatchFinder::MatchCallback {
    clang::Rewriter rewriter;

public:
    virtual void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override final {
        llvm::outs() << result.Nodes.getMap().size() << " nodes matched\n";
    }
};

int main(int argc, const char** argv) {
    llvm::cl::OptionCategory findPtoICategory("find-ptoi options");

    clang::tooling::CommonOptionsParser options(argc, argv, findPtoICategory);

    clang::tooling::ClangTool tool(options.getCompilations(), options.getSourcePathList());


    auto matcher = clang::ast_matchers::castExpr(clang::ast_matchers::hasCastKind(clang::CastKind::CK_PointerToIntegral));
    PtoICallback callback;
    clang::ast_matchers::MatchFinder finder;
    finder.addMatcher(matcher, &callback);

    return tool.run(clang::tooling::newFrontendActionFactory(&finder).get());
}

This outputs

0 nodes matched

when invoked on a file which contains 1 pointer to integral conversion:

#include <stdint.h>

int main() { 
    int i = 0;
    intptr_t a = reinterpret_cast<intptr_t>(&i);
    return 0; 
}

Again, I don't understand why the match would be detected, but no node would be found? If I dump the AST for the above code it gives:

`-FunctionDecl 0x55765ad54520 <example.cpp:5:1, line:9:1> line:5:5 main 'int ()'
  `-CompoundStmt 0x55765ad62010 <col:12, line:9:1>
    |-DeclStmt 0x55765ad61e40 <line:6:5, col:14>
    | `-VarDecl 0x55765ad54648 <col:5, col:13> col:9 used i 'int' cinit
    |   `-IntegerLiteral 0x55765ad61e20 <col:13> 'int' 0
    |-DeclStmt 0x55765ad61fc8 <line:7:5, col:48>
    | `-VarDecl 0x55765ad61e90 <col:5, col:47> col:14 a 'intptr_t':'long' cinit
    |   `-CXXReinterpretCastExpr 0x55765ad61f98 <col:18, col:47> 'intptr_t':'long' reinterpret_cast<intptr_t> <PointerToIntegral>
    |     `-UnaryOperator 0x55765ad61f48 <col:45, col:46> 'int *' prefix '&' cannot overflow
    |       `-DeclRefExpr 0x55765ad61ef8 <col:46> 'int' lvalue Var 0x55765ad54648 'i' 'int'
    `-ReturnStmt 0x55765ad62000 <line:8:5, col:12>
      `-IntegerLiteral 0x55765ad61fe0 <col:12> 'int' 0

So I would imagine that result.Nodes.getMap() would yield me at least the CXXReinterpretCastExpr shown in the AST dump? Yet it's empty.


Solution

  • Found it. Apparently you have to bind your matcher to some string, otherwise the nodes it matches will not be present in the bound nodes. It makes sense if you say it like that, but I had to search way too long for it.

    For anyone reading this, if you call the bind method at the end of your matcher, you can basically specify a string defined by you that will identify the nodes you find that were matched as a result of that specific matcher. There doesn't seem to be a thing like a wildcard string or anything, which is why it doesn't bind AST nodes to your results if you don't bind the matcher to something.

    I think it is meant to serve as a way to differentiate between matchers if multiple of them were to find results and they use the same callback and somehow the MatchResults contains multiple nodes that are matched at once? It's not really clear to me yet how the matching works. Does it batch multiple 'matchings' together to avoid calling run() too much? I don't know. For me there's always only one entry in the Nodes at a time.