From bd3f524777d3d52754343e6fee7528e4d5b2295a Mon Sep 17 00:00:00 2001 From: Dylan Le Date: Fri, 29 Jul 2022 16:50:30 -0400 Subject: [PATCH] internal/lsp: rename all the package names in the renamed package This CL contains a partial implementation of package renaming. Currently gopls is only able to rename references to the renaming package within the renaming package itself. prepareRename is still expected to return an error for renaming a package. For golang/go#41567 Change-Id: I3683a0a7128bba7620ef30db528f45b753e6c08f Reviewed-on: https://go-review.googlesource.com/c/tools/+/420219 Reviewed-by: Robert Findley TryBot-Result: Gopher Robot Run-TryBot: Dylan Le --- gopls/internal/regtest/misc/rename_test.go | 36 ++++++++++++++++++++++ internal/lsp/source/rename.go | 36 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/gopls/internal/regtest/misc/rename_test.go b/gopls/internal/regtest/misc/rename_test.go index 65a9ecb52e..1d980d90aa 100644 --- a/gopls/internal/regtest/misc/rename_test.go +++ b/gopls/internal/regtest/misc/rename_test.go @@ -10,6 +10,7 @@ import ( "golang.org/x/tools/internal/lsp/protocol" . "golang.org/x/tools/internal/lsp/regtest" + "golang.org/x/tools/internal/testenv" ) func TestPrepareRenamePackage(t *testing.T) { @@ -51,6 +52,41 @@ func main() { }) } +func TestRenamePackageInRenamedPackage(t *testing.T) { + // Failed at Go 1.13; not investigated + testenv.NeedsGo1Point(t, 14) + const files = ` +-- go.mod -- +module mod.com + +go 1.18 +-- main.go -- +package main + +import ( + "fmt" + "a.go" +) + +func main() { + fmt.Println(a.C) +} +-- a.go -- +package main + +const C = 1 +` + Run(t, files, func(t *testing.T, env *Env) { + env.OpenFile("main.go") + pos := env.RegexpSearch("main.go", "main") + env.Rename("main.go", pos, "pkg") + + // Check if the new package name exists. + env.RegexpSearch("main.go", "package pkg") + env.RegexpSearch("a.go", "package pkg") + }) +} + // Test for golang/go#47564. func TestRenameInTestVariant(t *testing.T) { const files = ` diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go index b6f0e6531e..6bbe91afae 100644 --- a/internal/lsp/source/rename.go +++ b/internal/lsp/source/rename.go @@ -118,6 +118,41 @@ func Rename(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position, ctx, done := event.Start(ctx, "source.Rename") defer done() + pgf, err := s.ParseGo(ctx, f, ParseFull) + if err != nil { + return nil, err + } + inPackageName, err := isInPackageName(ctx, s, f, pgf, pp) + if err != nil { + return nil, err + } + + if inPackageName { + renamingPkg, err := s.PackageForFile(ctx, f.URI(), TypecheckAll, NarrowestPackage) + if err != nil { + return nil, err + } + + result := make(map[span.URI][]protocol.TextEdit) + // Rename internal references to the package in the renaming package + // Todo(dle): need more investigation on case when pkg.GoFiles != pkg.CompiledGoFiles if using cgo. + for _, f := range renamingPkg.CompiledGoFiles() { + pkgNameMappedRange := NewMappedRange(f.Tok, f.Mapper, f.File.Name.Pos(), f.File.Name.End()) + rng, err := pkgNameMappedRange.Range() + if err != nil { + return nil, err + } + result[f.URI] = []protocol.TextEdit{ + { + Range: rng, + NewText: newName, + }, + } + } + + return result, nil + } + qos, err := qualifiedObjsAtProtocolPos(ctx, s, f.URI(), pp) if err != nil { return nil, err @@ -182,6 +217,7 @@ func Rename(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position, if err != nil { return nil, err } + result := make(map[span.URI][]protocol.TextEdit) for uri, edits := range changes { // These edits should really be associated with FileHandles for maximal correctness.