mirror of
https://github.com/golang/go
synced 2024-11-20 02:04:39 -07:00
gofix: test and fix missorted renames
Also introduce a new insertion heuristic: insert new import next to existing import with the longest matching prefix. R=golang-dev, adg, gri CC=golang-dev https://golang.org/cl/5412053
This commit is contained in:
parent
750d0e33fb
commit
2e9d7a6d1c
@ -552,6 +552,15 @@ func renameTop(f *ast.File, old, new string) bool {
|
|||||||
return fixed
|
return fixed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchLen returns the length of the longest prefix shared by x and y.
|
||||||
|
func matchLen(x, y string) int {
|
||||||
|
i := 0
|
||||||
|
for i < len(x) && i < len(y) && x[i] == y[i] {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// addImport adds the import path to the file f, if absent.
|
// addImport adds the import path to the file f, if absent.
|
||||||
func addImport(f *ast.File, ipath string) (added bool) {
|
func addImport(f *ast.File, ipath string) (added bool) {
|
||||||
if imports(f, ipath) {
|
if imports(f, ipath) {
|
||||||
@ -572,54 +581,66 @@ func addImport(f *ast.File, ipath string) (added bool) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var impdecl *ast.GenDecl
|
|
||||||
|
|
||||||
// Find an import decl to add to.
|
// Find an import decl to add to.
|
||||||
var lastImport = -1
|
var (
|
||||||
|
bestMatch = -1
|
||||||
|
lastImport = -1
|
||||||
|
impDecl *ast.GenDecl
|
||||||
|
impIndex = -1
|
||||||
|
)
|
||||||
for i, decl := range f.Decls {
|
for i, decl := range f.Decls {
|
||||||
gen, ok := decl.(*ast.GenDecl)
|
gen, ok := decl.(*ast.GenDecl)
|
||||||
|
|
||||||
if ok && gen.Tok == token.IMPORT {
|
if ok && gen.Tok == token.IMPORT {
|
||||||
lastImport = i
|
lastImport = i
|
||||||
// Do not add to import "C", to avoid disrupting the
|
// Do not add to import "C", to avoid disrupting the
|
||||||
// association with its doc comment, breaking cgo.
|
// association with its doc comment, breaking cgo.
|
||||||
if !declImports(gen, "C") {
|
if declImports(gen, "C") {
|
||||||
impdecl = gen
|
continue
|
||||||
break
|
}
|
||||||
|
|
||||||
|
// Compute longest shared prefix with imports in this block.
|
||||||
|
for j, spec := range gen.Specs {
|
||||||
|
impspec := spec.(*ast.ImportSpec)
|
||||||
|
n := matchLen(importPath(impspec), ipath)
|
||||||
|
if n > bestMatch {
|
||||||
|
bestMatch = n
|
||||||
|
impDecl = gen
|
||||||
|
impIndex = j
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No import decl found. Add one.
|
// If no import decl found, add one after the last import.
|
||||||
if impdecl == nil {
|
if impDecl == nil {
|
||||||
impdecl = &ast.GenDecl{
|
impDecl = &ast.GenDecl{
|
||||||
Tok: token.IMPORT,
|
Tok: token.IMPORT,
|
||||||
}
|
}
|
||||||
f.Decls = append(f.Decls, nil)
|
f.Decls = append(f.Decls, nil)
|
||||||
copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
|
copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
|
||||||
f.Decls[lastImport+1] = impdecl
|
f.Decls[lastImport+1] = impDecl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the import decl has parentheses, if needed.
|
// Ensure the import decl has parentheses, if needed.
|
||||||
if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
|
if len(impDecl.Specs) > 0 && !impDecl.Lparen.IsValid() {
|
||||||
impdecl.Lparen = impdecl.Pos()
|
impDecl.Lparen = impDecl.Pos()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume the import paths are alphabetically ordered.
|
insertAt := impIndex + 1
|
||||||
// If they are not, the result is ugly, but legal.
|
if insertAt == 0 {
|
||||||
insertAt := len(impdecl.Specs) // default to end of specs
|
insertAt = len(impDecl.Specs)
|
||||||
for i, spec := range impdecl.Specs {
|
|
||||||
impspec := spec.(*ast.ImportSpec)
|
|
||||||
if importPath(impspec) > ipath {
|
|
||||||
insertAt = i
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
impDecl.Specs = append(impDecl.Specs, nil)
|
||||||
|
copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
|
||||||
|
impDecl.Specs[insertAt] = newImport
|
||||||
|
if insertAt > 0 {
|
||||||
|
// Assign same position as the previous import,
|
||||||
|
// so that the sorter sees it as being in the same block.
|
||||||
|
prev := impDecl.Specs[insertAt-1]
|
||||||
|
newImport.Path.ValuePos = prev.Pos()
|
||||||
|
newImport.EndPos = prev.Pos()
|
||||||
}
|
}
|
||||||
|
|
||||||
impdecl.Specs = append(impdecl.Specs, nil)
|
|
||||||
copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
|
|
||||||
impdecl.Specs[insertAt] = newImport
|
|
||||||
|
|
||||||
f.Imports = append(f.Imports, newImport)
|
f.Imports = append(f.Imports, newImport)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -682,6 +703,9 @@ func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) {
|
|||||||
for _, imp := range f.Imports {
|
for _, imp := range f.Imports {
|
||||||
if importPath(imp) == oldPath {
|
if importPath(imp) == oldPath {
|
||||||
rewrote = true
|
rewrote = true
|
||||||
|
// record old End, beacuse the default is to compute
|
||||||
|
// it using the length of imp.Path.Value.
|
||||||
|
imp.EndPos = imp.End()
|
||||||
imp.Path.Value = strconv.Quote(newPath)
|
imp.Path.Value = strconv.Quote(newPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,33 @@ import poot "html/template"
|
|||||||
|
|
||||||
var _ = cmplx.Sin
|
var _ = cmplx.Sin
|
||||||
var _ = poot.Poot
|
var _ = poot.Poot
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "go1rename.2",
|
||||||
|
In: `package foo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"http"
|
||||||
|
"url"
|
||||||
|
|
||||||
|
"google/secret/project/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {}
|
||||||
|
`,
|
||||||
|
Out: `package foo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"google/secret/project/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -348,17 +348,54 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
|
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "import.3",
|
||||||
|
Fn: addImportFn("x/y/z", "x/a/c"),
|
||||||
|
In: `package main
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"a"
|
||||||
|
"b"
|
||||||
|
|
||||||
|
"x/w"
|
||||||
|
|
||||||
|
"d/f"
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
Out: `package main
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"a"
|
||||||
|
"b"
|
||||||
|
|
||||||
|
"x/a/c"
|
||||||
|
"x/w"
|
||||||
|
"x/y/z"
|
||||||
|
|
||||||
|
"d/f"
|
||||||
|
)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func addImportFn(path string) func(*ast.File) bool {
|
func addImportFn(path ...string) func(*ast.File) bool {
|
||||||
return func(f *ast.File) bool {
|
return func(f *ast.File) bool {
|
||||||
if !imports(f, path) {
|
fixed := false
|
||||||
addImport(f, path)
|
for _, p := range path {
|
||||||
return true
|
if !imports(f, p) {
|
||||||
|
addImport(f, p)
|
||||||
|
fixed = true
|
||||||
}
|
}
|
||||||
return false
|
}
|
||||||
|
return fixed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user