如何使用Clang Transformer重构C++函数返回类型及调用语法?
使用Clang Transformer完成指定C++代码重构
1. 匹配目标函数声明
首先精准定位Foo::bar()的函数声明,它的返回类型是const std::vector<std::unique_ptr<T>>&。用Clang AST Matchers构造匹配规则如下:
// 匹配 const std::vector<std::unique_ptr<...>>& 类型 auto vector_unique_ptr_ref = qualType( referenceType(), pointee( constQualified(), classTemplateSpecializationDecl( hasName("std::vector"), hasTemplateArgument( 0, templateArgument( refersToType( classTemplateSpecializationDecl(hasName("std::unique_ptr")) ) ) ) ) ) ); // 匹配 Foo::bar() 函数声明 auto target_func = functionDecl( hasName("bar"), ofClass(hasName("Foo")), returns(vector_unique_ptr_ref) );
2. 替换函数返回类型
用Transformer规则将返回类型替换为const std::vector<T>&,核心是提取原std::unique_ptr<T>中的T,构造新的返回类型:
auto rewrite_decl = makeRule( target_func, changeReturnTemplateType( [](const MatchResult& Result) -> std::string { // 获取原vector模板实例 const auto* vec_spec = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("vec_spec"); // 获取unique_ptr模板实例 const auto* uptr_spec = vec_spec->getTemplateArgs()[0] .getAsType()->getAs<ClassTemplateSpecializationDecl>(); // 提取T类型的字符串表示 const auto* t_type = uptr_spec->getTemplateArgs()[0].getAsType(); return "const std::vector<" + t_type->getAsString() + ">&"; } ) );
3. 匹配并替换遍历/访问中的成员调用
需要覆盖三种常见调用场景,完成箭头转点、移除解引用的操作:
场景1:遍历循环中的箭头调用
匹配遍历Foo::bar()返回值的循环里,std::unique_ptr的箭头成员调用:
// 匹配调用 Foo::bar() 的表达式 auto bar_call = callExpr(callee(target_func)); // 匹配遍历 bar() 返回值的for循环 auto loop_over_bar = forRangeStmt(hasRangeInit(bar_call)); // 匹配循环体内的 ptr->method() 调用 auto arrow_call_in_loop = memberExpr( isArrow(), base( declRefExpr( to(varDecl(hasType(classTemplateSpecializationDecl(hasName("std::unique_ptr"))))), hasAncestor(loop_over_bar) ) ) ); // 替换为 ptr.method() auto rewrite_loop_arrow = makeRule( arrow_call_in_loop, replaceWith("{0}.{1}", node("base"), node("member")) );
场景2:解引用后的成员调用
匹配(*ptr).method()这种写法,替换为ptr.method():
// 匹配循环体内的 (*ptr).method() 调用 auto deref_call_in_loop = memberExpr( base( unaryOperator( hasOperatorName("*"), hasUnaryOperand( declRefExpr( to(varDecl(hasType(classTemplateSpecializationDecl(hasName("std::unique_ptr"))))), hasAncestor(loop_over_bar) ) ) ) ) ); // 替换为 ptr.method() auto rewrite_loop_deref = makeRule( deref_call_in_loop, replaceWith("{0}.{1}", node("unaryOperand"), node("member")) );
场景3:直接下标访问后的箭头调用
匹配foo.bar()[0]->method()这种直接访问的情况,替换为foo.bar()[0].method():
// 匹配 bar()[idx]->method() 调用 auto direct_arrow_call = memberExpr( isArrow(), base( subscriptExpr(base(bar_call)) ) ); // 替换为 bar()[idx].method() auto rewrite_direct_arrow = makeRule( direct_arrow_call, replaceWith("{0}.{1}", node("base"), node("member")) );
4. 整合规则并执行
把所有规则添加到Transformer,用Clang Tool运行:
int main(int argc, const char** argv) { clang::tooling::ClangTool Tool(argc, argv); Transformer T; T.addRule(rewrite_decl); T.addRule(rewrite_loop_arrow); T.addRule(rewrite_loop_deref); T.addRule(rewrite_direct_arrow); return Tool.run(clang::tooling::newFrontendActionFactory(T.createASTConsumer()).get()); }
内容的提问来源于stack exchange,提问作者Semin Park
相关产品推荐
相关产品推荐

