@@ -40,14 +40,27 @@ func run(pass *analysis.Pass) (interface{}, error) {
4040 }
4141
4242 inspect .WithStack (nodeFilter , func (n ast.Node , push bool , stack []ast.Node ) bool {
43- id , digg := search .Check (n , stack )
43+ id , insert , digg := search .Check (n , stack )
4444 if id != nil && ! noLinter .IgnoreNode (id , "looppointer" ) {
45- msg := fmt .Sprintf ("taking a pointer for the loop variable %s" , id .Name )
45+ dMsg := fmt .Sprintf ("taking a pointer for the loop variable %s" , id .Name )
46+ fMsg := fmt .Sprintf ("loop variable %s should be pinned" , id .Name )
47+ var suggest []analysis.SuggestedFix
48+ if insert != token .NoPos {
49+ suggest = []analysis.SuggestedFix {{
50+ Message : fMsg ,
51+ TextEdits : []analysis.TextEdit {{
52+ Pos : insert ,
53+ End : insert ,
54+ NewText : []byte (fmt .Sprintf ("%[1]s := %[1]s\n " , id .Name )),
55+ }},
56+ }}
57+ }
4658 pass .Report (analysis.Diagnostic {
47- Pos : id .Pos (),
48- End : id .End (),
49- Message : msg ,
50- Category : "looppointer" ,
59+ Pos : id .Pos (),
60+ End : id .End (),
61+ Message : dMsg ,
62+ Category : "looppointer" ,
63+ SuggestedFixes : suggest ,
5164 })
5265 }
5366 return digg
@@ -61,7 +74,7 @@ type Searcher struct {
6174 Stats map [token.Pos ]struct {}
6275}
6376
64- func (s * Searcher ) Check (n ast.Node , stack []ast.Node ) (* ast.Ident , bool ) {
77+ func (s * Searcher ) Check (n ast.Node , stack []ast.Node ) (* ast.Ident , token. Pos , bool ) {
6578 switch typed := n .(type ) {
6679 case * ast.RangeStmt :
6780 s .parseRangeStmt (typed )
@@ -70,7 +83,7 @@ func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, bool) {
7083 case * ast.UnaryExpr :
7184 return s .checkUnaryExpr (typed , stack )
7285 }
73- return nil , true
86+ return nil , token . NoPos , true
7487}
7588
7689func (s * Searcher ) parseRangeStmt (n * ast.RangeStmt ) {
@@ -97,39 +110,48 @@ func (s *Searcher) addStat(expr ast.Expr) {
97110 }
98111}
99112
100- func (s * Searcher ) innermostLoop (stack []ast.Node ) ast.Node {
113+ func insertionPosition (block * ast.BlockStmt ) token.Pos {
114+ if len (block .List ) > 0 {
115+ return block .List [0 ].Pos ()
116+ }
117+ return token .NoPos
118+ }
119+
120+ func (s * Searcher ) innermostLoop (stack []ast.Node ) (ast.Node , token.Pos ) {
101121 for i := len (stack ) - 1 ; i >= 0 ; i -- {
102- switch stack [i ].(type ) {
103- case * ast.RangeStmt , * ast.ForStmt :
104- return stack [i ]
122+ switch typed := stack [i ].(type ) {
123+ case * ast.RangeStmt :
124+ return typed , insertionPosition (typed .Body )
125+ case * ast.ForStmt :
126+ return typed , insertionPosition (typed .Body )
105127 }
106128 }
107- return nil
129+ return nil , token . NoPos
108130}
109131
110- func (s * Searcher ) checkUnaryExpr (n * ast.UnaryExpr , stack []ast.Node ) (* ast.Ident , bool ) {
111- loop := s .innermostLoop (stack )
132+ func (s * Searcher ) checkUnaryExpr (n * ast.UnaryExpr , stack []ast.Node ) (* ast.Ident , token. Pos , bool ) {
133+ loop , insert := s .innermostLoop (stack )
112134 if loop == nil {
113- return nil , true
135+ return nil , token . NoPos , true
114136 }
115137
116138 if n .Op != token .AND {
117- return nil , true
139+ return nil , token . NoPos , true
118140 }
119141
120142 // Get identity of the referred item
121143 id := getIdentity (n .X )
122144 if id == nil {
123- return nil , true
145+ return nil , token . NoPos , true
124146 }
125147
126148 // If the identity is not the loop statement variable,
127149 // it will not be reported.
128150 if _ , isStat := s .Stats [id .Obj .Pos ()]; ! isStat {
129- return nil , true
151+ return nil , token . NoPos , true
130152 }
131153
132- return id , false
154+ return id , insert , false
133155}
134156
135157// Get variable identity
0 commit comments