如何让Clang AST匹配器支持匹配typedef类型的operator()调用?
Clang AST匹配器适配typedef类实例的operator()调用问题解决
问题背景
现有Clang AST匹配器可正常匹配MyBase或其派生类实例的operator()调用,但无法适配typedef定义的基类/派生类实例的operator()调用。尝试使用hasUnqualifiedDesugaredType、hasCanonicalType时触发类型初始化错误,原因是isSameOrDerivedFrom返回Matcher<CXXRecordDecl>,无法直接适配QualType类型的匹配器。
原有可工作的匹配器(非typedef场景)
示例代码:
class MyBase { void operator()(...) {} }; MyBase b; b(parameters); // 可被原有匹配器匹配
匹配器代码:
const auto MyBaseExpr = expr(hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase")))); Finder->addMatcher(traverse( TK_AsIs, cxxOperatorCallExpr( hasOverloadedOperatorName("()"), hasArgument(0, anyOf(MyBaseExpr, MyOtherBaseExpr)), hasAnyArgument(...) ), this);
typedef场景的匹配失败案例
示例代码:
typedef MyBase MyTypedef; MyTypedef t; t(parameters); // 原有匹配器无法识别
报错信息:
.../RedundantStringCStrCheck.cpp:193:40: error: invalid initialization of reference of type ‘const clang::ast_matchers::internal::Matcher<clang::QualType>&’ from expression of type ‘clang::ast_matchers::internal::BindableMatcher<Decl>’ 193 | expr(hasCanonicalType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
解决方法
核心是通过recordType将QualType匹配器与RecordDecl匹配器桥接:hasCanonicalType需要接收QualType类型的匹配器,先用recordType提取类型对应的RecordDecl,再对其应用cxxRecordDecl(isSameOrDerivedFrom(...))。
修改后的匹配器代码:
const auto MyBaseExpr = expr( hasCanonicalType( recordType( cxxRecordDecl(isSameOrDerivedFrom("::MyBase")) ) ) ); // 如需兼容非typedef+typedef场景,可合并原有逻辑: // const auto MyBaseExpr = expr( // anyOf( // hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))), // hasCanonicalType(recordType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase")))) // ) // ); Finder->addMatcher(traverse( TK_AsIs, cxxOperatorCallExpr( hasOverloadedOperatorName("()"), hasArgument(0, anyOf(MyBaseExpr, MyOtherBaseExpr)), hasAnyArgument(...) ), this);
原理说明
hasCanonicalType:获取类型的规范形式,自动解析typedef、别名等语法糖,得到背后的真实类型。recordType:作为QualType到RecordDecl的桥梁,将QualType匹配器转换为可接收RecordDecl匹配器的上下文,让cxxRecordDecl(isSameOrDerivedFrom(...))能正确作用在真实类型的RecordDecl上。
内容的提问来源于stack exchange,提问作者Mike Crowe
相关产品推荐
相关产品推荐

