@@ -16,6 +16,7 @@ import (
1616 "golang.org/x/tools/go/analysis/passes/inspect"
1717 "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1818 "golang.org/x/tools/go/ast/inspector"
19+ "golang.org/x/tools/internal/typesinternal"
1920)
2021
2122// NOTE: Experimental. Not part of the vet suite.
@@ -113,7 +114,7 @@ func (s span) contains(pos token.Pos) bool {
113114
114115// growSpan expands the span for the object to contain the source range [pos, end).
115116func growSpan (spans map [types.Object ]span , obj types.Object , pos , end token.Pos ) {
116- if strict {
117+ if strict || typesinternal . IsPackageLevel ( obj ) || isPkgName ( obj ) {
117118 return // No need
118119 }
119120 s , ok := spans [obj ]
@@ -245,46 +246,43 @@ func checkShadowing(pass *analysis.Pass, spans map[types.Object]span, ident *ast
245246 if shadowed .Parent () == types .Universe {
246247 return
247248 }
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 ()) {
264254 return
265255 }
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+ }
269264 }
270265 }
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 ))
289271 }
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
290288}
0 commit comments