【发布时间】:2019-11-20 13:09:12
【问题描述】:
鉴于此代码,我如何在不破坏 cmets 节点的情况下使用额外的导入规范打印它。
在下面的代码中,我使用包加载器 API 从字符串加载包。我尝试使用生成的 AST 来插入一个新节点,一个导入规范。
不幸的是,当我尝试打印修改后的 AST 时,cmets 被打乱了。
https://play.golang.org/p/N6_y1ehM1Qc
package main
import (
"go/ast"
"go/parser"
"go/printer"
"go/token"
"log"
"os"
"golang.org/x/tools/go/loader"
)
func main() {
var conf loader.Config
conf.ParserMode = parser.ParseComments
f, err := conf.ParseFile("main.go", `// some comment goes here
package main
// some comment here.
// main comment here.
func main(){
}
`)
if err != nil {
log.Fatal(err)
}
conf.CreateFromFiles("main", f)
prog, err := conf.Load()
if err != nil {
log.Println(err)
}
g := &ast.GenDecl{}
g.Tok = token.IMPORT
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: "package/path"},
}
g.Specs = append(g.Specs, spec)
f.Decls = append([]ast.Decl{g}, f.Decls...)
_ = prog
printer.Fprint(os.Stdout, token.NewFileSet(), f)
//printer.Fprint(os.Stdout, prog.Fset, f)
}
这个程序输出
package main // some comment goes here
// some comment here.
// main comment here.
import package/path
func main() {
}
我希望得到这个结果:
// some comment goes here
package main
// some comment here.
import package/path
// main comment here.
func main() {
}
这是有问题的,因为在更复杂的程序中,输出会被破坏:
// some comment goes here
package main
import // some comment here.
package/path
// main comment here.
func main() {
}
【问题讨论】:
-
您可以使用现有的
FileSet以避免所有内容放错位置,然后为导入声明设置所需的token.Pos。 play.golang.org/p/hCLQB3daxOF -
你有什么建议降下树来调整新插入节点之后每个元素的位置吗?我做了更多的测试,在我看来,只使用参考和添加/删除偏移量是有风险的。
-
也许可以尝试使用
golang.org/x/tools/go/ast/astutil并查看它的来源,看看它是如何计算位置的。不能说更多,因为我自己从未使用过。 -
谢谢,我忘记了 astutil。确实应该有帮助。
-
我们遇到了同样的问题。我认为 ast 包文档应该更新一下。 (我们最终选择了完全不同的方式)