зеркало из https://github.com/golang/tools.git
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding, and other imports before that. Currently, DeleteImport assumes there's a blank line-sized hole left behind where the import was, and always deletes it. That blank line-sized hole is there in all cases except the above edge case. This fix checks for that edge case, and does not remove the blank line-sized hole. The CL also adds a previously failing test case that catches this scenario. After the change to DeleteImport, the new test passes (along with all other tests). Fixes golang/go#7679. Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly matching to what you would get if you printed the AST and parsed it back. This is how the rest of the package and the current tests work (i.e., they only check that printing the AST gives the correct output). Changing that is very hard, if not impossible, at least not without resorting to manipulating AST via printing, text manipulation and parsing. This is okay for most usages, but it does create potential problems. For example, astutil.Imports() currently only works correctly on freshly parsed AST. If that AST is manipulated via astutil funcs, then Imports() may not always generate correct output. However, thas is a separate issue and should be treated as such. LGTM=bradfitz R=golang-codereviews, gobot, adonovan, bradfitz CC=golang-codereviews https://golang.org/cl/92250045
This commit is contained in:
Родитель
4374c8910f
Коммит
c0060eca2c
|
@ -160,11 +160,22 @@ func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool)
|
||||||
gen.Lparen = token.NoPos // drop parens
|
gen.Lparen = token.NoPos // drop parens
|
||||||
}
|
}
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
// We deleted an entry but now there will be
|
lastImpspec := gen.Specs[j-1].(*ast.ImportSpec)
|
||||||
|
lastLine := fset.Position(lastImpspec.Path.ValuePos).Line
|
||||||
|
line := fset.Position(impspec.Path.ValuePos).Line
|
||||||
|
|
||||||
|
// We deleted an entry but now there may be
|
||||||
// a blank line-sized hole where the import was.
|
// a blank line-sized hole where the import was.
|
||||||
// Close the hole by making the previous
|
if line-lastLine > 1 {
|
||||||
// import appear to "end" where this one did.
|
// There was a blank line immediately preceeing the deleted import,
|
||||||
gen.Specs[j-1].(*ast.ImportSpec).EndPos = impspec.End()
|
// so there's no need to close the hole.
|
||||||
|
// Do nothing.
|
||||||
|
} else {
|
||||||
|
// There was no blank line.
|
||||||
|
// Close the hole by making the previous
|
||||||
|
// import appear to "end" where this one did.
|
||||||
|
lastImpspec.EndPos = impspec.End()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -408,6 +408,61 @@ import (
|
||||||
pkg: "os",
|
pkg: "os",
|
||||||
in: "package main\n\nimport `os`",
|
in: "package main\n\nimport `os`",
|
||||||
out: `package main
|
out: `package main
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "import.13",
|
||||||
|
pkg: "io",
|
||||||
|
in: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"utf8"
|
||||||
|
|
||||||
|
"go/format"
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
out: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"utf8"
|
||||||
|
|
||||||
|
"go/format"
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "import.14",
|
||||||
|
pkg: "io",
|
||||||
|
in: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt" // a
|
||||||
|
|
||||||
|
"io" // b
|
||||||
|
"os" // c
|
||||||
|
"utf8" // d
|
||||||
|
|
||||||
|
"go/format" // e
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
out: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt" // a
|
||||||
|
|
||||||
|
// b
|
||||||
|
"os" // c
|
||||||
|
"utf8" // d
|
||||||
|
|
||||||
|
"go/format" // e
|
||||||
|
)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -540,6 +540,41 @@ func main() { fmt.Println("Hello, world") }
|
||||||
|
|
||||||
func notmain() { fmt.Println("Hello, world") }`,
|
func notmain() { fmt.Println("Hello, world") }`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Remove first import within in a 2nd/3rd/4th/etc. section.
|
||||||
|
// golang.org/issue/7679
|
||||||
|
{
|
||||||
|
name: "issue 7679",
|
||||||
|
in: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/foo/bar"
|
||||||
|
"github.com/foo/qux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var _ = fmt.Println
|
||||||
|
//var _ = bar.A
|
||||||
|
var _ = qux.B
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
out: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/foo/qux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var _ = fmt.Println
|
||||||
|
//var _ = bar.A
|
||||||
|
var _ = qux.B
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFixImports(t *testing.T) {
|
func TestFixImports(t *testing.T) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче