Skip to content

Commit cd01e86

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/golang: make singleFileFixer like fixer
In the past the singleFileFixer has two roles: to simplify the signature for fixers of a single file, and to allow them to be expressed only in terms of go/{ast,types} data types, allowing fixers to be more loosely coupled to gopls. But that latter role seems unimportant now, so this CL simplifies the two functions to make them more alike. Change-Id: I42ee9fd275e344fafee0b27b9861f8f599f89e3e Reviewed-on: https://go-review.googlesource.com/c/tools/+/650641 Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 4991e7d commit cd01e86

File tree

6 files changed

+76
-54
lines changed

6 files changed

+76
-54
lines changed

gopls/internal/analysis/fillstruct/fillstruct.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ import (
2525

2626
"golang.org/x/tools/go/analysis"
2727
"golang.org/x/tools/go/ast/astutil"
28+
"golang.org/x/tools/gopls/internal/cache"
29+
"golang.org/x/tools/gopls/internal/cache/parsego"
2830
"golang.org/x/tools/gopls/internal/fuzzy"
2931
"golang.org/x/tools/gopls/internal/util/safetoken"
3032
"golang.org/x/tools/internal/analysisinternal"
31-
"golang.org/x/tools/internal/astutil/cursor"
3233
"golang.org/x/tools/internal/typeparams"
3334
"golang.org/x/tools/internal/typesinternal"
3435
)
@@ -130,15 +131,15 @@ const FixCategory = "fillstruct" // recognized by gopls ApplyFix
130131

131132
// SuggestedFix computes the suggested fix for the kinds of
132133
// diagnostics produced by the Analyzer above.
133-
func SuggestedFix(fset *token.FileSet, start, end token.Pos, content []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
134-
if info == nil {
135-
return nil, nil, fmt.Errorf("nil types.Info")
136-
}
137-
138-
pos := start // don't use the end
139-
134+
func SuggestedFix(cpkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
135+
var (
136+
fset = cpkg.FileSet()
137+
pkg = cpkg.Types()
138+
info = cpkg.TypesInfo()
139+
pos = start // don't use end
140+
)
140141
// TODO(adonovan): simplify, using Cursor.
141-
file := curFile.Node().(*ast.File)
142+
file := pgf.Cursor.Node().(*ast.File)
142143
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
143144
if len(path) == 0 {
144145
return nil, nil, fmt.Errorf("no enclosing ast.Node")
@@ -235,7 +236,7 @@ func SuggestedFix(fset *token.FileSet, start, end token.Pos, content []byte, cur
235236
}
236237

237238
// Find the line on which the composite literal is declared.
238-
split := bytes.Split(content, []byte("\n"))
239+
split := bytes.Split(pgf.Src, []byte("\n"))
239240
lineNumber := safetoken.StartPosition(fset, expr.Lbrace).Line
240241
firstLine := split[lineNumber-1] // lines are 1-indexed
241242

gopls/internal/golang/extract.go

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020

2121
"golang.org/x/tools/go/analysis"
2222
"golang.org/x/tools/go/ast/astutil"
23+
"golang.org/x/tools/gopls/internal/cache"
24+
"golang.org/x/tools/gopls/internal/cache/parsego"
2325
goplsastutil "golang.org/x/tools/gopls/internal/util/astutil"
2426
"golang.org/x/tools/gopls/internal/util/bug"
2527
"golang.org/x/tools/gopls/internal/util/safetoken"
@@ -29,13 +31,13 @@ import (
2931
)
3032

3133
// extractVariable implements the refactor.extract.{variable,constant} CodeAction command.
32-
func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, _ *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
33-
return extractExprs(fset, start, end, src, curFile, info, false)
34+
func extractVariable(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
35+
return extractExprs(pkg, pgf, start, end, false)
3436
}
3537

3638
// extractVariableAll implements the refactor.extract.{variable,constant}-all CodeAction command.
37-
func extractVariableAll(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, _ *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
38-
return extractExprs(fset, start, end, src, curFile, info, true)
39+
func extractVariableAll(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
40+
return extractExprs(pkg, pgf, start, end, true)
3941
}
4042

4143
// extractExprs replaces occurrence(s) of a specified expression within the same function
@@ -44,11 +46,15 @@ func extractVariableAll(fset *token.FileSet, start, end token.Pos, src []byte, c
4446
//
4547
// The new variable/constant is declared as close as possible to the first found expression
4648
// within the deepest common scope accessible to all candidate occurrences.
47-
func extractExprs(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, info *types.Info, all bool) (*token.FileSet, *analysis.SuggestedFix, error) {
48-
file := curFile.Node().(*ast.File)
49+
func extractExprs(pkg *cache.Package, pgf *parsego.File, start, end token.Pos, all bool) (*token.FileSet, *analysis.SuggestedFix, error) {
50+
var (
51+
fset = pkg.FileSet()
52+
info = pkg.TypesInfo()
53+
file = pgf.File
54+
)
4955
// TODO(adonovan): simplify, using Cursor.
5056
tokFile := fset.File(file.FileStart)
51-
exprs, err := canExtractVariable(info, curFile, start, end, all)
57+
exprs, err := canExtractVariable(info, pgf.Cursor, start, end, all)
5258
if err != nil {
5359
return nil, nil, fmt.Errorf("cannot extract: %v", err)
5460
}
@@ -157,7 +163,7 @@ Outer:
157163
return nil, nil, fmt.Errorf("cannot find location to insert extraction: %v", err)
158164
}
159165
// Within function: compute appropriate statement indentation.
160-
indent, err := calculateIndentation(src, tokFile, before)
166+
indent, err := calculateIndentation(pgf.Src, tokFile, before)
161167
if err != nil {
162168
return nil, nil, err
163169
}
@@ -576,13 +582,13 @@ type returnVariable struct {
576582
}
577583

578584
// extractMethod refactors the selected block of code into a new method.
579-
func extractMethod(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
580-
return extractFunctionMethod(fset, start, end, src, curFile, pkg, info, true)
585+
func extractMethod(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
586+
return extractFunctionMethod(pkg, pgf, start, end, true)
581587
}
582588

583589
// extractFunction refactors the selected block of code into a new function.
584-
func extractFunction(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
585-
return extractFunctionMethod(fset, start, end, src, curFile, pkg, info, false)
590+
func extractFunction(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
591+
return extractFunctionMethod(pkg, pgf, start, end, false)
586592
}
587593

588594
// extractFunctionMethod refactors the selected block of code into a new function/method.
@@ -593,19 +599,26 @@ func extractFunction(fset *token.FileSet, start, end token.Pos, src []byte, curF
593599
// and return values of the extracted function/method. Lastly, we construct the call
594600
// of the function/method and insert this call as well as the extracted function/method into
595601
// their proper locations.
596-
func extractFunctionMethod(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info, isMethod bool) (*token.FileSet, *analysis.SuggestedFix, error) {
602+
func extractFunctionMethod(cpkg *cache.Package, pgf *parsego.File, start, end token.Pos, isMethod bool) (*token.FileSet, *analysis.SuggestedFix, error) {
603+
var (
604+
fset = cpkg.FileSet()
605+
pkg = cpkg.Types()
606+
info = cpkg.TypesInfo()
607+
src = pgf.Src
608+
)
609+
597610
errorPrefix := "extractFunction"
598611
if isMethod {
599612
errorPrefix = "extractMethod"
600613
}
601614

602-
file := curFile.Node().(*ast.File)
615+
file := pgf.Cursor.Node().(*ast.File)
603616
// TODO(adonovan): simplify, using Cursor.
604617
tok := fset.File(file.FileStart)
605618
if tok == nil {
606619
return nil, nil, bug.Errorf("no file for position")
607620
}
608-
p, ok, methodOk, err := canExtractFunction(tok, start, end, src, curFile)
621+
p, ok, methodOk, err := canExtractFunction(tok, start, end, src, pgf.Cursor)
609622
if (!ok && !isMethod) || (!methodOk && isMethod) {
610623
return nil, nil, fmt.Errorf("%s: cannot extract %s: %v", errorPrefix,
611624
safetoken.StartPosition(fset, start), err)

gopls/internal/golang/fix.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"context"
99
"fmt"
1010
"go/token"
11-
"go/types"
1211

1312
"golang.org/x/tools/go/analysis"
1413
"golang.org/x/tools/gopls/internal/analysis/embeddirective"
@@ -19,7 +18,6 @@ import (
1918
"golang.org/x/tools/gopls/internal/file"
2019
"golang.org/x/tools/gopls/internal/protocol"
2120
"golang.org/x/tools/gopls/internal/util/bug"
22-
"golang.org/x/tools/internal/astutil/cursor"
2321
"golang.org/x/tools/internal/imports"
2422
)
2523

@@ -41,18 +39,14 @@ import (
4139
// A fixer may return (nil, nil) if no fix is available.
4240
type fixer func(ctx context.Context, s *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error)
4341

44-
// A singleFileFixer is a Fixer that inspects only a single file,
45-
// and does not depend on data types from the cache package.
46-
//
47-
// TODO(adonovan): move fillstruct and undeclaredname into this
48-
// package, so we can remove the import restriction and push
49-
// the singleFile wrapper down into each singleFileFixer?
50-
type singleFileFixer func(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error)
42+
// A singleFileFixer is a [fixer] that inspects only a single file.
43+
type singleFileFixer func(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error)
5144

52-
// singleFile adapts a single-file fixer to a Fixer.
45+
// singleFile adapts a [singleFileFixer] to a [fixer]
46+
// by discarding the snapshot and the context it needs.
5347
func singleFile(fixer1 singleFileFixer) fixer {
54-
return func(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
55-
return fixer1(pkg.FileSet(), start, end, pgf.Src, pgf.Cursor, pkg.Types(), pkg.TypesInfo())
48+
return func(_ context.Context, _ *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
49+
return fixer1(pkg, pgf, start, end)
5650
}
5751
}
5852

gopls/internal/golang/invertifcondition.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,24 @@ import (
88
"fmt"
99
"go/ast"
1010
"go/token"
11-
"go/types"
1211
"strings"
1312

1413
"golang.org/x/tools/go/analysis"
1514
"golang.org/x/tools/go/ast/astutil"
15+
"golang.org/x/tools/gopls/internal/cache"
16+
"golang.org/x/tools/gopls/internal/cache/parsego"
1617
"golang.org/x/tools/gopls/internal/util/safetoken"
1718
"golang.org/x/tools/internal/astutil/cursor"
1819
)
1920

2021
// invertIfCondition is a singleFileFixFunc that inverts an if/else statement
21-
func invertIfCondition(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, _ *types.Package, _ *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
22-
ifStatement, _, err := canInvertIfCondition(curFile, start, end)
22+
func invertIfCondition(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
23+
var (
24+
fset = pkg.FileSet()
25+
src = pgf.Src
26+
)
27+
28+
ifStatement, _, err := canInvertIfCondition(pgf.Cursor, start, end)
2329
if err != nil {
2430
return nil, nil, err
2531
}

gopls/internal/golang/lines.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ import (
1212
"bytes"
1313
"go/ast"
1414
"go/token"
15-
"go/types"
1615
"slices"
1716
"sort"
1817
"strings"
1918

2019
"golang.org/x/tools/go/analysis"
2120
"golang.org/x/tools/go/ast/astutil"
21+
"golang.org/x/tools/gopls/internal/cache"
22+
"golang.org/x/tools/gopls/internal/cache/parsego"
2223
"golang.org/x/tools/gopls/internal/util/safetoken"
2324
"golang.org/x/tools/internal/astutil/cursor"
2425
)
@@ -85,23 +86,25 @@ func canSplitJoinLines(items []ast.Node, comments []*ast.CommentGroup) bool {
8586
}
8687

8788
// splitLines is a singleFile fixer.
88-
func splitLines(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, _ *types.Package, _ *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
89-
itemType, items, comments, indent, braceOpen, braceClose := findSplitJoinTarget(fset, curFile, src, start, end)
89+
func splitLines(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
90+
fset := pkg.FileSet()
91+
itemType, items, comments, indent, braceOpen, braceClose := findSplitJoinTarget(fset, pgf.Cursor, pgf.Src, start, end)
9092
if itemType == "" {
9193
return nil, nil, nil // no fix available
9294
}
9395

94-
return fset, processLines(fset, items, comments, src, braceOpen, braceClose, ",\n", "\n", ",\n"+indent, indent+"\t"), nil
96+
return fset, processLines(fset, items, comments, pgf.Src, braceOpen, braceClose, ",\n", "\n", ",\n"+indent, indent+"\t"), nil
9597
}
9698

9799
// joinLines is a singleFile fixer.
98-
func joinLines(fset *token.FileSet, start, end token.Pos, src []byte, curFile cursor.Cursor, _ *types.Package, _ *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
99-
itemType, items, comments, _, braceOpen, braceClose := findSplitJoinTarget(fset, curFile, src, start, end)
100+
func joinLines(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
101+
fset := pkg.FileSet()
102+
itemType, items, comments, _, braceOpen, braceClose := findSplitJoinTarget(fset, pgf.Cursor, pgf.Src, start, end)
100103
if itemType == "" {
101104
return nil, nil, nil // no fix available
102105
}
103106

104-
return fset, processLines(fset, items, comments, src, braceOpen, braceClose, ", ", "", "", ""), nil
107+
return fset, processLines(fset, items, comments, pgf.Src, braceOpen, braceClose, ", ", "", "", ""), nil
105108
}
106109

107110
// processLines is the common operation for both split and join lines because this split/join operation is

gopls/internal/golang/undeclared.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ import (
1616

1717
"golang.org/x/tools/go/analysis"
1818
"golang.org/x/tools/go/ast/astutil"
19+
"golang.org/x/tools/gopls/internal/cache"
20+
"golang.org/x/tools/gopls/internal/cache/parsego"
1921
"golang.org/x/tools/gopls/internal/util/typesutil"
20-
"golang.org/x/tools/internal/astutil/cursor"
2122
"golang.org/x/tools/internal/typesinternal"
2223
)
2324

@@ -70,9 +71,13 @@ func undeclaredFixTitle(path []ast.Node, errMsg string) string {
7071
}
7172

7273
// createUndeclared generates a suggested declaration for an undeclared variable or function.
73-
func createUndeclared(fset *token.FileSet, start, end token.Pos, content []byte, curFile cursor.Cursor, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
74-
pos := start // don't use the end
75-
file := curFile.Node().(*ast.File)
74+
func createUndeclared(pkg *cache.Package, pgf *parsego.File, start, end token.Pos) (*token.FileSet, *analysis.SuggestedFix, error) {
75+
var (
76+
fset = pkg.FileSet()
77+
info = pkg.TypesInfo()
78+
file = pgf.File
79+
pos = start // don't use end
80+
)
7681
// TODO(adonovan): simplify, using Cursor.
7782
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
7883
if len(path) < 2 {
@@ -86,7 +91,7 @@ func createUndeclared(fset *token.FileSet, start, end token.Pos, content []byte,
8691
// Check for a possible call expression, in which case we should add a
8792
// new function declaration.
8893
if isCallPosition(path) {
89-
return newFunctionDeclaration(path, file, pkg, info, fset)
94+
return newFunctionDeclaration(path, file, pkg.Types(), info, fset)
9095
}
9196
var (
9297
firstRef *ast.Ident // We should insert the new declaration before the first occurrence of the undefined ident.
@@ -132,7 +137,7 @@ func createUndeclared(fset *token.FileSet, start, end token.Pos, content []byte,
132137
if err != nil {
133138
return nil, nil, fmt.Errorf("could not locate insertion point: %v", err)
134139
}
135-
indent, err := calculateIndentation(content, fset.File(file.FileStart), insertBeforeStmt)
140+
indent, err := calculateIndentation(pgf.Src, fset.File(file.FileStart), insertBeforeStmt)
136141
if err != nil {
137142
return nil, nil, err
138143
}
@@ -141,7 +146,7 @@ func createUndeclared(fset *token.FileSet, start, end token.Pos, content []byte,
141146
// Default to 0.
142147
typs = []types.Type{types.Typ[types.Int]}
143148
}
144-
expr, _ := typesinternal.ZeroExpr(typs[0], typesinternal.FileQualifier(file, pkg))
149+
expr, _ := typesinternal.ZeroExpr(typs[0], typesinternal.FileQualifier(file, pkg.Types()))
145150
assignStmt := &ast.AssignStmt{
146151
Lhs: []ast.Expr{ast.NewIdent(ident.Name)},
147152
Tok: token.DEFINE,

0 commit comments

Comments
 (0)