AST matcher on a specific node

邮差的信 提交于 2020-03-04 05:03:22

问题


I wrote a AST matcher for finding specific type statements. In the matched nodes I calculated the neighbor siblings of that node. Now I need to run matcher on the neighbor nodes to verify they satisfies my condition or not. The clang AST matcher matches the whole tree node one by one. I want to run matcher against a particular node and return true if the node matches my required condition. Is this possible?


回答1:


I suggest to implement your own matcher that will encapsulate the logic of finding neighbor nodes and matching them against other matchers.

I've put together the following matcher as an example of how that can be done:

using clang::ast_matchers::internal::Matcher;
constexpr auto AVERAGE_NUMBER_OF_NESTED_MATCHERS = 3;
using Matchers =
    llvm::SmallVector<Matcher<clang::Stmt>, AVERAGE_NUMBER_OF_NESTED_MATCHERS>;


clang::Stmt *getNeighbor(const clang::Stmt &Node, clang::ASTContext &Context) {
  // It is my naive implementation of this method, you can easily put your own
  auto Parents = Context.getParents(Node);
  if (Parents.size() != 1) {
    return nullptr;
  }

  // As we deal with statements, let's assume that neighbor - is the next
  // statement in the enclosing compound statement.
  if (auto *Parent = Parents[0].get<clang::CompoundStmt>()) {
    auto Neighbor = std::adjacent_find(
        Parent->body_begin(), Parent->body_end(),
        [&Node](const auto *Top, const auto *Bottom) { return Top == &Node; });

    if (Neighbor != Parent->body_end()) {
      return *std::next(Neighbor);
    }
  }

  return nullptr;
}

AST_MATCHER_P(clang::Stmt, neighbors, Matchers, NestedMatchers) {
  // Node is the current tested node
  const clang::Stmt *CurrentNode = &Node;

  // Our goal is to iterate over the given matchers and match the current node
  // with the first matcher.
  //
  // Further on, we plan on checking whether the next
  // matcher matches the neighbor/sibling of the previous node.
  for (auto NestedMatcher : NestedMatchers) {
    // This is how one can call a matcher to test one node.
    //
    // NOTE: it uses Finder and Builder, so it's better to do it from
    //       inside of a matcher and get those for free
    if (CurrentNode == nullptr or
        not NestedMatcher.matches(*CurrentNode, Finder, Builder)) {
      return false;
    }

    // Here you can put your own implementation of finding neighbor/sibling
    CurrentNode = getNeighbor(*CurrentNode, Finder->getASTContext());
  }

  return true;
}

I hope that the comments within the snippet cover the main ideas behind this matcher.

Demo

Matcher:

neighbors({declStmt().bind("first"), forStmt().bind("second"),
           returnStmt().bind("third")})

Code snippet:

int foo() {
  int x = 42;
  int y = 10;
  for (; x > y; --x) {
  }
  return x;
}

Output:

first:
DeclStmt 0x4c683e0
`-VarDecl 0x4c68360  used y 'int' cinit
  `-IntegerLiteral 0x4c683c0 'int' 10

second:
ForStmt 0x4c684d0
|-<<<NULL>>>
|-<<<NULL>>>
|-BinaryOperator 0x4c68468 '_Bool' '>'
| |-ImplicitCastExpr 0x4c68438 'int' <LValueToRValue>
| | `-DeclRefExpr 0x4c683f8 'int' lvalue Var 0x4c682b0 'x' 'int'
| `-ImplicitCastExpr 0x4c68450 'int' <LValueToRValue>
|   `-DeclRefExpr 0x4c68418 'int' lvalue Var 0x4c68360 'y' 'int'
|-UnaryOperator 0x4c684a8 'int' lvalue prefix '--'
| `-DeclRefExpr 0x4c68488 'int' lvalue Var 0x4c682b0 'x' 'int'
`-CompoundStmt 0x4c684c0

third:
ReturnStmt 0x4c68540
`-ImplicitCastExpr 0x4c68528 'int' <LValueToRValue>
  `-DeclRefExpr 0x4c68508 'int' lvalue Var 0x4c682b0 'x' 'int'

I hope that answers your question!



来源:https://stackoverflow.com/questions/60439281/ast-matcher-on-a-specific-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!