Skip to content

Commit 78461fc

Browse files
committed
replace_all
1 parent 386503d commit 78461fc

16 files changed

+823
-35
lines changed
243 KB
Loading
Loading
237 KB
Loading
-26.8 KB
Binary file not shown.

gopls/doc/features/transformation.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Gopls supports the following code actions:
7272
- [`refactor.extract.method`](#extract)
7373
- [`refactor.extract.toNewFile`](#extract.toNewFile)
7474
- [`refactor.extract.variable`](#extract)
75+
- [`refactor.extract.variable.all`](#extract)
7576
- [`refactor.inline.call`](#refactor.inline.call)
7677
- [`refactor.rewrite.changeQuote`](#refactor.rewrite.changeQuote)
7778
- [`refactor.rewrite.fillStruct`](#refactor.rewrite.fillStruct)
@@ -313,11 +314,18 @@ newly created declaration that contains the selected code:
313314
will be a method of the same receiver type.
314315

315316
- **`refactor.extract.variable`** replaces an expression by a reference to a new
316-
local variable named `x` initialized by the expression:
317+
local variable named `newVar` initialized by the expression:
317318

318-
![Before extracting a var](../assets/extract-var-before.png)
319+
![Before extracting a var](../assets/extract-expressions-before.png)
319320
![After extracting a var](../assets/extract-var-after.png)
320321

322+
- **`refactor.extract.variable.all`** replaces all occurrences of the selected expression
323+
within the function with a reference to a new local variable named `newVar`.
324+
This extracts the expression once and reuses it wherever it appears in the function.
325+
326+
![Before extracting all expressions](../assets/extract-expressions-before.png)
327+
![After extracting all expressions](../assets/extract-expressions-after.png)
328+
321329
If the default name for the new declaration is already in use, gopls
322330
generates a fresh name.
323331

gopls/doc/release/v0.17.0.md

+5
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,8 @@ Gopls now offers a new code action, “Declare missing method of T.f”,
7373
where T is the concrete type and f is the undefined method.
7474
The stub method's signature is inferred
7575
from the context of the call.
76+
77+
## Replace all occurrences of expression within function with newVar
78+
When you have multiple instances of the same expression in a function,
79+
you can use this code action to extract it into a variable.
80+
All occurrences of the expression will be replaced with a reference to the new variable.

gopls/internal/golang/codeaction.go

+22
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"golang.org/x/tools/gopls/internal/protocol"
2828
"golang.org/x/tools/gopls/internal/protocol/command"
2929
"golang.org/x/tools/gopls/internal/settings"
30+
"golang.org/x/tools/gopls/internal/util/safetoken"
3031
"golang.org/x/tools/gopls/internal/util/typesutil"
3132
"golang.org/x/tools/internal/event"
3233
"golang.org/x/tools/internal/imports"
@@ -236,6 +237,7 @@ var codeActionProducers = [...]codeActionProducer{
236237
{kind: settings.RefactorExtractFunction, fn: refactorExtractFunction},
237238
{kind: settings.RefactorExtractMethod, fn: refactorExtractMethod},
238239
{kind: settings.RefactorExtractToNewFile, fn: refactorExtractToNewFile},
240+
{kind: settings.RefactorExtractAllOccursOfExpr, fn: refactorExtractAllOccursOfExpr},
239241
{kind: settings.RefactorExtractVariable, fn: refactorExtractVariable},
240242
{kind: settings.RefactorInlineCall, fn: refactorInlineCall, needPkg: true},
241243
{kind: settings.RefactorRewriteChangeQuote, fn: refactorRewriteChangeQuote},
@@ -458,6 +460,26 @@ func refactorExtractVariable(ctx context.Context, req *codeActionsRequest) error
458460
return nil
459461
}
460462

463+
// refactorExtractAllOccursOfExpr produces "Extract all occcurrances of expression" code action.
464+
// See [extractAllOccursOfExpr] for command implementation.
465+
func refactorExtractAllOccursOfExpr(ctx context.Context, req *codeActionsRequest) error {
466+
// Don't suggest if only one expr is found,
467+
// otherwise will duplicate with [refactorExtractVariable]
468+
if exprs, ok, _ := canExtractExprs(req.start, req.end, req.pgf.File); ok && len(exprs) > 1 {
469+
startOffset, err := safetoken.Offset(req.pgf.Tok, exprs[0].Pos())
470+
if err != nil {
471+
return nil
472+
}
473+
endOffset, err := safetoken.Offset(req.pgf.Tok, exprs[0].End())
474+
if err != nil {
475+
return nil
476+
}
477+
expr := req.pgf.Src[startOffset:endOffset]
478+
req.addApplyFixAction(fmt.Sprintf("Extract %d occcurrances of %s", len(exprs), expr), fixExtractAllOccursOfExpr, req.loc)
479+
}
480+
return nil
481+
}
482+
461483
// refactorExtractToNewFile produces "Extract declarations to new file" code actions.
462484
// See [server.commandHandler.ExtractToNewFile] for command implementation.
463485
func refactorExtractToNewFile(ctx context.Context, req *codeActionsRequest) error {

gopls/internal/golang/extract.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,22 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file
3636
// TODO: stricter rules for selectorExpr.
3737
case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.SliceExpr,
3838
*ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr:
39-
lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", 0)
39+
lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "newVar", 0)
4040
lhsNames = append(lhsNames, lhsName)
4141
case *ast.CallExpr:
4242
tup, ok := info.TypeOf(expr).(*types.Tuple)
4343
if !ok {
4444
// If the call expression only has one return value, we can treat it the
4545
// same as our standard extract variable case.
46-
lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", 0)
46+
lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "newVar", 0)
4747
lhsNames = append(lhsNames, lhsName)
4848
break
4949
}
5050
idx := 0
5151
for i := 0; i < tup.Len(); i++ {
5252
// Generate a unique variable for each return value.
5353
var lhsName string
54-
lhsName, idx = generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", idx)
54+
lhsName, idx = generateAvailableIdentifier(expr.Pos(), path, pkg, info, "newVar", idx)
5555
lhsNames = append(lhsNames, lhsName)
5656
}
5757
default:

0 commit comments

Comments
 (0)