clang - 特定节点上的 AST 匹配器

标签 clang abstract-syntax-tree matcher

我编写了一个 AST 匹配器来查找特定类型语句。在匹配的节点中,我计算了该节点的邻居兄弟节点。现在我需要在邻居节点上运行匹配器来验证它们是否满足我的条件。 clang AST 匹配器将整个树节点一一匹配。我想针对特定节点运行匹配器,如果该节点符合我所需的条件,则返回 true。 这可能吗?

最佳答案

我建议实现您自己的匹配器,它将封装查找邻居节点并将它们与其他匹配器进行匹配的逻辑。

我整理了以下匹配器作为如何完成此操作的示例:

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;
}

我希望代码片段中的评论涵盖了这个匹配器背后的主要思想。

演示

匹配器:

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

代码片段:

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

输出:

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'

希望这能回答您的问题!

关于clang - 特定节点上的 AST 匹配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60439281/

相关文章:

Clang:不要优化特定功能

java - 从 IBinding 获取 CompilationUnit

java - 正则表达式替换java中查询参数中的值

Java 模式 REGEX 不匹配的地方

ios - 无法通过 pragma 禁用 LLVM 优化

visual-studio - Visual Studio 错误的界面(想要更换编译器)

abstract-syntax-tree - 从 .Net 程序集获取 AST,无需源代码(IL 代码)

java - 使用模式组查找第一个单词

c++ - 如何使用 Clang Libtooling 在终端上打印一行?

ruby - 从 Ruby block 中提取 AST