@@ -42,6 +42,8 @@ func run(pass *analysis.Pass) (any, error) {
4242	inspect  :=  pass .ResultOf [inspect .Analyzer ].(* inspector.Inspector )
4343
4444	spans  :=  make (map [types.Object ]span )
45+ 	usedPkgVars  :=  make (map [types.Object ]struct {})
46+ 
4547	for  id , obj  :=  range  pass .TypesInfo .Defs  {
4648		// Ignore identifiers that don't denote objects 
4749		// (package names, symbolic variables such as t 
@@ -52,6 +54,10 @@ func run(pass *analysis.Pass) (any, error) {
5254	}
5355	for  id , obj  :=  range  pass .TypesInfo .Uses  {
5456		growSpan (spans , obj , id .Pos (), id .End ())
57+ 		// Track usage for package-level variables. 
58+ 		if  obj .Parent () ==  obj .Pkg ().Scope () {
59+ 			usedPkgVars [obj ] =  struct {}{}
60+ 		}
5561	}
5662	for  node , obj  :=  range  pass .TypesInfo .Implicits  {
5763		// A type switch with a short variable declaration 
@@ -74,9 +80,9 @@ func run(pass *analysis.Pass) (any, error) {
7480	inspect .Preorder (nodeFilter , func (n  ast.Node ) {
7581		switch  n  :=  n .(type ) {
7682		case  * ast.AssignStmt :
77- 			checkShadowAssignment (pass , spans , n )
83+ 			checkShadowAssignment (pass , spans , usedPkgVars ,  n )
7884		case  * ast.GenDecl :
79- 			checkShadowDecl (pass , spans , n )
85+ 			checkShadowDecl (pass , spans , usedPkgVars ,  n )
8086		}
8187	})
8288	return  nil , nil 
@@ -131,7 +137,7 @@ func growSpan(spans map[types.Object]span, obj types.Object, pos, end token.Pos)
131137}
132138
133139// checkShadowAssignment checks for shadowing in a short variable declaration. 
134- func  checkShadowAssignment (pass  * analysis.Pass , spans  map [types.Object ]span , a  * ast.AssignStmt ) {
140+ func  checkShadowAssignment (pass  * analysis.Pass , spans  map [types.Object ]span , usedPkgVars   map [types. Object ] struct {},  a  * ast.AssignStmt ) {
135141	if  a .Tok  !=  token .DEFINE  {
136142		return 
137143	}
@@ -144,7 +150,7 @@ func checkShadowAssignment(pass *analysis.Pass, spans map[types.Object]span, a *
144150			pass .ReportRangef (expr , "invalid AST: short variable declaration of non-identifier" )
145151			return 
146152		}
147- 		checkShadowing (pass , spans , ident )
153+ 		checkShadowing (pass , spans , usedPkgVars ,  ident )
148154	}
149155}
150156
@@ -204,7 +210,7 @@ func idiomaticRedecl(d *ast.ValueSpec) bool {
204210}
205211
206212// checkShadowDecl checks for shadowing in a general variable declaration. 
207- func  checkShadowDecl (pass  * analysis.Pass , spans  map [types.Object ]span , d  * ast.GenDecl ) {
213+ func  checkShadowDecl (pass  * analysis.Pass , spans  map [types.Object ]span , usedPkgVars   map [types. Object ] struct {},  d  * ast.GenDecl ) {
208214	if  d .Tok  !=  token .VAR  {
209215		return 
210216	}
@@ -220,13 +226,13 @@ func checkShadowDecl(pass *analysis.Pass, spans map[types.Object]span, d *ast.Ge
220226			return 
221227		}
222228		for  _ , ident  :=  range  valueSpec .Names  {
223- 			checkShadowing (pass , spans , ident )
229+ 			checkShadowing (pass , spans , usedPkgVars ,  ident )
224230		}
225231	}
226232}
227233
228234// checkShadowing checks whether the identifier shadows an identifier in an outer scope. 
229- func  checkShadowing (pass  * analysis.Pass , spans  map [types.Object ]span , ident  * ast.Ident ) {
235+ func  checkShadowing (pass  * analysis.Pass , spans  map [types.Object ]span , usedPkgVars   map [types. Object ] struct {},  ident  * ast.Ident ) {
230236	if  ident .Name  ==  "_"  {
231237		// Can't shadow the blank identifier. 
232238		return 
@@ -249,23 +255,31 @@ func checkShadowing(pass *analysis.Pass, spans map[types.Object]span, ident *ast
249255	shadowedPos  :=  pass .Fset .Position (shadowed .Pos ())
250256	identPos  :=  pass .Fset .Position (ident .Pos ())
251257
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 
258+ 	// Check if the shadowed variable is at package level. 
259+ 	if  shadowed .Parent () ==  shadowed .Pkg ().Scope () {
260+ 		if  ! strict  {
261+ 			// Don't complain if the package variable is unused. 
262+ 			if  _ , ok  :=  usedPkgVars [shadowed ]; ! ok  {
263+ 				return 
264+ 			}
256265		}
257266	} 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 )
264- 			return 
265- 		}
266- 
267- 		if  shadowedPos .Filename  ==  identPos .Filename  &&  ! span .contains (ident .Pos ()) {
268- 			return 
267+ 		if  strict  {
268+ 			// The shadowed identifier must appear before this one to be an instance of shadowing. 
269+ 			if  shadowed .Pos () >  ident .Pos () {
270+ 				return 
271+ 			}
272+ 		} else  {
273+ 			// Don't complain if the span of validity of the shadowed identifier doesn't include 
274+ 			// the shadowing identifier. 
275+ 			span , ok  :=  spans [shadowed ]
276+ 			if  ! ok  {
277+ 				pass .ReportRangef (ident , "internal error: no range for %q" , ident .Name )
278+ 				return 
279+ 			}
280+ 			if  ! span .contains (ident .Pos ()) {
281+ 				return 
282+ 			}
269283		}
270284	}
271285	// Don't complain if the types differ: that implies the programmer really wants two different things. 
0 commit comments