Permalink
Browse files

gofmt, gofix: sort imports

Add ast.SortImports(fset, file) to go/ast, for use by both programs.

Fixes #346.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5330069
  • Loading branch information...
rsc committed Nov 2, 2011
1 parent 7db617b commit 4a9ebb18f1ff90cbc182648e65cc9071c8920e3c
View
@@ -569,9 +569,9 @@ func renameTop(f *ast.File, old, new string) bool {
}
// addImport adds the import path to the file f, if absent.
func addImport(f *ast.File, ipath string) {
func addImport(f *ast.File, ipath string) (added bool) {
if imports(f, ipath) {
return
return false
}
// Determine name of import.
@@ -637,10 +637,11 @@ func addImport(f *ast.File, ipath string) {
impdecl.Specs[insertAt] = newImport
f.Imports = append(f.Imports, newImport)
return true
}
// deleteImport deletes the import path from the file f, if present.
func deleteImport(f *ast.File, path string) {
func deleteImport(f *ast.File, path string) (deleted bool) {
oldImport := importSpec(f, path)
// Find the import node that imports path, if any.
@@ -657,6 +658,7 @@ func deleteImport(f *ast.File, path string) {
// We found an import spec that imports path.
// Delete it.
deleted = true
copy(gen.Specs[j:], gen.Specs[j+1:])
gen.Specs = gen.Specs[:len(gen.Specs)-1]
@@ -687,6 +689,19 @@ func deleteImport(f *ast.File, path string) {
break
}
}
return
}
// rewriteImport rewrites any import of path oldPath to path newPath.
func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) {
for _, imp := range f.Imports {
if importPath(imp) == oldPath {
rewrote = true
imp.Path.Value = strconv.Quote(newPath)
}
}
return
}
func usesImport(f *ast.File, path string) (used bool) {
@@ -244,6 +244,26 @@ import (
"io"
"os"
)
`,
},
{
Name: "import.13",
Fn: rewriteImportFn("utf8", "encoding/utf8"),
In: `package main
import (
"io"
"os"
"utf8" // thanks ken
)
`,
Out: `package main
import (
"encoding/utf8" // thanks ken
"io"
"os"
)
`,
},
}
@@ -267,3 +287,13 @@ func deleteImportFn(path string) func(*ast.File) bool {
return false
}
}
func rewriteImportFn(old, new string) func(*ast.File) bool {
return func(f *ast.File) bool {
if imports(f, old) {
rewriteImport(f, old, new)
return true
}
return false
}
}
View
@@ -9,6 +9,7 @@ import (
"exec"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/scanner"
@@ -102,11 +103,21 @@ var printConfig = &printer.Config{
tabWidth,
}
func gofmtFile(f *ast.File) ([]byte, error) {
var buf bytes.Buffer
ast.SortImports(fset, f)
_, err := printConfig.Fprint(&buf, fset, f)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func processFile(filename string, useStdin bool) error {
var f *os.File
var err error
var fixlog bytes.Buffer
var buf bytes.Buffer
if useStdin {
f = os.Stdin
@@ -142,12 +153,10 @@ func processFile(filename string, useStdin bool) error {
// AST changed.
// Print and parse, to update any missing scoping
// or position information for subsequent fixers.
buf.Reset()
_, err = printConfig.Fprint(&buf, fset, newFile)
newSrc, err := gofmtFile(newFile)
if err != nil {
return err
}
newSrc := buf.Bytes()
newFile, err = parser.ParseFile(fset, filename, newSrc, parserMode)
if err != nil {
return err
@@ -165,12 +174,10 @@ func processFile(filename string, useStdin bool) error {
// output of the printer run on a standard AST generated by the parser,
// but the source we generated inside the loop above is the
// output of the printer run on a mangled AST generated by a fixer.
buf.Reset()
_, err = printConfig.Fprint(&buf, fset, newFile)
newSrc, err := gofmtFile(newFile)
if err != nil {
return err
}
newSrc := buf.Bytes()
if *doDiff {
data, err := diff(src, newSrc)
View
@@ -5,10 +5,8 @@
package main
import (
"bytes"
"go/ast"
"go/parser"
"go/printer"
"strings"
"testing"
)
@@ -43,14 +41,12 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out
return
}
var buf bytes.Buffer
buf.Reset()
_, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
outb, err := gofmtFile(file)
if err != nil {
t.Errorf("%s: printing: %v", desc, err)
return
}
if s := buf.String(); in != s && fn != fnop {
if s := string(outb); in != s && fn != fnop {
t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
desc, desc, in, desc, s)
tdiff(t, in, s)
@@ -67,14 +63,13 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out
fixed = fn(file)
}
buf.Reset()
_, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
outb, err = gofmtFile(file)
if err != nil {
t.Errorf("%s: printing: %v", desc, err)
return
}
return buf.String(), fixed, true
return string(outb), fixed, true
}
func TestRewrite(t *testing.T) {
@@ -22,8 +22,8 @@ package netchan
// BUG: can't use range clause to receive when using ImportNValues to limit the count.
import (
"log"
"io"
"log"
"net"
"os"
"reflect"
@@ -22,8 +22,8 @@ package netchan
// BUG: can't use range clause to receive when using ImportNValues to limit the count.
import (
"log"
"io"
"log"
"net"
"os"
"reflect"
View
@@ -114,6 +114,8 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
}
}
ast.SortImports(fset, file)
if *simplifyAST {
simplify(file)
}
@@ -78,6 +78,7 @@ var tests = []struct {
{"testdata/rewrite2.input", "-r=int->bool"},
{"testdata/stdin*.input", "-stdin"},
{"testdata/comments.input", ""},
{"testdata/import.input", ""},
}
func TestRewrite(t *testing.T) {
@@ -0,0 +1,108 @@
package main
import (
"errors"
"fmt"
"io"
"log"
"math"
)
import (
"fmt"
"math"
"log"
"errors"
"io"
)
import (
"errors"
"fmt"
"io"
"log"
"math"
"fmt"
"math"
"log"
"errors"
"io"
)
import (
// a block with comments
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
)
import (
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
// for Printf
"fmt"
"math"
// for Fatal
"log"
"errors"
// for Reader
"io"
)
import (
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
"fmt" // for Printf
"errors"
"io" // for Reader
"log" // for Fatal
"math"
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
)
Oops, something went wrong.

0 comments on commit 4a9ebb1

Please sign in to comment.