aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/kyoh86/exportloopref/exportloopref.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-02-22 20:37:25 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-02-22 21:02:12 +0100
commitfcc6d71be2c3ce7d9305c04fc2e87af554571bac (patch)
treeb01dbb3d1e2988e28ea158d2d543d603ec0b9569 /vendor/github.com/kyoh86/exportloopref/exportloopref.go
parent8f23c528ad5a943b9ffec5dcaf332fd0f614006e (diff)
go.mod: update golangci-lint to v1.37
Diffstat (limited to 'vendor/github.com/kyoh86/exportloopref/exportloopref.go')
-rw-r--r--vendor/github.com/kyoh86/exportloopref/exportloopref.go83
1 files changed, 56 insertions, 27 deletions
diff --git a/vendor/github.com/kyoh86/exportloopref/exportloopref.go b/vendor/github.com/kyoh86/exportloopref/exportloopref.go
index 0b310b3c9..4d1671a06 100644
--- a/vendor/github.com/kyoh86/exportloopref/exportloopref.go
+++ b/vendor/github.com/kyoh86/exportloopref/exportloopref.go
@@ -1,6 +1,7 @@
package exportloopref
import (
+ "fmt"
"go/ast"
"go/token"
"go/types"
@@ -42,9 +43,28 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool {
- id, digg := search.Check(n, stack)
+ id, insert, digg := search.Check(n, stack)
if id != nil {
- pass.ReportRangef(id, "exporting a pointer for the loop variable %s", id.Name)
+ dMsg := fmt.Sprintf("exporting a pointer for the loop variable %s", id.Name)
+ fMsg := fmt.Sprintf("loop variable %s should be pinned", id.Name)
+ var suggest []analysis.SuggestedFix
+ if insert != token.NoPos {
+ suggest = []analysis.SuggestedFix{{
+ Message: fMsg,
+ TextEdits: []analysis.TextEdit{{
+ Pos: insert,
+ End: insert,
+ NewText: []byte(fmt.Sprintf("%[1]s := %[1]s\n", id.Name)),
+ }},
+ }}
+ }
+ d := analysis.Diagnostic{Pos: id.Pos(),
+ End: id.End(),
+ Message: dMsg,
+ Category: "exportloopref",
+ SuggestedFixes: suggest,
+ }
+ pass.Report(d)
}
return digg
})
@@ -59,13 +79,13 @@ type Searcher struct {
// - var <X> int
// - D := ...
Stats map[token.Pos]struct{}
- // Internal variables maps loop-position, decl-location to ignore
+ // Local variables maps loop-position, decl-location to ignore
// safe pointers for variable which declared in the loop.
Vars map[token.Pos]map[token.Pos]struct{}
Types map[ast.Expr]types.TypeAndValue
}
-func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, bool) {
+func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, token.Pos, bool) {
switch typed := n.(type) {
case *ast.RangeStmt:
s.parseRangeStmt(typed)
@@ -79,7 +99,7 @@ func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, bool) {
case *ast.UnaryExpr:
return s.checkUnaryExpr(typed, stack)
}
- return nil, true
+ return nil, token.NoPos, true
}
func (s *Searcher) parseRangeStmt(n *ast.RangeStmt) {
@@ -107,7 +127,7 @@ func (s *Searcher) addStat(expr ast.Expr) {
}
func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) {
- loop := s.innermostLoop(stack)
+ loop, _ := s.innermostLoop(stack)
if loop == nil {
return
}
@@ -123,12 +143,12 @@ func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) {
}
func (s *Searcher) parseAssignStmt(n *ast.AssignStmt, stack []ast.Node) {
- loop := s.innermostLoop(stack)
+ loop, _ := s.innermostLoop(stack)
if loop == nil {
return
}
- // Find statements declaring internal variable
+ // Find statements declaring local variable
if n.Tok == token.DEFINE {
for _, h := range n.Lhs {
s.addVar(loop, h)
@@ -150,36 +170,45 @@ func (s *Searcher) addVar(loop ast.Node, expr ast.Expr) {
s.Vars[loopPos] = vars
}
-func (s *Searcher) innermostLoop(stack []ast.Node) ast.Node {
+func insertionPosition(block *ast.BlockStmt) token.Pos {
+ if len(block.List) > 0 {
+ return block.List[0].Pos()
+ }
+ return token.NoPos
+}
+
+func (s *Searcher) innermostLoop(stack []ast.Node) (ast.Node, token.Pos) {
for i := len(stack) - 1; i >= 0; i-- {
- switch stack[i].(type) {
- case *ast.RangeStmt, *ast.ForStmt:
- return stack[i]
+ switch typed := stack[i].(type) {
+ case *ast.RangeStmt:
+ return typed, insertionPosition(typed.Body)
+ case *ast.ForStmt:
+ return typed, insertionPosition(typed.Body)
}
}
- return nil
+ return nil, token.NoPos
}
-func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Ident, bool) {
- loop := s.innermostLoop(stack)
+func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Ident, token.Pos, bool) {
+ loop, insert := s.innermostLoop(stack)
if loop == nil {
- return nil, true
+ return nil, token.NoPos, true
}
if n.Op != token.AND {
- return nil, true
+ return nil, token.NoPos, true
}
// Get identity of the referred item
id := s.getIdentity(n.X)
if id == nil {
- return nil, true
+ return nil, token.NoPos, true
}
// If the identity is not the loop statement variable,
// it will not be reported.
if _, isStat := s.Stats[id.Obj.Pos()]; !isStat {
- return nil, true
+ return nil, token.NoPos, true
}
// check stack append(), []X{}, map[Type]X{}, Struct{}, &Struct{}, X.(Type), (X)
@@ -196,16 +225,16 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
case (*ast.CallExpr):
fun, ok := typed.Fun.(*ast.Ident)
if !ok {
- return nil, false // it's calling a function other of `append`. It cannot be checked
+ return nil, token.NoPos, false // it's calling a function other of `append`. It cannot be checked
}
if fun.Name != "append" {
- return nil, false // it's calling a function other of `append`. It cannot be checked
+ return nil, token.NoPos, false // it's calling a function other of `append`. It cannot be checked
}
case (*ast.AssignStmt):
if len(typed.Rhs) != len(typed.Lhs) {
- return nil, false // dead logic
+ return nil, token.NoPos, false // dead logic
}
// search x where Rhs[x].Pos() == mayRHPos
@@ -217,23 +246,23 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden
}
}
- // check Lhs[x] is not inner variable
+ // check Lhs[x] is not local variable
lh := typed.Lhs[index]
isVar := s.isVar(loop, lh)
if !isVar {
- return id, false
+ return id, insert, false
}
- return nil, true
+ return nil, token.NoPos, true
default:
// Other statement is not able to be checked.
- return nil, false
+ return nil, token.NoPos, false
}
// memory an expr that may be right-hand in the AssignStmt
mayRHPos = stack[i].Pos()
}
- return nil, true
+ return nil, token.NoPos, true
}
func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool {