如何复用Clang AST匹配器 自定义匹配器抽离公共匹配逻辑
自定义libclang AST Matcher实现公共逻辑复用
你可以直接通过AST_MATCHER_P宏封装公共匹配前缀,不需要每次重复写functionDecl(hasName("foo"), hasDescendant(...))结构,具体实现如下:
匹配器定义
根据使用习惯分两种场景实现,按需选择即可:
场景1:保持原有匹配逻辑(匹配结果为foo函数本身)
该写法和你原有代码逻辑完全一致:匹配名为foo的函数,且函数体内存在符合传入规则的后代节点。
#include <clang/ASTMatchers/ASTMatchers.h> using namespace clang::ast_matchers; AST_MATCHER_P( clang::FunctionDecl, inFoo, clang::ast_matchers::internal::Matcher<clang::Stmt>, InnerMatcher ) { // 校验当前节点是名为foo的函数 if (!Node.getIdentifier() || Node.getName() != "foo") { return false; } // 校验函数体存在匹配InnerMatcher规则的后代节点 return matchesFirstInPointerRange( Node.getBody()->child_begin(), Node.getBody()->child_end(), InnerMatcher, Finder, Builder ); }
使用示例:
// 等价于 functionDecl(hasName("foo"), hasDescendant(cxxConstructorExpr())) auto fooHasCtor = functionDecl(inFoo(cxxConstructorExpr()));
场景2:直接匹配foo函数内的目标节点(匹配结果为目标节点本身)
该写法完全符合你给出的inFoo(cxxConstructorExpr())调用形式,匹配结果直接是foo函数体内符合规则的节点,不需要再从foo函数节点下遍历找子节点。
#include <clang/ASTMatchers/ASTMatchers.h> using namespace clang::ast_matchers; AST_MATCHER_P( clang::Stmt, inFoo, clang::ast_matchers::internal::Matcher<clang::Stmt>, InnerMatcher ) { // 校验当前节点在名为foo的函数体内,且本身符合传入的匹配规则 return InnerMatcher.matches(Node, Finder, Builder) && hasAncestor(functionDecl(hasName("foo"))).matches(Node, Finder, Builder); }
使用示例:
// 直接匹配foo函数内的所有构造表达式,匹配结果可直接bind拿到节点 auto ctor = inFoo(cxxConstructorExpr()).bind("foo_ctor");
宏参数说明
AST_MATCHER_P用于定义带参数的自定义匹配器,四个核心传参含义:
- 第一个参数:自定义匹配器要绑定的根AST节点类型,比如匹配函数声明填
clang::FunctionDecl,匹配通用语句填clang::Stmt - 第二个参数:自定义匹配器的名称,示例中为
inFoo - 第三个参数:传入的子匹配器对应的类型,比如传入匹配语句的子匹配器就填
clang::ast_matchers::internal::Matcher<clang::Stmt> - 第四个参数:子匹配器在实现函数内的变量名,示例中为
InnerMatcher
实现函数内可直接访问三个上下文变量:
Node:当前遍历到的、待匹配的AST节点实例Finder、Builder:匹配器上下文对象,调用子匹配器的matches方法时直接透传即可
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

