Skip to content
This repository was archived by the owner on Dec 26, 2025. It is now read-only.

Commit 1850976

Browse files
committed
Suggest fixes
1 parent a98c48b commit 1850976

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

looppointer.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7689
func (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

Comments
 (0)