Skip to content

Commit a6adab9

Browse files
committed
gopls/internal/analysis/modernize: check FileVersions throughout
This CL ensures that every modernizer sub-pass checks the effective Go version of each file before inspecting that file, using a version-filtering *ast.File iterator, something enabled by Cursors. It does increase indentation by a level though, so I split some of the deeper function into outer and inner parts. Change-Id: I2bcd059c4f52af5673a7d1e9f07ff9463dce96b0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/638698 Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent c437d40 commit a6adab9

File tree

7 files changed

+356
-351
lines changed

7 files changed

+356
-351
lines changed

gopls/internal/analysis/modernize/bloop.go

+8-16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"golang.org/x/tools/go/types/typeutil"
1717
"golang.org/x/tools/internal/astutil/cursor"
1818
"golang.org/x/tools/internal/typesinternal"
19-
"golang.org/x/tools/internal/versions"
2019
)
2120

2221
// bloop updates benchmarks that use "for range b.N", replacing it
@@ -82,19 +81,13 @@ func bloop(pass *analysis.Pass) {
8281

8382
// Find all for/range statements.
8483
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
85-
filter := []ast.Node{
86-
(*ast.File)(nil),
84+
loops := []ast.Node{
8785
(*ast.ForStmt)(nil),
8886
(*ast.RangeStmt)(nil),
8987
}
90-
cursor.Root(inspect).Inspect(filter, func(cur cursor.Cursor, push bool) (descend bool) {
91-
if push {
92-
switch n := cur.Node().(type) {
93-
case *ast.File:
94-
if versions.Before(info.FileVersions[n], "go1.24") {
95-
return false
96-
}
97-
88+
for curFile := range filesUsing(inspect, info, "go1.24") {
89+
for curLoop := range curFile.Preorder(loops...) {
90+
switch n := curLoop.Node().(type) {
9891
case *ast.ForStmt:
9992
// for _; i < b.N; _ {}
10093
if cmp, ok := n.Cond.(*ast.BinaryExpr); ok && cmp.Op == token.LSS {
@@ -108,7 +101,7 @@ func bloop(pass *analysis.Pass) {
108101
// for i := 0; i < b.N; i++ {
109102
// ...no references to i...
110103
// }
111-
body, _ := cur.LastChild()
104+
body, _ := curLoop.LastChild()
112105
if assign, ok := n.Init.(*ast.AssignStmt); ok &&
113106
assign.Tok == token.DEFINE &&
114107
len(assign.Rhs) == 1 &&
@@ -129,7 +122,7 @@ func bloop(pass *analysis.Pass) {
129122
Message: "b.N can be modernized using b.Loop()",
130123
SuggestedFixes: []analysis.SuggestedFix{{
131124
Message: "Replace b.N with b.Loop()",
132-
TextEdits: edits(cur, sel.X, delStart, delEnd),
125+
TextEdits: edits(curLoop, sel.X, delStart, delEnd),
133126
}},
134127
})
135128
}
@@ -153,14 +146,13 @@ func bloop(pass *analysis.Pass) {
153146
Message: "b.N can be modernized using b.Loop()",
154147
SuggestedFixes: []analysis.SuggestedFix{{
155148
Message: "Replace b.N with b.Loop()",
156-
TextEdits: edits(cur, sel.X, n.Range, n.X.End()),
149+
TextEdits: edits(curLoop, sel.X, n.Range, n.X.End()),
157150
}},
158151
})
159152
}
160153
}
161154
}
162-
return true
163-
})
155+
}
164156
}
165157

166158
// isPtrToNamed reports whether t is type "*pkgpath.Name".

gopls/internal/analysis/modernize/efaceany.go

+29-27
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,45 @@ package modernize
66

77
import (
88
"go/ast"
9-
"go/types"
109

1110
"golang.org/x/tools/go/analysis"
1211
"golang.org/x/tools/go/analysis/passes/inspect"
1312
"golang.org/x/tools/go/ast/inspector"
1413
)
1514

16-
// The efaceany pass replaces interface{} with 'any'.
15+
// The efaceany pass replaces interface{} with go1.18's 'any'.
1716
func efaceany(pass *analysis.Pass) {
18-
// TODO(adonovan): opt: combine all these micro-passes into a single traversal.
1917
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
20-
for iface := range inspector.All[*ast.InterfaceType](inspect) {
21-
if iface.Methods.NumFields() == 0 {
2218

23-
// TODO(adonovan): opt: record the enclosing file as we go.
24-
f := enclosingFile(pass, iface.Pos())
25-
scope := pass.TypesInfo.Scopes[f].Innermost(iface.Pos())
26-
if _, obj := scope.LookupParent("any", iface.Pos()); obj != types.Universe.Lookup("any") {
27-
continue // 'any' is shadowed
28-
}
19+
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.18") {
20+
file := curFile.Node().(*ast.File)
21+
22+
for curIface := range curFile.Preorder((*ast.InterfaceType)(nil)) {
23+
iface := curIface.Node().(*ast.InterfaceType)
2924

30-
pass.Report(analysis.Diagnostic{
31-
Pos: iface.Pos(),
32-
End: iface.End(),
33-
Category: "efaceany",
34-
Message: "interface{} can be replaced by any",
35-
SuggestedFixes: []analysis.SuggestedFix{{
36-
Message: "Replace interface{} by any",
37-
TextEdits: []analysis.TextEdit{
38-
{
39-
Pos: iface.Pos(),
40-
End: iface.End(),
41-
NewText: []byte("any"),
42-
},
43-
},
44-
}},
45-
})
25+
if iface.Methods.NumFields() == 0 {
26+
// Check that 'any' is not shadowed.
27+
// TODO(adonovan): find scope using only local Cursor operations.
28+
scope := pass.TypesInfo.Scopes[file].Innermost(iface.Pos())
29+
if _, obj := scope.LookupParent("any", iface.Pos()); obj == builtinAny {
30+
pass.Report(analysis.Diagnostic{
31+
Pos: iface.Pos(),
32+
End: iface.End(),
33+
Category: "efaceany",
34+
Message: "interface{} can be replaced by any",
35+
SuggestedFixes: []analysis.SuggestedFix{{
36+
Message: "Replace interface{} by any",
37+
TextEdits: []analysis.TextEdit{
38+
{
39+
Pos: iface.Pos(),
40+
End: iface.End(),
41+
NewText: []byte("any"),
42+
},
43+
},
44+
}},
45+
})
46+
}
47+
}
4648
}
4749
}
4850
}

0 commit comments

Comments
 (0)