clang-tidy ASTMatch匹配CallExpr时如何获取所属父函数名
问题原因
getParents() 仅返回当前节点的直接父节点。从给出的AST结构可以看到,目标CallExpr的直接父节点是CompoundStmt(语句块节点),并非外层的FunctionDecl。如果调用表达式写在if分支、循环、lambda、switch块等嵌套结构中,CallExpr和FunctionDecl之间还会间隔更多层其他AST节点,直接取第一层父节点强转FunctionDecl必然返回空指针。
解决方法
有两种成熟实现方案,优先推荐匹配器绑定方案,代码更简洁性能更好。
方案1:匹配阶段直接绑定外层函数(推荐)
修改原有匹配规则,通过hasAncestor匹配器直接把CallExpr所属的外层函数绑定到指定ID,回调中直接取值即可,不需要手动遍历父节点链:
// 匹配规则修改为 Finder->addMatcher( callExpr( hasAncestor(functionDecl().bind("enclosing_func")) ).bind("call"), this );
回调函数中直接获取绑定的函数节点:
const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("call"); const auto *EnclosingFunc = Result.Nodes.getNodeAs<FunctionDecl>("enclosing_func"); if (EnclosingFunc == nullptr) { // 处理CallExpr位于全局初始化、静态变量初始化等不属于任何函数的场景 return; } std::string FunctionName = EnclosingFunc->getNameInfo().getAsString();
方案2:手动沿父节点链向上遍历
如果不想修改匹配规则,可以写一个简单的辅助函数,从CallExpr节点开始逐层向上查找,直到找到FunctionDecl节点或者遍历到AST根节点:
const FunctionDecl* getEnclosingFunc(const ast_type_traits::DynTypedNode& StartNode, ASTContext& Ctx) { ast_type_traits::DynTypedNode CurNode = StartNode; while (true) { if (const auto* FD = CurNode.get<FunctionDecl>()) { return FD; } ASTContext::DynTypedNodeList Parents = Ctx.getParents(CurNode); if (Parents.empty()) { // 遍历到根节点仍未找到FunctionDecl,说明当前CallExpr不在函数内部 return nullptr; } // 常规代码场景下节点仅存在一个父节点,模板实例化等特殊场景可能存在多个父节点,可按需扩展处理逻辑 CurNode = Parents[0]; } }
回调中调用该辅助函数即可:
const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("call"); const FunctionDecl* Parent = getEnclosingFunc( ast_type_traits::DynTypedNode::create(*MatchedCallExpr), *Result.Context ); std::string FunctionName {}; if (Parent == nullptr) { return; } FunctionName = Parent->getNameInfo().getAsString();
内容的提问来源于stack exchange,提问作者Langewin
相关产品推荐
相关产品推荐

