@@ -16,6 +16,7 @@ import (
16
16
"golang.org/x/tools/go/analysis/passes/inspect"
17
17
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
18
18
"golang.org/x/tools/go/ast/inspector"
19
+ "golang.org/x/tools/internal/typesinternal"
19
20
)
20
21
21
22
// NOTE: Experimental. Not part of the vet suite.
@@ -113,7 +114,7 @@ func (s span) contains(pos token.Pos) bool {
113
114
114
115
// growSpan expands the span for the object to contain the source range [pos, end).
115
116
func growSpan (spans map [types.Object ]span , obj types.Object , pos , end token.Pos ) {
116
- if strict {
117
+ if strict || typesinternal . IsPackageLevel ( obj ) || isPkgName ( obj ) {
117
118
return // No need
118
119
}
119
120
s , ok := spans [obj ]
@@ -245,46 +246,43 @@ func checkShadowing(pass *analysis.Pass, spans map[types.Object]span, ident *ast
245
246
if shadowed .Parent () == types .Universe {
246
247
return
247
248
}
248
-
249
- shadowedPos := pass .Fset .Position (shadowed .Pos ())
250
- identPos := pass .Fset .Position (ident .Pos ())
251
-
252
- if strict {
253
- // The shadowed identifier must appear before this one to be an instance of shadowing.
254
- if shadowed .Pos () > ident .Pos () {
255
- return
256
- }
257
- } else {
258
- // Don't complain if the span of validity of the shadowed identifier doesn't include
259
- // the shadowing identifier, except for cross-file shadowing where file processing
260
- // order affects span checks.
261
- span , ok := spans [shadowed ]
262
- if ! ok {
263
- pass .ReportRangef (ident , "internal error: no range for %q" , ident .Name )
249
+ // Package names (imports) don't have a type and are always in scope in the file,
250
+ // so they are always reported when shadowed.
251
+ if ! isPkgName (shadowed ) {
252
+ // Don't complain if the types differ: that implies the programmer really wants two different things.
253
+ if ! types .Identical (obj .Type (), shadowed .Type ()) {
264
254
return
265
255
}
266
-
267
- if shadowedPos .Filename == identPos .Filename && ! span .contains (ident .Pos ()) {
268
- return
256
+ // Package-level variables are always in scope, so they're always reported when shadowed.
257
+ if ! strict && ! typesinternal .IsPackageLevel (shadowed ) {
258
+ // Don't complain if the span of validity of the shadowed identifier doesn't include
259
+ // the shadowing identifier.
260
+ span , ok := spans [shadowed ]
261
+ if ! ok || ! span .contains (ident .Pos ()) {
262
+ return
263
+ }
269
264
}
270
265
}
271
- // Don't complain if the types differ: that implies the programmer really wants two different things.
272
- if types .Identical (obj .Type (), shadowed .Type ()) {
273
- // Build the message, adding filename only if in a different file
274
- message := fmt .Sprintf ("declaration of %q shadows declaration at line %d" , obj .Name (), shadowedPos .Line )
275
- if shadowedPos .Filename != identPos .Filename {
276
- message += fmt .Sprintf (" in %s" , filepath .Base (shadowedPos .Filename ))
277
- }
278
-
279
- pass .Report (analysis.Diagnostic {
280
- Pos : ident .Pos (),
281
- End : ident .End (),
282
- Message : message ,
283
- Related : []analysis.RelatedInformation {{
284
- Pos : shadowed .Pos (),
285
- End : shadowed .Pos () + token .Pos (len (shadowed .Name ())),
286
- Message : fmt .Sprintf ("shadowed symbol %q declared here" , obj .Name ()),
287
- }},
288
- })
266
+ shadowedPos := pass .Fset .Position (shadowed .Pos ())
267
+ message := fmt .Sprintf ("declaration of %q shadows declaration at line %d" , obj .Name (), shadowedPos .Line )
268
+ currentFile := pass .Fset .Position (ident .Pos ()).Filename
269
+ if shadowedPos .Filename != currentFile {
270
+ message += fmt .Sprintf (" in %s" , filepath .Base (shadowedPos .Filename ))
289
271
}
272
+ pass .Report (analysis.Diagnostic {
273
+ Pos : ident .Pos (),
274
+ End : ident .End (),
275
+ Message : message ,
276
+ Related : []analysis.RelatedInformation {{
277
+ Pos : shadowed .Pos (),
278
+ End : shadowed .Pos () + token .Pos (len (shadowed .Name ())),
279
+ Message : fmt .Sprintf ("shadowed symbol %q declared here" , obj .Name ()),
280
+ }},
281
+ })
282
+ }
283
+
284
+ // isPkgName reports whether obj is a package name (import).
285
+ func isPkgName (obj types.Object ) bool {
286
+ _ , ok := obj .(* types.PkgName )
287
+ return ok
290
288
}
0 commit comments