Fragment Description:



Using the go/format/parser/token packages This example illustrates how to remove a variable declaration in a Go program while maintaining correct comment association using an ast.CommentMap.


ASTremoveDeclexample

Go Playground

Last update, on 2015, Fri 9 Oct, 16:15:31

/* ... <== see fragment description ... */

package main

import (
    "bytes"
    "fmt"
    "go/ast"
    "go/format"
    "go/parser"
    "go/token"
    "strings"
)

var source = `/* This is the package comment.
 that is quite long
*/
package main
// This comment is associated with the hello constant.
// ?And This one?
const hello = "Hello, World!" // line comment 1
// This comment is associated with the foo variable.
var foo = hello /* line comment 2 */
// This comment is associated with the main function.
func main() {
   fmt.Println(hello) // line comment 3
}`

func main() {
    ExampleCommentMap()
}

// This example illustrates how to remove a variable declaration
// in a Go program while maintaining correct comment association
// using an ast.CommentMap.
func ExampleCommentMap() {
    // src is the input for which we create the AST that we
    // are going to manipulate.
    // Create the AST by parsing src.
    fset := token.NewFileSet() // positions are relative to fset
    // sign: func ParseFile(fset *token.FileSet, filename string,
    // src interface{}, mode Mode) (f *ast.File, err error)
    f, err := parser.ParseFile(fset, "", source, parser.ParseComments)
    if err != nil {
        panic(err)
    }
    // Create an ast.CommentMap from the ast.File's comments.
    // This helps keeping the association between comments
    // and AST nodes.
    cmap := ast.NewCommentMap(fset, f, f.Comments)
    // Remove the first variable declaration from the list of declarations.
    f.Decls = removeFirstVarDecl(f.Decls)
    // Use the comment map to filter comments that don't belong anymore
    // (the comments associated with the variable declaration), and create
    // the new comments list.
    f.Comments = cmap.Filter(f).Comments()
    // fmt.Printf("Comment[0] with [%v] is: %#v\n========\n",
    // f.Comments[0].Pos(),
    // f.Comments[0].Text())
    setOfLines := strings.Split(f.Comments[0].Text(), "\n")
    for i, line := range setOfLines {
        // delete this line
        setOfLines = append(setOfLines[:i], setOfLines[i+1:]...)
        // replace it by new a line starting with "//"
        // insert line in the set of lines
        setOfLines = append(setOfLines[:i], append([]string{"//" + line}, setOfLines[i:]...)...)
    }
    // for i, line := range setOfLines {
    // fmt.Printf("line[%d] is: %s\n", i, line)
    // }
    f.Comments[0].List[0].Text = strings.Join(setOfLines, "\n")
    // Print the modified AST.
    var buf bytes.Buffer
    if err := format.Node(&buf, fset, f); err != nil {
        panic(err)
    }
    fmt.Printf("%s", buf.Bytes())
}
func removeFirstVarDecl(list []ast.Decl) []ast.Decl {
    for i, decl := range list {
        if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR {
            copy(list[i:], list[i+1:])
            return list[:len(list)-1]
        }
    }
    panic("variable declaration not found")
}

/* Expected Output
// This is the package comment.
// that is quite long
//
package main
// This comment is associated with the hello constant.
// ?And This one?
const hello = "Hello, World!" // line comment 1
// This comment is associated with the main function.
func main() {
   fmt.Println(hello) // line comment 3
}
*/
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.



Comments