internal/lsp: support renaming import specs
Support the renaming of the imported name of a package within a file.
This case needs to be special cased because the ident may be added or
removed.
Change-Id: I333bc2b2ca5ce81c4a2afb8b10035f525dfad464
Reviewed-on: https://go-review.googlesource.com/c/tools/+/184199
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index 59b6171..41668a8 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -5,9 +5,11 @@
package source
import (
+ "bytes"
"context"
"fmt"
"go/ast"
+ "go/format"
"go/token"
"go/types"
"regexp"
@@ -49,11 +51,6 @@
return nil, fmt.Errorf("failed to rename because %q is declared in package %q", i.Name, i.decl.obj.Pkg().Name())
}
- // TODO(suzmue): Support renaming of imported packages.
- if _, ok := i.decl.obj.(*types.PkgName); ok {
- return nil, fmt.Errorf("renaming imported package %s not supported", i.Name)
- }
-
refs, err := i.References(ctx)
if err != nil {
return nil, err
@@ -96,6 +93,18 @@
return nil, err
}
+ // Renaming a types.PkgName may result in the addition or removal of an identifier,
+ // so we deal with this separately.
+ if pkgName, ok := ref.obj.(*types.PkgName); ok && ref.isDeclaration {
+ edit, err := r.updatePkgName(pkgName)
+ if err != nil {
+ return nil, err
+ }
+ result[refSpan.URI()] = append(result[refSpan.URI()], *edit)
+ continue
+ }
+
+ // Replace the identifier with r.to.
edit := TextEdit{
Span: refSpan,
NewText: r.to,
@@ -103,16 +112,16 @@
result[refSpan.URI()] = append(result[refSpan.URI()], edit)
- if !ref.isDeclaration || ref.ident == nil { // done if it it is a use or does not have an identifier
+ if !ref.isDeclaration || ref.ident == nil { // uses do not have doc comments to update.
continue
}
doc := r.docComment(r.pkg, ref.ident)
- if doc == nil { // no doc comment
+ if doc == nil {
continue
}
- // Perform the rename in doc comments declared in the original package
+ // Perform the rename in doc comments declared in the original package.
for _, comment := range doc.List {
for _, locs := range docRegexp.FindAllStringIndex(comment.Text, -1) {
rng := span.NewRange(r.fset, comment.Pos()+token.Pos(locs[0]), comment.Pos()+token.Pos(locs[1]))
@@ -120,7 +129,7 @@
if err != nil {
return nil, err
}
- result[refSpan.URI()] = append(result[refSpan.URI()], TextEdit{
+ result[spn.URI()] = append(result[spn.URI()], TextEdit{
Span: spn,
NewText: r.to,
})
@@ -159,3 +168,46 @@
}
return nil
}
+
+// updatePkgName returns the updates to rename a pkgName in the import spec
+func (r *renamer) updatePkgName(pkgName *types.PkgName) (*TextEdit, error) {
+ // Modify ImportSpec syntax to add or remove the Name as needed.
+ pkg := r.packages[pkgName.Pkg()]
+ _, path, _ := pathEnclosingInterval(r.ctx, r.fset, pkg, pkgName.Pos(), pkgName.Pos())
+
+ if len(path) < 2 {
+ return nil, fmt.Errorf("failed to update PkgName for %s", pkgName.Name())
+ }
+ spec, ok := path[1].(*ast.ImportSpec)
+ if !ok {
+ return nil, fmt.Errorf("failed to update PkgName for %s", pkgName.Name())
+ }
+
+ var astIdent *ast.Ident // will be nil if ident is removed
+ if pkgName.Imported().Name() != r.to {
+ // ImportSpec.Name needed
+ astIdent = &ast.Ident{NamePos: spec.Path.Pos(), Name: r.to}
+ }
+
+ // Make a copy of the ident that just has the name and path.
+ updated := &ast.ImportSpec{
+ Name: astIdent,
+ Path: spec.Path,
+ EndPos: spec.EndPos,
+ }
+
+ rng := span.NewRange(r.fset, spec.Pos(), spec.End())
+ spn, err := rng.Span()
+ if err != nil {
+ return nil, err
+ }
+
+ var buf bytes.Buffer
+ format.Node(&buf, r.fset, updated)
+ newText := buf.String()
+
+ return &TextEdit{
+ Span: spn,
+ NewText: newText,
+ }, nil
+}
diff --git a/internal/lsp/testdata/rename/a/random.go.golden b/internal/lsp/testdata/rename/a/random.go.golden
index bd07e97..427b7d2 100644
--- a/internal/lsp/testdata/rename/a/random.go.golden
+++ b/internal/lsp/testdata/rename/a/random.go.golden
@@ -1,7 +1,11 @@
-- GetSum-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -30,18 +34,22 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y) //@rename("y", "y1")
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- myX-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -70,18 +78,22 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y) //@rename("y", "y1")
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- pos-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -110,18 +122,22 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y) //@rename("y", "y1")
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- z-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -150,18 +166,22 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y) //@rename("y", "y1")
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- y0-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -190,18 +210,22 @@
switch y0 := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y0) //@rename("y", "y1")
+ fmt.Printf("%d", y0) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y0) //@rename("y", "y2")
+ lg.Printf("%s", y0) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y0) //@rename("y", "y3")
+ f2.Printf("%v", y0) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- y1-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -230,18 +254,22 @@
switch y1 := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y1) //@rename("y", "y1")
+ fmt.Printf("%d", y1) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y1) //@rename("y", "y2")
+ lg.Printf("%s", y1) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y1) //@rename("y", "y3")
+ f2.Printf("%v", y1) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- y2-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -270,18 +298,22 @@
switch y2 := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y2) //@rename("y", "y1")
+ fmt.Printf("%d", y2) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y2) //@rename("y", "y2")
+ lg.Printf("%s", y2) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y2) //@rename("y", "y3")
+ f2.Printf("%v", y2) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- y3-rename --
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -310,18 +342,22 @@
switch y3 := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y3) //@rename("y", "y1")
+ fmt.Printf("%d", y3) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y3) //@rename("y", "y2")
+ lg.Printf("%s", y3) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y3) //@rename("y", "y3")
+ f2.Printf("%v", y3) //@rename("y", "y3"),rename("f2","fmt2")
}
}
-- format-rename --
package a
-import format "fmt"
+import (
+ lg "log"
+ format "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -350,11 +386,99 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- format.Printf("%d", y) //@rename("y", "y1")
+ format.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- format.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- format.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- log-rename --
+package a
+
+import (
+ "log"
+ "fmt"
+ f2 "fmt"
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ log.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
+ }
+}
+
+-- fmt2-rename --
+package a
+
+import (
+ lg "log"
+ "fmt"
+ fmt2 "fmt"
+)
+
+func Random() int {
+ y := 6 + 7
+ return y
+}
+
+func Random2(y int) int { //@rename("y", "z")
+ return y
+}
+
+type Pos struct {
+ x, y int
+}
+
+func (p *Pos) Sum() int {
+ return p.x + p.y //@rename("x", "myX")
+}
+
+func _() {
+ var p Pos //@rename("p", "pos")
+ _ = p.Sum() //@rename("Sum", "GetSum")
+}
+
+func sw() {
+ var x interface{}
+
+ switch y := x.(type) { //@rename("y", "y0")
+ case int:
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
+ case string:
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
+ default:
+ fmt2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
diff --git a/internal/lsp/testdata/rename/a/random.go.in b/internal/lsp/testdata/rename/a/random.go.in
index c1c0fc5..c2cf020 100644
--- a/internal/lsp/testdata/rename/a/random.go.in
+++ b/internal/lsp/testdata/rename/a/random.go.in
@@ -1,6 +1,10 @@
package a
-import "fmt"
+import (
+ lg "log"
+ "fmt"
+ f2 "fmt"
+)
func Random() int {
y := 6 + 7
@@ -29,10 +33,10 @@
switch y := x.(type) { //@rename("y", "y0")
case int:
- fmt.Printf("%d", y) //@rename("y", "y1")
+ fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format")
case string:
- fmt.Printf("%s", y) //@rename("y", "y2")
+ lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log")
default:
- fmt.Printf("%v", y) //@rename("y", "y3")
+ f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2")
}
}
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 6d659a5..86bd922 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -34,7 +34,7 @@
ExpectedTypeDefinitionsCount = 2
ExpectedHighlightsCount = 2
ExpectedReferencesCount = 4
- ExpectedRenamesCount = 8
+ ExpectedRenamesCount = 11
ExpectedSymbolsCount = 1
ExpectedSignaturesCount = 20
ExpectedLinksCount = 2