@@ -3,6 +3,7 @@ package exportloopref
33import (
44 "go/ast"
55 "go/token"
6+ "go/types"
67
78 "golang.org/x/tools/go/analysis"
89 "golang.org/x/tools/go/analysis/passes/inspect"
@@ -29,6 +30,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
2930 search := & Searcher {
3031 Stats : map [token.Pos ]struct {}{},
3132 Vars : map [token.Pos ]map [token.Pos ]struct {}{},
33+ Types : pass .TypesInfo .Types ,
3234 }
3335
3436 nodeFilter := []ast.Node {
@@ -51,10 +53,16 @@ func run(pass *analysis.Pass) (interface{}, error) {
5153}
5254
5355type Searcher struct {
54- // statement variables
56+ // Statement variables : map to collect positions that
57+ // variables are declared like below.
58+ // - for <KEY>, <VALUE> := range ...
59+ // - var <X> int
60+ // - D := ...
5561 Stats map [token.Pos ]struct {}
56- // internal variables
57- Vars map [token.Pos ]map [token.Pos ]struct {}
62+ // Internal variables maps loop-position, decl-location to ignore
63+ // safe pointers for variable which declared in the loop.
64+ Vars map [token.Pos ]map [token.Pos ]struct {}
65+ Types map [ast.Expr ]types.TypeAndValue
5866}
5967
6068func (s * Searcher ) Check (n ast.Node , stack []ast.Node ) (* ast.Ident , bool ) {
@@ -67,6 +75,7 @@ func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, bool) {
6775 s .parseDeclStmt (typed , stack )
6876 case * ast.AssignStmt :
6977 s .parseAssignStmt (typed , stack )
78+
7079 case * ast.UnaryExpr :
7180 return s .checkUnaryExpr (typed , stack )
7281 }
@@ -162,7 +171,7 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
162171 }
163172
164173 // Get identity of the referred item
165- id := getIdentity (n .X )
174+ id := s . getIdentity (n .X )
166175 if id == nil {
167176 return nil , true
168177 }
@@ -245,20 +254,27 @@ func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool {
245254}
246255
247256// Get variable identity
248- func getIdentity (expr ast.Expr ) * ast.Ident {
257+ func ( s * Searcher ) getIdentity (expr ast.Expr ) * ast.Ident {
249258 switch typed := expr .(type ) {
250259 case * ast.SelectorExpr :
251260 // Get parent identity; i.e. `a` of the `a.b`.
252261 parent , ok := typed .X .(* ast.Ident )
253262 if ! ok {
254263 return nil
255264 }
265+
256266 // parent is a package name identity
257267 if parent .Obj == nil {
258268 return nil
259269 }
270+
271+ // Ignore if the parent is pointer ref (fix for #2)
272+ if _ , ok := s .Types [parent ].Type .(* types.Pointer ); ok {
273+ return nil
274+ }
275+
260276 // NOTE: If that is descendants member like `a.b.c`,
261- // typed.X will be `*ast.SelectorExpr`.
277+ // typed.X will be `*ast.SelectorExpr` `a.b` .
262278 return parent
263279
264280 case * ast.Ident :
0 commit comments