Skip to content

Commit edb9587

Browse files
committed
go/analysis/passes/modernize: stditerators: better name heuristic
This change causes stditerators' name heuristic to choose the name v from a function body of this form: for i := 0; i < x.Len(); i++ { if v := x.At(i); cond { ... } } The fix may result in the degenerate for v := range x.All() { if v := v; cond { ... } } so the forvar analyzer has been taught to recognise this pattern too (see parent CL). Updates golang/go#76240 Updates golang/go#76241 Change-Id: I8888fea5adce3e5f55002abadd16527f877e3389 Reviewed-on: https://go-review.googlesource.com/c/tools/+/719361 Reviewed-by: Robert Findley <rfindley@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 2f6a4f9 commit edb9587

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

go/analysis/passes/modernize/stditerators.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ func stditerators(pass *analysis.Pass) (any, error) {
112112
//
113113
// for ... { e := x.At(i); use(e) }
114114
//
115+
// or
116+
//
117+
// for ... { if e := x.At(i); cond { use(e) } }
118+
//
115119
// then chooseName prefers the name e and additionally
116120
// returns the var's symbol. We'll transform this to:
117121
//
@@ -120,10 +124,11 @@ func stditerators(pass *analysis.Pass) (any, error) {
120124
// which leaves a redundant assignment that a
121125
// subsequent 'forvar' pass will eliminate.
122126
chooseName := func(curBody inspector.Cursor, x ast.Expr, i *types.Var) (string, *types.Var) {
123-
// Is body { elem := x.At(i); ... } ?
124-
body := curBody.Node().(*ast.BlockStmt)
125-
if len(body.List) > 0 {
126-
if assign, ok := body.List[0].(*ast.AssignStmt); ok &&
127+
128+
// isVarAssign reports whether stmt has the form v := x.At(i)
129+
// and returns the variable if so.
130+
isVarAssign := func(stmt ast.Stmt) *types.Var {
131+
if assign, ok := stmt.(*ast.AssignStmt); ok &&
127132
assign.Tok == token.DEFINE &&
128133
len(assign.Lhs) == 1 &&
129134
len(assign.Rhs) == 1 &&
@@ -134,9 +139,25 @@ func stditerators(pass *analysis.Pass) (any, error) {
134139
astutil.EqualSyntax(ast.Unparen(call.Fun).(*ast.SelectorExpr).X, x) &&
135140
is[*ast.Ident](call.Args[0]) &&
136141
info.Uses[call.Args[0].(*ast.Ident)] == i {
137-
// Have: { elem := x.At(i); ... }
142+
// Have: elem := x.At(i)
138143
id := assign.Lhs[0].(*ast.Ident)
139-
return id.Name, info.Defs[id].(*types.Var)
144+
return info.Defs[id].(*types.Var)
145+
}
146+
}
147+
return nil
148+
}
149+
150+
body := curBody.Node().(*ast.BlockStmt)
151+
if len(body.List) > 0 {
152+
// Is body { elem := x.At(i); ... } ?
153+
if v := isVarAssign(body.List[0]); v != nil {
154+
return v.Name(), v
155+
}
156+
157+
// Or { if elem := x.At(i); cond { ... } } ?
158+
if ifstmt, ok := body.List[0].(*ast.IfStmt); ok && ifstmt.Init != nil {
159+
if v := isVarAssign(ifstmt.Init); v != nil {
160+
return v.Name(), v
140161
}
141162
}
142163
}

go/analysis/passes/modernize/testdata/src/stditerators/stditerators.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@ func _(union, union2 *types.Union) {
5656
print(i, union2.Term(i))
5757
}
5858
}
59+
60+
func _(tuple *types.Tuple) {
61+
for i := 0; i < tuple.Len(); i++ { // want "Len/At loop can simplified using Tuple.Variables iteration"
62+
if foo := tuple.At(i); true { // => preferred name = "foo"
63+
print(foo)
64+
}
65+
bar := tuple.At(i)
66+
print(bar)
67+
}
68+
}

go/analysis/passes/modernize/testdata/src/stditerators/stditerators.go.golden

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@ func _(union, union2 *types.Union) {
5656
print(i, union2.Term(i))
5757
}
5858
}
59+
60+
func _(tuple *types.Tuple) {
61+
for foo := range tuple.Variables() { // want "Len/At loop can simplified using Tuple.Variables iteration"
62+
if foo := foo; true { // => preferred name = "foo"
63+
print(foo)
64+
}
65+
bar := foo
66+
print(bar)
67+
}
68+
}

0 commit comments

Comments
 (0)