go.tools/cmd/cover: preserve comments, as other build tools may need "// +build" directives.

Also: fix a crash when a file already contains 'import "sync/atomic"'.

R=r, gri
CC=golang-dev
https://golang.org/cl/14441052
This commit is contained in:
Alan Donovan 2013-10-10 15:29:24 -04:00
parent 579c61d653
commit f5b337da55
1 changed files with 44 additions and 2 deletions

View File

@ -19,6 +19,7 @@
package main package main
import ( import (
"bytes"
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
@ -26,8 +27,10 @@ import (
"go/printer" "go/printer"
"go/token" "go/token"
"io" "io"
"io/ioutil"
"log" "log"
"os" "os"
"path/filepath"
"sort" "sort"
"strconv" "strconv"
) )
@ -251,7 +254,10 @@ func (f *File) addImport(path string) string {
// Does the package already import it? // Does the package already import it?
for _, s := range f.astFile.Imports { for _, s := range f.astFile.Imports {
if unquote(s.Path.Value) == path { if unquote(s.Path.Value) == path {
return s.Name.Name if s.Name != nil {
return s.Name.Name
}
return filepath.Base(path)
} }
} }
newImport := &ast.ImportSpec{ newImport := &ast.ImportSpec{
@ -297,12 +303,47 @@ func (f *File) addImport(path string) string {
return atomicPackageName return atomicPackageName
} }
var slashslash = []byte("//")
// initialComments returns the prefix of content containing only
// whitepace and line comments. Any +build directives must appear
// within this region. This approach is more reliable than using
// go/printer to print a modified AST containing comments.
//
func initialComments(content []byte) []byte {
// Derived from go/build.Context.shouldBuild.
end := 0
p := content
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
}
line = bytes.TrimSpace(line)
if len(line) == 0 { // Blank line.
end = len(content) - len(p)
continue
}
if !bytes.HasPrefix(line, slashslash) { // Not comment line.
break
}
}
return content[:end]
}
func cover(name string) { func cover(name string) {
fset := token.NewFileSet() fset := token.NewFileSet()
parsedFile, err := parser.ParseFile(fset, name, nil, 0) content, err := ioutil.ReadFile(name)
if err != nil { if err != nil {
log.Fatalf("cover: %s: %s", name, err) log.Fatalf("cover: %s: %s", name, err)
} }
parsedFile, err := parser.ParseFile(fset, name, content, 0)
if err != nil {
log.Fatalf("cover: %s: %s", name, err)
}
file := &File{ file := &File{
fset: fset, fset: fset,
name: name, name: name,
@ -320,6 +361,7 @@ func cover(name string) {
log.Fatalf("cover: %s", err) log.Fatalf("cover: %s", err)
} }
} }
fd.Write(initialComments(content)) // Retain '// +build' directives.
file.print(fd) file.print(fd)
// After printing the source tree, add some declarations for the counters etc. // After printing the source tree, add some declarations for the counters etc.
// We could do this by adding to the tree, but it's easier just to print the text. // We could do this by adding to the tree, but it's easier just to print the text.