go/ast, insertion in file.Decls produces invalid code because of comment

20 hours ago 1
ARTICLE AD BOX

I want to create a new struct embedding original struct. But if original struct has comment, it gets placed in the middle of embed struct declaration.

Example code: https://go.dev/play/p/8xqxpmNy2Qj

package main import ( "bytes" "fmt" "go/ast" "go/parser" "go/printer" "go/token" ) func main() { src := `package demo // Original comment type Original struct { Name string }` fset := token.NewFileSet() file, err := parser.ParseFile(fset, "input.go", src, parser.ParseComments) if err != nil { panic(err) } original := "Original" newName := "Embed" // find original struct and insert before it for i, decl := range file.Decls { gen, ok := decl.(*ast.GenDecl) if !ok || gen.Tok != token.TYPE { continue } for _, spec := range gen.Specs { ts, ok := spec.(*ast.TypeSpec) if !ok || ts.Name.Name != original { continue } // create: type ItemWrapper struct { Item } newDecl := &ast.GenDecl{ Tok: token.TYPE, Specs: []ast.Spec{ &ast.TypeSpec{ Name: ast.NewIdent(newName), Type: &ast.StructType{ Fields: &ast.FieldList{ List: []*ast.Field{ { Type: ast.NewIdent(original), }, }, }, }, }, }, } // insert before original file.Decls = append(file.Decls[:i], append([]ast.Decl{newDecl}, file.Decls[i:]...)..., ) goto done } } done: var buf bytes.Buffer if err := printer.Fprint(&buf, fset, file); err != nil { panic(err) } fmt.Println(buf.String()) /* Output: package demo type // Original comment Embed struct { Original } type Original struct { Name string } */ }

What are the best ways to handle this situation and work with comments in general other than using dave/dst library (since judging by this comment it seems Dave may not want to support this library)?

Read Entire Article