@@ -3,6 +3,7 @@ package exportloopref
3
3
import (
4
4
"go/ast"
5
5
"go/token"
6
+ "go/types"
6
7
7
8
"golang.org/x/tools/go/analysis"
8
9
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -29,6 +30,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
29
30
search := & Searcher {
30
31
Stats : map [token.Pos ]struct {}{},
31
32
Vars : map [token.Pos ]map [token.Pos ]struct {}{},
33
+ Types : pass .TypesInfo .Types ,
32
34
}
33
35
34
36
nodeFilter := []ast.Node {
@@ -51,10 +53,16 @@ func run(pass *analysis.Pass) (interface{}, error) {
51
53
}
52
54
53
55
type 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 := ...
55
61
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
58
66
}
59
67
60
68
func (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) {
67
75
s .parseDeclStmt (typed , stack )
68
76
case * ast.AssignStmt :
69
77
s .parseAssignStmt (typed , stack )
78
+
70
79
case * ast.UnaryExpr :
71
80
return s .checkUnaryExpr (typed , stack )
72
81
}
@@ -162,7 +171,7 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
162
171
}
163
172
164
173
// Get identity of the referred item
165
- id := getIdentity (n .X )
174
+ id := s . getIdentity (n .X )
166
175
if id == nil {
167
176
return nil , true
168
177
}
@@ -245,20 +254,27 @@ func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool {
245
254
}
246
255
247
256
// Get variable identity
248
- func getIdentity (expr ast.Expr ) * ast.Ident {
257
+ func ( s * Searcher ) getIdentity (expr ast.Expr ) * ast.Ident {
249
258
switch typed := expr .(type ) {
250
259
case * ast.SelectorExpr :
251
260
// Get parent identity; i.e. `a` of the `a.b`.
252
261
parent , ok := typed .X .(* ast.Ident )
253
262
if ! ok {
254
263
return nil
255
264
}
265
+
256
266
// parent is a package name identity
257
267
if parent .Obj == nil {
258
268
return nil
259
269
}
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
+
260
276
// 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` .
262
278
return parent
263
279
264
280
case * ast.Ident :
0 commit comments