You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:02:33