From c4a336ef6a2feb97e86b0c7ebdd500717074f42b Mon Sep 17 00:00:00 2001 From: Suzy Mueller Date: Wed, 21 Aug 2019 22:40:36 -0400 Subject: [PATCH] internal/lsp: support renaming of import spec This change allows renamings of the name of an import spec. Since there is not always explicit identifier available to select and rename, allow renaming packages from positions within the import spec. Change-Id: I0a8aaa92c26e1795ddb9c31a1165b2f2ee89aa34 Reviewed-on: https://go-review.googlesource.com/c/tools/+/191165 Run-TryBot: Suzy Mueller TryBot-Result: Gobot Gobot Reviewed-by: Ian Cottrell --- internal/lsp/source/rename.go | 61 ++++++- .../lsp/testdata/rename/a/random.go.golden | 157 ++++++++++++++++-- internal/lsp/testdata/rename/a/random.go.in | 2 +- internal/lsp/tests/tests.go | 2 +- 4 files changed, 203 insertions(+), 19 deletions(-) diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go index 5ac65fbd6e..00f26f585e 100644 --- a/internal/lsp/source/rename.go +++ b/internal/lsp/source/rename.go @@ -40,14 +40,19 @@ func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.U ctx, done := trace.StartSpan(ctx, "source.Rename") defer done() + // If the object declaration is nil, assume it is an import spec. + if i.decl.obj == nil { + // Find the corresponding package name for this import spec + // and rename that instead. + ident, err := i.getPkgName(ctx) + if err != nil { + return nil, err + } + return ident.Rename(ctx, newName) + } if i.Name == newName { return nil, errors.Errorf("old and new names are the same: %s", newName) } - // If the object declaration is nil, assume it is an import spec and return an error. - // TODO(suzmue): support renaming of identifiers in an import spec. - if i.decl.obj == nil { - return nil, errors.Errorf("renaming import %q not supported", i.Name) - } if !isValidIdentifier(i.Name) { return nil, errors.Errorf("invalid identifier to rename: %q", i.Name) } @@ -104,6 +109,52 @@ func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.U return changes, nil } +// getPkgName gets the pkg name associated with an identifer representing +// the import path in an import spec. +func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) { + file := i.File.FileSet().File(i.Range.Start) + pkgLine := file.Line(i.Range.Start) + + for _, obj := range i.pkg.GetTypesInfo().Defs { + pkgName, ok := obj.(*types.PkgName) + if ok && file.Line(pkgName.Pos()) == pkgLine { + return getPkgNameIdentifier(ctx, i, pkgName) + } + } + for _, obj := range i.pkg.GetTypesInfo().Implicits { + pkgName, ok := obj.(*types.PkgName) + if ok && file.Line(pkgName.Pos()) == pkgLine { + return getPkgNameIdentifier(ctx, i, pkgName) + } + } + return nil, errors.Errorf("no package name for %q", i.Name) +} + +// getPkgNameIdentifier returns an IdentifierInfo representing pkgName. +// pkgName must be in the same package and file as ident. +func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *types.PkgName) (*IdentifierInfo, error) { + decl := declaration{ + obj: pkgName, + wasImplicit: true, + } + var err error + if decl.rng, err = objToRange(ctx, ident.File.FileSet(), decl.obj); err != nil { + return nil, err + } + if decl.node, err = objToNode(ctx, ident.File.View(), ident.pkg.GetTypes(), decl.obj, decl.rng); err != nil { + return nil, err + } + return &IdentifierInfo{ + Name: pkgName.Name(), + Range: decl.rng, + File: ident.File, + decl: decl, + pkg: ident.pkg, + wasEmbeddedField: false, + qf: ident.qf, + }, nil +} + // Rename all references to the identifier. func (r *renamer) update() (map[span.URI][]diff.TextEdit, error) { result := make(map[span.URI][]diff.TextEdit) diff --git a/internal/lsp/testdata/rename/a/random.go.golden b/internal/lsp/testdata/rename/a/random.go.golden index 518757f14f..b1a20ff850 100644 --- a/internal/lsp/testdata/rename/a/random.go.golden +++ b/internal/lsp/testdata/rename/a/random.go.golden @@ -5,7 +5,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -43,6 +43,96 @@ func sw() { } } +-- f2name-rename -- +random.go: +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2name "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +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: + f2name.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- f2y-rename -- +random.go: +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2y "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +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: + f2y.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + -- fmt2-rename -- random.go: package a @@ -50,7 +140,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - fmt2 "fmt" + fmt2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -89,7 +179,50 @@ func sw() { } -- fmty-rename -- -renaming import "fmt" not supported +random.go: +package a + +import ( + lg "log" + fmty "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +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: + fmty.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + -- format-rename -- random.go: package a @@ -97,7 +230,7 @@ package a import ( lg "log" format "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -142,7 +275,7 @@ package a import ( "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -187,7 +320,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -232,7 +365,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -277,7 +410,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -322,7 +455,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -367,7 +500,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -412,7 +545,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { @@ -457,7 +590,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { diff --git a/internal/lsp/testdata/rename/a/random.go.in b/internal/lsp/testdata/rename/a/random.go.in index 12026d0503..069db27baa 100644 --- a/internal/lsp/testdata/rename/a/random.go.in +++ b/internal/lsp/testdata/rename/a/random.go.in @@ -3,7 +3,7 @@ package a import ( lg "log" "fmt" //@rename("fmt", "fmty") - f2 "fmt" + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") ) func Random() int { diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index a79c1e3726..c0a5b31fae 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -38,7 +38,7 @@ const ( ExpectedTypeDefinitionsCount = 2 ExpectedHighlightsCount = 2 ExpectedReferencesCount = 5 - ExpectedRenamesCount = 18 + ExpectedRenamesCount = 20 ExpectedSymbolsCount = 1 ExpectedSignaturesCount = 21 ExpectedLinksCount = 4