@@ -16,7 +16,10 @@ import (
16
16
"golang.org/x/tools/go/analysis/passes/inspect"
17
17
"golang.org/x/tools/go/ast/inspector"
18
18
"golang.org/x/tools/go/types/typeutil"
19
+ "golang.org/x/tools/gopls/internal/util/moreiters"
19
20
"golang.org/x/tools/internal/analysisinternal"
21
+ "golang.org/x/tools/internal/astutil/cursor"
22
+ "golang.org/x/tools/internal/astutil/edge"
20
23
"golang.org/x/tools/internal/diff"
21
24
"golang.org/x/tools/internal/refactor/inline"
22
25
"golang.org/x/tools/internal/typesinternal"
@@ -51,6 +54,12 @@ func run(pass *analysis.Pass) (any, error) {
51
54
return content , nil
52
55
}
53
56
57
+ // Return the unique ast.File for a cursor.
58
+ currentFile := func (c cursor.Cursor ) * ast.File {
59
+ cf , _ := moreiters .First (c .Ancestors ((* ast .File )(nil )))
60
+ return cf .Node ().(* ast.File )
61
+ }
62
+
54
63
// Pass 1: find functions and constants annotated with an appropriate "//go:fix"
55
64
// comment (the syntax proposed by #32816),
56
65
// and export a fact for each one.
@@ -150,19 +159,8 @@ func run(pass *analysis.Pass) (any, error) {
150
159
// and forward each reference to a forwardable constant.
151
160
//
152
161
// TODO(adonovan): handle multiple diffs that each add the same import.
153
- nodeFilter = []ast.Node {
154
- (* ast .File )(nil ),
155
- (* ast .CallExpr )(nil ),
156
- (* ast .SelectorExpr )(nil ),
157
- (* ast .Ident )(nil ),
158
- }
159
- var currentFile * ast.File
160
- var currentSel * ast.SelectorExpr
161
- inspect .Preorder (nodeFilter , func (n ast.Node ) {
162
- if file , ok := n .(* ast.File ); ok {
163
- currentFile = file
164
- return
165
- }
162
+ for cur := range cursor .Root (inspect ).Preorder ((* ast .CallExpr )(nil ), (* ast .Ident )(nil )) {
163
+ n := cur .Node ()
166
164
switch n := n .(type ) {
167
165
case * ast.CallExpr :
168
166
call := n
@@ -177,27 +175,28 @@ func run(pass *analysis.Pass) (any, error) {
177
175
}
178
176
}
179
177
if callee == nil {
180
- return // nope
178
+ continue // nope
181
179
}
182
180
183
181
// Inline the call.
184
182
content , err := readFile (call )
185
183
if err != nil {
186
184
pass .Reportf (call .Lparen , "invalid inlining candidate: cannot read source file: %v" , err )
187
- return
185
+ continue
188
186
}
187
+ curFile := currentFile (cur )
189
188
caller := & inline.Caller {
190
189
Fset : pass .Fset ,
191
190
Types : pass .Pkg ,
192
191
Info : pass .TypesInfo ,
193
- File : currentFile ,
192
+ File : curFile ,
194
193
Call : call ,
195
194
Content : content ,
196
195
}
197
196
res , err := inline .Inline (caller , callee , & inline.Options {Logf : discard })
198
197
if err != nil {
199
198
pass .Reportf (call .Lparen , "%v" , err )
200
- return
199
+ continue
201
200
}
202
201
if res .Literalized {
203
202
// Users are not fond of inlinings that literalize
@@ -207,16 +206,16 @@ func run(pass *analysis.Pass) (any, error) {
207
206
// and often literalizes when it cannot prove that
208
207
// reducing the call is safe; the user of this tool
209
208
// has no indication of what the problem is.)
210
- return
209
+ continue
211
210
}
212
211
got := res .Content
213
212
214
213
// Suggest the "fix".
215
214
var textEdits []analysis.TextEdit
216
215
for _ , edit := range diff .Bytes (content , got ) {
217
216
textEdits = append (textEdits , analysis.TextEdit {
218
- Pos : currentFile .FileStart + token .Pos (edit .Start ),
219
- End : currentFile .FileStart + token .Pos (edit .End ),
217
+ Pos : curFile .FileStart + token .Pos (edit .Start ),
218
+ End : curFile .FileStart + token .Pos (edit .End ),
220
219
NewText : []byte (edit .New ),
221
220
})
222
221
}
@@ -231,9 +230,6 @@ func run(pass *analysis.Pass) (any, error) {
231
230
})
232
231
}
233
232
234
- case * ast.SelectorExpr :
235
- currentSel = n
236
-
237
233
case * ast.Ident :
238
234
// If the identifier is a use of a forwardable constant, suggest forwarding it.
239
235
if con , ok := pass .TypesInfo .Uses [n ].(* types.Const ); ok {
@@ -246,15 +242,15 @@ func run(pass *analysis.Pass) (any, error) {
246
242
}
247
243
}
248
244
if fcon == nil {
249
- return // nope
245
+ continue // nope
250
246
}
251
247
252
248
// If n is qualified by a package identifier, we'll need the full selector expression.
253
249
var sel * ast.SelectorExpr
254
- if currentSel != nil && n == currentSel .Sel {
255
- sel = currentSel
256
- currentSel = nil
250
+ if e , _ := cur .Edge (); e == edge .SelectorExpr_Sel {
251
+ sel = cur .Parent ().Node ().(* ast.SelectorExpr )
257
252
}
253
+ curFile := currentFile (cur )
258
254
259
255
// We have an identifier A here (n), possibly qualified by a package identifier (sel.X),
260
256
// and a forwardable "const A = B" elsewhere (fcon).
@@ -267,16 +263,16 @@ func run(pass *analysis.Pass) (any, error) {
267
263
// are in the current package.
268
264
if pass .Pkg .Path () == fcon .RHSPkgPath {
269
265
// fcon.rhsObj is the object referred to by B in the definition of A.
270
- scope := pass .TypesInfo .Scopes [currentFile ].Innermost (n .Pos ()) // n's scope
271
- _ , obj := scope .LookupParent (fcon .RHSName , n .Pos ()) // what "B" means in n's scope
266
+ scope := pass .TypesInfo .Scopes [curFile ].Innermost (n .Pos ()) // n's scope
267
+ _ , obj := scope .LookupParent (fcon .RHSName , n .Pos ()) // what "B" means in n's scope
272
268
if obj == nil {
273
269
// Should be impossible: if code at n can refer to the LHS,
274
270
// it can refer to the RHS.
275
271
panic (fmt .Sprintf ("no object for forwardable const %s RHS %s" , n .Name , fcon .RHSName ))
276
272
}
277
273
if obj != fcon .rhsObj {
278
274
// "B" means something different here than at the forwardable const's scope.
279
- return
275
+ continue
280
276
}
281
277
}
282
278
importPrefix := ""
@@ -285,7 +281,7 @@ func run(pass *analysis.Pass) (any, error) {
285
281
// TODO(jba): fix AddImport so that it returns "." if an existing dot import will work.
286
282
// We will need to tell AddImport the name of the identifier we want to qualify (fcon.RHSName here).
287
283
importID , eds := analysisinternal .AddImport (
288
- pass .TypesInfo , currentFile , n .Pos (), fcon .RHSPkgPath , fcon .RHSPkgName )
284
+ pass .TypesInfo , curFile , n .Pos (), fcon .RHSPkgPath , fcon .RHSPkgName )
289
285
importPrefix = importID + "."
290
286
edits = eds
291
287
}
@@ -316,7 +312,7 @@ func run(pass *analysis.Pass) (any, error) {
316
312
})
317
313
}
318
314
}
319
- })
315
+ }
320
316
321
317
return nil , nil
322
318
}
0 commit comments