Skip to content

Commit

Permalink
replace_all
Browse files Browse the repository at this point in the history
  • Loading branch information
xzbdmw committed Nov 15, 2024
1 parent b1c39aa commit 81352ac
Show file tree
Hide file tree
Showing 15 changed files with 890 additions and 66 deletions.
Binary file added gopls/doc/assets/extract-expressions-after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gopls/doc/assets/extract-expressions-before.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified gopls/doc/assets/extract-var-after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed gopls/doc/assets/extract-var-before.png
Binary file not shown.
12 changes: 10 additions & 2 deletions gopls/doc/features/transformation.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Gopls supports the following code actions:
- [`refactor.extract.method`](#extract)
- [`refactor.extract.toNewFile`](#extract.toNewFile)
- [`refactor.extract.variable`](#extract)
- [`refactor.extract.variable.all`](#extract)
- [`refactor.inline.call`](#refactor.inline.call)
- [`refactor.rewrite.changeQuote`](#refactor.rewrite.changeQuote)
- [`refactor.rewrite.fillStruct`](#refactor.rewrite.fillStruct)
Expand Down Expand Up @@ -313,11 +314,18 @@ newly created declaration that contains the selected code:
will be a method of the same receiver type.

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

![Before extracting a var](../assets/extract-var-before.png)
![Before extracting a var](../assets/extract-expressions-before.png)
![After extracting a var](../assets/extract-var-after.png)

- **`refactor.extract.variable.all`** replaces all occurrences of the selected expression
within the function with a reference to a new local variable named `newVar`.
This extracts the expression once and reuses it wherever it appears in the function.

![Before extracting all expressions](../assets/extract-expressions-before.png)
![After extracting all expressions](../assets/extract-expressions-after.png)

If the default name for the new declaration is already in use, gopls
generates a fresh name.

Expand Down
5 changes: 5 additions & 0 deletions gopls/doc/release/v0.17.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,8 @@ from the context of the call.
The new `yield` analyzer detects mistakes using the `yield` function
in a Go 1.23 iterator, such as failure to check its boolean result and
break out of a loop.

## Extract all occurrences of the same expression under selection
When you have multiple instances of the same expression in a function,
you can use this code action to extract it into a variable.
All occurrences of the expression will be replaced with a reference to the new variable.
24 changes: 23 additions & 1 deletion gopls/internal/golang/codeaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"golang.org/x/tools/gopls/internal/protocol"
"golang.org/x/tools/gopls/internal/protocol/command"
"golang.org/x/tools/gopls/internal/settings"
"golang.org/x/tools/gopls/internal/util/safetoken"
"golang.org/x/tools/gopls/internal/util/typesutil"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/imports"
Expand Down Expand Up @@ -236,6 +237,7 @@ var codeActionProducers = [...]codeActionProducer{
{kind: settings.RefactorExtractFunction, fn: refactorExtractFunction},
{kind: settings.RefactorExtractMethod, fn: refactorExtractMethod},
{kind: settings.RefactorExtractToNewFile, fn: refactorExtractToNewFile},
{kind: settings.RefactorExtractAllOccursOfExpr, fn: refactorExtractAllOccursOfExpr},
{kind: settings.RefactorExtractVariable, fn: refactorExtractVariable},
{kind: settings.RefactorInlineCall, fn: refactorInlineCall, needPkg: true},
{kind: settings.RefactorRewriteChangeQuote, fn: refactorRewriteChangeQuote},
Expand Down Expand Up @@ -452,12 +454,32 @@ func refactorExtractMethod(ctx context.Context, req *codeActionsRequest) error {
// refactorExtractVariable produces "Extract variable" code actions.
// See [extractVariable] for command implementation.
func refactorExtractVariable(ctx context.Context, req *codeActionsRequest) error {
if _, _, ok, _ := canExtractVariable(req.start, req.end, req.pgf.File); ok {
if _, ok, _ := canExtractVariable(req.start, req.end, req.pgf.File, false); ok {
req.addApplyFixAction("Extract variable", fixExtractVariable, req.loc)
}
return nil
}

// refactorExtractAllOccursOfExpr produces "Extract n occurrences of expression" code action.
// See [extractAllOccursOfExpr] for command implementation.
func refactorExtractAllOccursOfExpr(ctx context.Context, req *codeActionsRequest) error {
// Don't suggest if only one expr is found,
// otherwise it will duplicate with [refactorExtractVariable]
if exprs, ok, _ := canExtractVariable(req.start, req.end, req.pgf.File, true); ok && len(exprs) > 1 {
startOffset, err := safetoken.Offset(req.pgf.Tok, exprs[0].Pos())
if err != nil {
return nil
}
endOffset, err := safetoken.Offset(req.pgf.Tok, exprs[0].End())
if err != nil {
return nil
}
expr := req.pgf.Src[startOffset:endOffset]
req.addApplyFixAction(fmt.Sprintf("Extract %d occurrences of %s", len(exprs), expr), fixExtractAllOccursOfExpr, req.loc)
}
return nil
}

// refactorExtractToNewFile produces "Extract declarations to new file" code actions.
// See [server.commandHandler.ExtractToNewFile] for command implementation.
func refactorExtractToNewFile(ctx context.Context, req *codeActionsRequest) error {
Expand Down
Loading

0 comments on commit 81352ac

Please sign in to comment.