go/ast 不支持合并 AST,正确做法是根据意图选择源码拼接、语义层函数注入或中间结构体数据合并,避免直接操作节点导致位置错乱、作用域冲突或 panic。

go/ast 本身不提供「合并 AST」的接口,也没有定义任何合并语义——它只是只读的结构表示。强行拼接两个 *ast.File 或递归复制节点,大概率导致位置信息错乱、作用域冲突、类型系统失效,甚至 ast.Inspect 遍历时 panic。
真正可行的路径不是“合并 AST”,而是根据具体目标选择对应方案。
需要把两段 Go 代码拼成一个文件(如代码生成)
这不是 AST 合并,是源码拼接。直接操作字符串或fmt.Sprintf 更安全:
• 必须保证两段代码都语法合法,且无包名/导入冲突;
• 若含 import 块,需手动去重合并(不能靠 AST 节点追加,ast.GenDecl 的 Specs 不维护导入顺序或别名);
• 拼接后若要再解析,必须用全新 token.FileSet,否则 .Pos() 全乱;
• 示例:把 func A() {} 和 func B() {} 合成一个文件,不如用 strings.Join([]string{src1, src2}, "\n"),再 parser.ParseFile 一次。
立即学习“go语言免费学习笔记(深入)”;
想把两个 AST 中的函数声明合并进同一个作用域(如插桩、AOP)
不能靠节点树合并,得走语义层:• 先用 ast.Inspect 分别提取所有 *ast.FuncDecl;
• 检查函数名是否重复(Go 不允许同包同名函数),冲突时需重命名或跳过;
• 将选中的 FuncDecl 追加到目标 *ast.File 的 f.Decls 切片末尾;
• 注意:不能直接修改原 *ast.File 的 Decls 并复用其 token.FileSet —— 新增节点的 Pos() 必须由 fset.NewTokenFile(...).Base() 生成,否则位置无效,后续 go/format 或 IDE 提示会崩。
想基于 AST 实现配置/规则的逻辑合并(如策略注入)
这本质是「数据合并」,不是「语法树合并」:• 把 AST 解构成中间结构体(例如 type Rule struct { Name string; Expr string }),而非保留 *ast.CallExpr;
• 在中间层做字段级合并(如 map key 冲突时覆盖/保留/报错),再重新构建新 AST;
• 避免在 *ast.BasicLit 或 *ast.Ident 上做指针拷贝——它们共享底层 token.FileSet,跨文件引用会导致 Pos() 返回错误行号;
• 如果原始 AST 来自不同文件,token.Position 的 Filename 字段已固化,无法“合并”成统一路径,只能丢弃或重写。


















