是否可以使用 RecursiveASTVisitor 仅遍历 AST 的子树

Is it possible to traverse only a subtree of the AST with RecursiveASTVisitor

提问人:Mike van Dyke 提问时间:11/13/2023 更新时间:11/14/2023 访问量:44

问:

我想用 clang 的 .当我指定应该遍历整个 AST 时(如下所示),这需要花费大量时间:RecursiveASTVisitor

void MyVisitor::HandleTranslationUnit(clang::ASTContext& context)
{
  TraverseDecl(context.getTranslationUnitDecl());
}

出于这个原因,我想使用 AST 匹配器将 AST 缩小到我想要遍历的代码的相关部分。假设我只想遍历某些函数声明,那么我有如下内容:

void MyVisitor::HandleTranslationUnit(clang::ASTContext& context)
{
    auto decl = context.getTranslationUnitDecl();
    auto relevantNodes = match(findAll(functionDecl(/* any matcher */).bind("function")), *decl, context);
    for(auto &relevantNode : relevantNodes)
    {
      const clang::FunctionDecl *relevantFunctionDecl = relevantNode.getNodeAs<clang::FunctionDecl>("function");
      if(relevantFunctionDecl)
      {
        TraverseDecl(relevantFunctionDecl);
        //----------^ cannot pass const clang::FunctionDecl* to function accepting clang::Decl*
      }
    }
}

在我的代码中,该方法返回一个 const 指针,但接受非常量指针,即编译失败。getNodeAs<>TraverseDecl

有没有办法只遍历 AST 的某些部分?

提前致谢!

c++ clang 抽象语法树 clang-ast-matchers

评论


答:

1赞 Scott McPeak 11/14/2023 #1

是的,可以访问子树。只需按照代码片段中所示的操作即可,但添加以允许将从匹配器获取的指针传递给 。C++ 未定义行为没有问题,因为所有 AST 对象最初都是在没有限定符的情况下创建的。const_castRecursiveASTVisitorconst

一般来说,Clang API 在恒定性方面有点不一致。许多 API(如匹配器)处理指针,因为它们本身不会修改 AST。但是,虽然 也是如此,但使用修改 AST 的转换器编写转换器有些常见,因此其 API 不使用 .constRecursiveASTVisitorconst

请参阅 Clang Discourse 讨论 使用 Clang 静态分析是否安全? 对于类似的问题和 Clang 开发人员的评论。

(顺便说一句,我认为这部分源于这样一个事实,即 C++ 没有“常量多态性”的概念,如果它存在,它可能允许 API 选择性地统一处理或非指针。由于语言强制做出选择,因此 API 设计人员必须选择更适合常见用法的,因此客户端必须在某些边界处插入。constconstconst_cast