Skip to content

Commit 30641f5

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/analysis/modernize: use typeindex throughout
Change-Id: Ibc59b715430f60a4d311adff5fe75287ae2b897a Reviewed-on: https://go-review.googlesource.com/c/tools/+/660616 Reviewed-by: Jonathan Amsterdam <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Commit-Queue: Alan Donovan <[email protected]>
1 parent 11a3153 commit 30641f5

File tree

8 files changed

+103
-104
lines changed

8 files changed

+103
-104
lines changed

gopls/internal/analysis/modernize/bloop.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import (
1515
"golang.org/x/tools/go/ast/inspector"
1616
"golang.org/x/tools/go/types/typeutil"
1717
"golang.org/x/tools/internal/analysisinternal"
18+
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
1819
"golang.org/x/tools/internal/astutil/cursor"
20+
"golang.org/x/tools/internal/typesinternal/typeindex"
1921
)
2022

2123
// bloop updates benchmarks that use "for range b.N", replacing it
@@ -31,7 +33,11 @@ func bloop(pass *analysis.Pass) {
3133
return
3234
}
3335

34-
info := pass.TypesInfo
36+
var (
37+
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
38+
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
39+
info = pass.TypesInfo
40+
)
3541

3642
// edits computes the text edits for a matched for/range loop
3743
// at the specified cursor. b is the *testing.B value, and
@@ -76,7 +82,6 @@ func bloop(pass *analysis.Pass) {
7682
}
7783

7884
// Find all for/range statements.
79-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
8085
loops := []ast.Node{
8186
(*ast.ForStmt)(nil),
8287
(*ast.RangeStmt)(nil),
@@ -105,7 +110,7 @@ func bloop(pass *analysis.Pass) {
105110
is[*ast.IncDecStmt](n.Post) &&
106111
n.Post.(*ast.IncDecStmt).Tok == token.INC &&
107112
equalSyntax(n.Post.(*ast.IncDecStmt).X, assign.Lhs[0]) &&
108-
!uses(info, body, info.Defs[assign.Lhs[0].(*ast.Ident)]) {
113+
!uses(index, body, info.Defs[assign.Lhs[0].(*ast.Ident)]) {
109114

110115
delStart, delEnd = n.Init.Pos(), n.Post.End()
111116
}
@@ -152,10 +157,9 @@ func bloop(pass *analysis.Pass) {
152157
}
153158

154159
// uses reports whether the subtree cur contains a use of obj.
155-
// TODO(adonovan): opt: use typeindex.
156-
func uses(info *types.Info, cur cursor.Cursor, obj types.Object) bool {
157-
for curId := range cur.Preorder((*ast.Ident)(nil)) {
158-
if info.Uses[curId.Node().(*ast.Ident)] == obj {
160+
func uses(index *typeindex.Index, cur cursor.Cursor, obj types.Object) bool {
161+
for use := range index.Uses(obj) {
162+
if cur.Contains(use) {
159163
return true
160164
}
161165
}

gopls/internal/analysis/modernize/fmtappendf.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func fmtappendf(pass *analysis.Pass) {
3232
conv := curCall.Parent().Node().(*ast.CallExpr)
3333
tv := pass.TypesInfo.Types[conv.Fun]
3434
if tv.IsType() && types.Identical(tv.Type, byteSliceType) &&
35-
fileUses(pass.TypesInfo, curCall, "go1.19") {
35+
fileUses(pass.TypesInfo, enclosingFile(curCall), "go1.19") {
3636
// Have: []byte(fmt.SprintX(...))
3737

3838
// Find "Sprint" identifier.

gopls/internal/analysis/modernize/modernize.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,19 @@ func filesUsing(inspect *inspector.Inspector, info *types.Info, version string)
140140
}
141141
}
142142

143-
// fileUses reports whether the file containing the specified cursor
144-
// uses at least the specified version of Go (e.g. "go1.24").
145-
func fileUses(info *types.Info, c cursor.Cursor, version string) bool {
143+
// fileUses reports whether the specified file uses at least the
144+
// specified version of Go (e.g. "go1.24").
145+
func fileUses(info *types.Info, file *ast.File, version string) bool {
146+
return !versions.Before(info.FileVersions[file], version)
147+
}
148+
149+
// enclosingFile returns the syntax tree for the file enclosing c.
150+
func enclosingFile(c cursor.Cursor) *ast.File {
146151
// TODO(adonovan): make Ancestors reflexive so !ok becomes impossible.
147152
if curFile, ok := moreiters.First(c.Ancestors((*ast.File)(nil))); ok {
148153
c = curFile
149154
}
150-
file := c.Node().(*ast.File)
151-
return !versions.Before(info.FileVersions[file], version)
155+
return c.Node().(*ast.File)
152156
}
153157

154158
// within reports whether the current pass is analyzing one of the

gopls/internal/analysis/modernize/slicescontains.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ import (
1515
"golang.org/x/tools/go/ast/inspector"
1616
"golang.org/x/tools/go/types/typeutil"
1717
"golang.org/x/tools/internal/analysisinternal"
18+
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
1819
"golang.org/x/tools/internal/astutil/cursor"
1920
"golang.org/x/tools/internal/typeparams"
21+
"golang.org/x/tools/internal/typesinternal/typeindex"
2022
)
2123

2224
// The slicescontains pass identifies loops that can be replaced by a
@@ -56,7 +58,11 @@ func slicescontains(pass *analysis.Pass) {
5658
return
5759
}
5860

59-
info := pass.TypesInfo
61+
var (
62+
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
63+
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
64+
info = pass.TypesInfo
65+
)
6066

6167
// check is called for each RangeStmt of this form:
6268
// for i, elem := range s { if cond { ... } }
@@ -144,8 +150,8 @@ func slicescontains(pass *analysis.Pass) {
144150
if !ok {
145151
panic(fmt.Sprintf("FindNode(%T) failed", n))
146152
}
147-
return uses(info, cur, info.Defs[rng.Key.(*ast.Ident)]) ||
148-
rng.Value != nil && uses(info, cur, info.Defs[rng.Value.(*ast.Ident)])
153+
return uses(index, cur, info.Defs[rng.Key.(*ast.Ident)]) ||
154+
rng.Value != nil && uses(index, cur, info.Defs[rng.Value.(*ast.Ident)])
149155
}
150156
if usesRangeVar(body) {
151157
// Body uses range var "i" or "elem".
@@ -349,7 +355,6 @@ func slicescontains(pass *analysis.Pass) {
349355
}
350356
}
351357

352-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
353358
for curFile := range filesUsing(inspect, info, "go1.21") {
354359
file := curFile.Node().(*ast.File)
355360

gopls/internal/analysis/modernize/sortslice.go

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ import (
1010
"go/types"
1111

1212
"golang.org/x/tools/go/analysis"
13-
"golang.org/x/tools/go/analysis/passes/inspect"
14-
"golang.org/x/tools/go/ast/inspector"
15-
"golang.org/x/tools/go/types/typeutil"
1613
"golang.org/x/tools/internal/analysisinternal"
14+
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
15+
"golang.org/x/tools/internal/typesinternal/typeindex"
1716
)
1817

1918
// The sortslice pass replaces sort.Slice(slice, less) with
@@ -42,14 +41,13 @@ func sortslice(pass *analysis.Pass) {
4241
return
4342
}
4443

45-
info := pass.TypesInfo
46-
47-
check := func(file *ast.File, call *ast.CallExpr) {
48-
// call to sort.Slice?
49-
obj := typeutil.Callee(info, call)
50-
if !analysisinternal.IsFunctionNamed(obj, "sort", "Slice") {
51-
return
52-
}
44+
var (
45+
info = pass.TypesInfo
46+
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
47+
sortSlice = index.Object("sort", "Slice")
48+
)
49+
for curCall := range index.Calls(sortSlice) {
50+
call := curCall.Node().(*ast.CallExpr)
5351
if lit, ok := call.Args[1].(*ast.FuncLit); ok && len(lit.Body.List) == 1 {
5452
sig := info.Types[lit.Type].Type.(*types.Signature)
5553

@@ -68,7 +66,9 @@ func sortslice(pass *analysis.Pass) {
6866
is[*ast.Ident](index.Index) &&
6967
info.Uses[index.Index.(*ast.Ident)] == v
7068
}
71-
if isIndex(compare.X, i) && isIndex(compare.Y, j) {
69+
file := enclosingFile(curCall)
70+
if isIndex(compare.X, i) && isIndex(compare.Y, j) &&
71+
fileUses(info, file, "go1.21") {
7272
// Have: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
7373

7474
_, prefix, importEdits := analysisinternal.AddImport(
@@ -102,14 +102,4 @@ func sortslice(pass *analysis.Pass) {
102102
}
103103
}
104104
}
105-
106-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
107-
for curFile := range filesUsing(inspect, info, "go1.21") {
108-
file := curFile.Node().(*ast.File)
109-
110-
for curCall := range curFile.Preorder((*ast.CallExpr)(nil)) {
111-
call := curCall.Node().(*ast.CallExpr)
112-
check(file, call)
113-
}
114-
}
115105
}

gopls/internal/analysis/modernize/stringscutprefix.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"golang.org/x/tools/go/ast/inspector"
1515
"golang.org/x/tools/go/types/typeutil"
1616
"golang.org/x/tools/internal/analysisinternal"
17+
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
18+
"golang.org/x/tools/internal/typesinternal/typeindex"
1719
)
1820

1921
// stringscutprefix offers a fix to replace an if statement which
@@ -35,8 +37,15 @@ import (
3537
// Variants:
3638
// - bytes.HasPrefix usage as pattern 1.
3739
func stringscutprefix(pass *analysis.Pass) {
38-
if !analysisinternal.Imports(pass.Pkg, "strings") &&
39-
!analysisinternal.Imports(pass.Pkg, "bytes") {
40+
var (
41+
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
42+
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
43+
info = pass.TypesInfo
44+
45+
stringsTrimPrefix = index.Object("strings", "TrimPrefix")
46+
bytesTrimPrefix = index.Object("bytes", "TrimPrefix")
47+
)
48+
if !index.Used(stringsTrimPrefix, bytesTrimPrefix) {
4049
return
4150
}
4251

@@ -45,8 +54,6 @@ func stringscutprefix(pass *analysis.Pass) {
4554
fixedMessage = "Replace HasPrefix/TrimPrefix with CutPrefix"
4655
)
4756

48-
info := pass.TypesInfo
49-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
5057
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.20") {
5158
for curIfStmt := range curFile.Preorder((*ast.IfStmt)(nil)) {
5259
ifStmt := curIfStmt.Node().(*ast.IfStmt)
@@ -65,8 +72,7 @@ func stringscutprefix(pass *analysis.Pass) {
6572
for curCall := range firstStmt.Preorder((*ast.CallExpr)(nil)) {
6673
call1 := curCall.Node().(*ast.CallExpr)
6774
obj1 := typeutil.Callee(info, call1)
68-
if !analysisinternal.IsFunctionNamed(obj1, "strings", "TrimPrefix") &&
69-
!analysisinternal.IsFunctionNamed(obj1, "bytes", "TrimPrefix") {
75+
if obj1 != stringsTrimPrefix && obj1 != bytesTrimPrefix {
7076
continue
7177
}
7278

@@ -140,7 +146,7 @@ func stringscutprefix(pass *analysis.Pass) {
140146
if call, ok := assign.Rhs[0].(*ast.CallExpr); ok && assign.Tok == token.DEFINE {
141147
lhs := assign.Lhs[0]
142148
obj := typeutil.Callee(info, call)
143-
if analysisinternal.IsFunctionNamed(obj, "strings", "TrimPrefix") &&
149+
if obj == stringsTrimPrefix &&
144150
(equalSyntax(lhs, bin.X) && equalSyntax(call.Args[0], bin.Y) ||
145151
(equalSyntax(lhs, bin.Y) && equalSyntax(call.Args[0], bin.X))) {
146152
okVarName := analysisinternal.FreshName(info.Scopes[ifStmt], ifStmt.Pos(), "ok")

gopls/internal/analysis/modernize/stringsseq.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import (
1414
"golang.org/x/tools/go/analysis/passes/inspect"
1515
"golang.org/x/tools/go/ast/inspector"
1616
"golang.org/x/tools/go/types/typeutil"
17-
"golang.org/x/tools/internal/analysisinternal"
17+
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
1818
"golang.org/x/tools/internal/astutil/edge"
19+
"golang.org/x/tools/internal/typesinternal/typeindex"
1920
)
2021

2122
// stringsseq offers a fix to replace a call to strings.Split with
@@ -33,12 +34,20 @@ import (
3334
// - bytes.SplitSeq
3435
// - bytes.FieldsSeq
3536
func stringsseq(pass *analysis.Pass) {
36-
if !analysisinternal.Imports(pass.Pkg, "strings") &&
37-
!analysisinternal.Imports(pass.Pkg, "bytes") {
37+
var (
38+
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
39+
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
40+
info = pass.TypesInfo
41+
42+
stringsSplit = index.Object("strings", "Split")
43+
stringsFields = index.Object("strings", "Fields")
44+
bytesSplit = index.Object("bytes", "Split")
45+
bytesFields = index.Object("bytes", "Fields")
46+
)
47+
if !index.Used(stringsSplit, stringsFields, bytesSplit, bytesFields) {
3848
return
3949
}
40-
info := pass.TypesInfo
41-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
50+
4251
for curFile := range filesUsing(inspect, info, "go1.24") {
4352
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
4453
rng := curRange.Node().(*ast.RangeStmt)
@@ -62,7 +71,7 @@ func stringsseq(pass *analysis.Pass) {
6271
len(assign.Lhs) == 1 &&
6372
len(assign.Rhs) == 1 &&
6473
info.Defs[assign.Lhs[0].(*ast.Ident)] == v &&
65-
soleUse(info, v) == id {
74+
soleUseIs(index, v, id) {
6675
// Have:
6776
// lines := ...
6877
// for _, line := range lines {...}
@@ -96,9 +105,8 @@ func stringsseq(pass *analysis.Pass) {
96105
continue
97106
}
98107

99-
obj := typeutil.Callee(info, call)
100-
if analysisinternal.IsFunctionNamed(obj, "strings", "Split", "Fields") ||
101-
analysisinternal.IsFunctionNamed(obj, "bytes", "Split", "Fields") {
108+
switch obj := typeutil.Callee(info, call); obj {
109+
case stringsSplit, stringsFields, bytesSplit, bytesFields:
102110
oldFnName := obj.Name()
103111
seqFnName := fmt.Sprintf("%sSeq", oldFnName)
104112
pass.Report(analysis.Diagnostic{

0 commit comments

Comments
 (0)