@@ -43,10 +43,28 @@ func run(pass *analysis.Pass) (interface{}, error) {
43
43
}
44
44
45
45
inspect .WithStack (nodeFilter , func (n ast.Node , push bool , stack []ast.Node ) bool {
46
- id , digg := search .Check (n , stack )
46
+ id , insert , digg := search .Check (n , stack )
47
47
if id != nil {
48
- msg := fmt .Sprintf ("exporting a pointer for the loop variable %s" , id .Name )
49
- pass .Report (analysis.Diagnostic {Pos : id .Pos (), End : id .End (), Message : msg , Category : "exportloopref" })
48
+ dMsg := fmt .Sprintf ("exporting a pointer for the loop variable %s" , id .Name )
49
+ fMsg := fmt .Sprintf ("loop variable %s should be pinned" , id .Name )
50
+ var suggest []analysis.SuggestedFix
51
+ if insert != token .NoPos {
52
+ suggest = []analysis.SuggestedFix {{
53
+ Message : fMsg ,
54
+ TextEdits : []analysis.TextEdit {{
55
+ Pos : insert ,
56
+ End : insert ,
57
+ NewText : []byte (fmt .Sprintf ("%[1]s := %[1]s\n " , id .Name )),
58
+ }},
59
+ }}
60
+ }
61
+ d := analysis.Diagnostic {Pos : id .Pos (),
62
+ End : id .End (),
63
+ Message : dMsg ,
64
+ Category : "exportloopref" ,
65
+ SuggestedFixes : suggest ,
66
+ }
67
+ pass .Report (d )
50
68
}
51
69
return digg
52
70
})
@@ -67,7 +85,7 @@ type Searcher struct {
67
85
Types map [ast.Expr ]types.TypeAndValue
68
86
}
69
87
70
- func (s * Searcher ) Check (n ast.Node , stack []ast.Node ) (* ast.Ident , bool ) {
88
+ func (s * Searcher ) Check (n ast.Node , stack []ast.Node ) (* ast.Ident , token. Pos , bool ) {
71
89
switch typed := n .(type ) {
72
90
case * ast.RangeStmt :
73
91
s .parseRangeStmt (typed )
@@ -81,7 +99,7 @@ func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, bool) {
81
99
case * ast.UnaryExpr :
82
100
return s .checkUnaryExpr (typed , stack )
83
101
}
84
- return nil , true
102
+ return nil , token . NoPos , true
85
103
}
86
104
87
105
func (s * Searcher ) parseRangeStmt (n * ast.RangeStmt ) {
@@ -109,7 +127,7 @@ func (s *Searcher) addStat(expr ast.Expr) {
109
127
}
110
128
111
129
func (s * Searcher ) parseDeclStmt (n * ast.DeclStmt , stack []ast.Node ) {
112
- loop := s .innermostLoop (stack )
130
+ loop , _ := s .innermostLoop (stack )
113
131
if loop == nil {
114
132
return
115
133
}
@@ -125,7 +143,7 @@ func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) {
125
143
}
126
144
127
145
func (s * Searcher ) parseAssignStmt (n * ast.AssignStmt , stack []ast.Node ) {
128
- loop := s .innermostLoop (stack )
146
+ loop , _ := s .innermostLoop (stack )
129
147
if loop == nil {
130
148
return
131
149
}
@@ -152,36 +170,45 @@ func (s *Searcher) addVar(loop ast.Node, expr ast.Expr) {
152
170
s .Vars [loopPos ] = vars
153
171
}
154
172
155
- func (s * Searcher ) innermostLoop (stack []ast.Node ) ast.Node {
173
+ func insertionPosition (block * ast.BlockStmt ) token.Pos {
174
+ if len (block .List ) > 0 {
175
+ return block .List [0 ].Pos ()
176
+ }
177
+ return token .NoPos
178
+ }
179
+
180
+ func (s * Searcher ) innermostLoop (stack []ast.Node ) (ast.Node , token.Pos ) {
156
181
for i := len (stack ) - 1 ; i >= 0 ; i -- {
157
- switch stack [i ].(type ) {
158
- case * ast.RangeStmt , * ast.ForStmt :
159
- return stack [i ]
182
+ switch typed := stack [i ].(type ) {
183
+ case * ast.RangeStmt :
184
+ return typed , insertionPosition (typed .Body )
185
+ case * ast.ForStmt :
186
+ return typed , insertionPosition (typed .Body )
160
187
}
161
188
}
162
- return nil
189
+ return nil , token . NoPos
163
190
}
164
191
165
- func (s * Searcher ) checkUnaryExpr (n * ast.UnaryExpr , stack []ast.Node ) (* ast.Ident , bool ) {
166
- loop := s .innermostLoop (stack )
192
+ func (s * Searcher ) checkUnaryExpr (n * ast.UnaryExpr , stack []ast.Node ) (* ast.Ident , token. Pos , bool ) {
193
+ loop , insert := s .innermostLoop (stack )
167
194
if loop == nil {
168
- return nil , true
195
+ return nil , token . NoPos , true
169
196
}
170
197
171
198
if n .Op != token .AND {
172
- return nil , true
199
+ return nil , token . NoPos , true
173
200
}
174
201
175
202
// Get identity of the referred item
176
203
id := s .getIdentity (n .X )
177
204
if id == nil {
178
- return nil , true
205
+ return nil , token . NoPos , true
179
206
}
180
207
181
208
// If the identity is not the loop statement variable,
182
209
// it will not be reported.
183
210
if _ , isStat := s .Stats [id .Obj .Pos ()]; ! isStat {
184
- return nil , true
211
+ return nil , token . NoPos , true
185
212
}
186
213
187
214
// check stack append(), []X{}, map[Type]X{}, Struct{}, &Struct{}, X.(Type), (X)
@@ -198,16 +225,16 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
198
225
case (* ast.CallExpr ):
199
226
fun , ok := typed .Fun .(* ast.Ident )
200
227
if ! ok {
201
- return nil , false // it's calling a function other of `append`. It cannot be checked
228
+ return nil , token . NoPos , false // it's calling a function other of `append`. It cannot be checked
202
229
}
203
230
204
231
if fun .Name != "append" {
205
- return nil , false // it's calling a function other of `append`. It cannot be checked
232
+ return nil , token . NoPos , false // it's calling a function other of `append`. It cannot be checked
206
233
}
207
234
208
235
case (* ast.AssignStmt ):
209
236
if len (typed .Rhs ) != len (typed .Lhs ) {
210
- return nil , false // dead logic
237
+ return nil , token . NoPos , false // dead logic
211
238
}
212
239
213
240
// search x where Rhs[x].Pos() == mayRHPos
@@ -223,19 +250,19 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
223
250
lh := typed .Lhs [index ]
224
251
isVar := s .isVar (loop , lh )
225
252
if ! isVar {
226
- return id , false
253
+ return id , insert , false
227
254
}
228
255
229
- return nil , true
256
+ return nil , token . NoPos , true
230
257
default :
231
258
// Other statement is not able to be checked.
232
- return nil , false
259
+ return nil , token . NoPos , false
233
260
}
234
261
235
262
// memory an expr that may be right-hand in the AssignStmt
236
263
mayRHPos = stack [i ].Pos ()
237
264
}
238
- return nil , true
265
+ return nil , token . NoPos , true
239
266
}
240
267
241
268
func (s * Searcher ) isVar (loop ast.Node , expr ast.Expr ) bool {
0 commit comments