Skip to content

Commit c3feb70

Browse files
committed
gopls/internal/golang: add skeleton for move type codeaction
This is the first CL for implementing move type refactoring, which will allow users to move a type declaration to a different package. The code action producer for move type is off. Change-Id: I10bface65ab6e1cb94180433360c923e8fa78c59 Reviewed-on: https://go-review.googlesource.com/c/tools/+/724020 Reviewed-by: Robert Findley <rfindley@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 869ced3 commit c3feb70

File tree

7 files changed

+99
-0
lines changed

7 files changed

+99
-0
lines changed

gopls/internal/golang/codeaction.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ var codeActionProducers = [...]codeActionProducer{
255255
{kind: settings.RefactorExtractVariableAll, fn: refactorExtractVariableAll, needPkg: true},
256256
{kind: settings.RefactorInlineCall, fn: refactorInlineCall, needPkg: true},
257257
{kind: settings.RefactorInlineVariable, fn: refactorInlineVariable, needPkg: true},
258+
// {kind: settings.RefactorMoveType, fn: refactorMoveType, needPkg: true},
258259
{kind: settings.RefactorRewriteChangeQuote, fn: refactorRewriteChangeQuote},
259260
{kind: settings.RefactorRewriteFillStruct, fn: refactorRewriteFillStruct, needPkg: true},
260261
{kind: settings.RefactorRewriteFillSwitch, fn: refactorRewriteFillSwitch, needPkg: true},
@@ -1132,3 +1133,12 @@ func toggleCompilerOptDetails(ctx context.Context, req *codeActionsRequest) erro
11321133
}
11331134
return nil
11341135
}
1136+
1137+
func refactorMoveType(ctx context.Context, req *codeActionsRequest) error {
1138+
curSel, _ := req.pgf.Cursor.FindByPos(req.start, req.end)
1139+
if _, _, _, typeName, ok := selectionContainsType(curSel); ok {
1140+
cmd := command.NewMoveTypeCommand(fmt.Sprintf("Move type %s", typeName), command.MoveTypeArgs{Location: req.loc})
1141+
req.addCommandAction(cmd, false)
1142+
}
1143+
return nil
1144+
}

gopls/internal/golang/movetype.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package golang
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"go/ast"
11+
"go/token"
12+
13+
"golang.org/x/tools/go/ast/inspector"
14+
"golang.org/x/tools/gopls/internal/cache"
15+
"golang.org/x/tools/gopls/internal/file"
16+
"golang.org/x/tools/gopls/internal/protocol"
17+
"golang.org/x/tools/internal/moreiters"
18+
)
19+
20+
// MoveType moves the selected type declaration into a new package and updates all references.
21+
func MoveType(ctx context.Context, fh file.Handle, snapshot *cache.Snapshot, loc protocol.Location, newPkgDir string) ([]protocol.DocumentChange, error) {
22+
return nil, fmt.Errorf("MoveType: not yet supported")
23+
}
24+
25+
// selectionContainsType returns the Cursor, GenDecl and TypeSpec of the type
26+
// declaration that encloses cursor if one exists. Otherwise it returns false.
27+
func selectionContainsType(cursor inspector.Cursor) (inspector.Cursor, *ast.GenDecl, *ast.TypeSpec, string, bool) {
28+
declCur, ok := moreiters.First(cursor.Enclosing((*ast.GenDecl)(nil)))
29+
if !ok {
30+
return inspector.Cursor{}, &ast.GenDecl{}, &ast.TypeSpec{}, "", false
31+
}
32+
33+
// Verify that we have a type declaration (e.g. not an import declaration).
34+
declNode := declCur.Node().(*ast.GenDecl)
35+
if declNode.Tok != token.TYPE {
36+
return inspector.Cursor{}, &ast.GenDecl{}, &ast.TypeSpec{}, "", false
37+
}
38+
39+
typSpec, ok := declNode.Specs[0].(*ast.TypeSpec)
40+
if !ok {
41+
return inspector.Cursor{}, &ast.GenDecl{}, &ast.TypeSpec{}, "", false
42+
}
43+
44+
return declCur, declNode, declNode.Specs[0].(*ast.TypeSpec), typSpec.Name.Name, true
45+
}

gopls/internal/protocol/command/command_gen.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gopls/internal/protocol/command/interface.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ type Interface interface {
322322

323323
// ModifyTags: Add or remove struct tags on a given node.
324324
ModifyTags(context.Context, ModifyTagsArgs) error
325+
326+
// MoveType: Move a type declaration to a different package.
327+
MoveType(context.Context, MoveTypeArgs) error
325328
}
326329

327330
type RunTestsArgs struct {
@@ -876,3 +879,11 @@ type LSPArgs struct {
876879
Method string `json:"method"`
877880
Param json.RawMessage `json:"param"`
878881
}
882+
883+
// MoveTypeArgs specifies a "move type" refactoring to perform.
884+
type MoveTypeArgs struct {
885+
// The location of the type to move.
886+
Location protocol.Location
887+
// TODO(mkalil): Determine format of the parameter that specifies where to
888+
// move the type to.
889+
}

gopls/internal/server/command.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,3 +1892,16 @@ func parseTransform(input string) (modifytags.Transform, error) {
18921892
return modifytags.SnakeCase, fmt.Errorf("invalid Transform value")
18931893
}
18941894
}
1895+
1896+
func (c *commandHandler) MoveType(ctx context.Context, args command.MoveTypeArgs) error {
1897+
err := c.run(ctx, commandConfig{
1898+
forURI: args.Location.URI,
1899+
}, func(ctx context.Context, deps commandDeps) error {
1900+
changes, err := golang.MoveType(ctx, deps.fh, deps.snapshot, args.Location, "newpkg/new.go")
1901+
if err != nil {
1902+
return err
1903+
}
1904+
return applyChanges(ctx, c.s.client, changes)
1905+
})
1906+
return err
1907+
}

gopls/internal/settings/codeactionkind.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ const (
114114
RefactorExtractVariableAll protocol.CodeActionKind = "refactor.extract.variable-all"
115115
RefactorExtractToNewFile protocol.CodeActionKind = "refactor.extract.toNewFile"
116116

117+
// refactor.move
118+
RefactorMoveType protocol.CodeActionKind = "refactor.move.moveType"
119+
117120
// Note: add new kinds to:
118121
// - the SupportedCodeActions map in default.go
119122
// - the codeActionProducers table in ../golang/codeaction.go

gopls/internal/settings/default.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func DefaultOptions(overrides ...func(*Options)) *Options {
7171
RefactorExtractVariable: true,
7272
RefactorExtractVariableAll: true,
7373
RefactorExtractToNewFile: true,
74+
RefactorMoveType: true, // off while implementation unfinished
7475
// Not GoTest: it must be explicit in CodeActionParams.Context.Only
7576
},
7677
file.Mod: {

0 commit comments

Comments
 (0)