diff options
Diffstat (limited to 'vendor/github.com/kyoh86/exportloopref')
5 files changed, 110 insertions, 38 deletions
diff --git a/vendor/github.com/kyoh86/exportloopref/.golangci.yml b/vendor/github.com/kyoh86/exportloopref/.golangci.yml index 58667b215..e876057f3 100644 --- a/vendor/github.com/kyoh86/exportloopref/.golangci.yml +++ b/vendor/github.com/kyoh86/exportloopref/.golangci.yml @@ -1,4 +1,4 @@ linters: enable: - unparam - - scopelint + - exportloopref diff --git a/vendor/github.com/kyoh86/exportloopref/README.md b/vendor/github.com/kyoh86/exportloopref/README.md index 5b1549159..5c019c738 100644 --- a/vendor/github.com/kyoh86/exportloopref/README.md +++ b/vendor/github.com/kyoh86/exportloopref/README.md @@ -2,13 +2,14 @@ An analyzer that finds exporting pointers for loop variables. +[](https://pkg.go.dev/kyoh86/exportloopref) [](https://goreportcard.com/report/github.com/kyoh86/exportloopref) [](https://codecov.io/gh/kyoh86/exportloopref) [](https://github.com/kyoh86/exportloopref/releases) ## What's this? -Sample problem code from: https://github.com/kyoh86/exportloopref/blob/master/testdata/simple/simple.go +Sample problem code from: https://github.com/kyoh86/exportloopref/blob/master/testdata/src/simple/simple.go ```go package main @@ -32,8 +33,8 @@ func main() { var vArray [4]*int var v *int if i%2 == 0 { - v = &p // not a diagnostic (x is inner variable) - vArray[1] = &p // not a diagnostic (x is inner variable) + v = &p // not a diagnostic (x is local variable) + vArray[1] = &p // not a diagnostic (x is local variable) vStr.x = &p } _ = v @@ -72,7 +73,7 @@ func main() { println("loop expecting 10, 11, 12, 13") for i, p := range []int{10, 11, 12, 13} { - p := p // FIX variable into the inner variable + p := p // FIX variable into the local variable printp(&p) intSlice = append(intSlice, &p) intArray[i] = &p @@ -108,12 +109,12 @@ func printp(p *int) { } ``` -ref: https://github.com/kyoh86/exportloopref/blob/master/testdata/fixed/fixed.go +ref: https://github.com/kyoh86/exportloopref/blob/master/testdata/src/fixed/fixed.go ## Sensing policy I want to make exportloopref as accurately as possible. -So some cases of lints will be ignored. +So some cases of lints will be false-negative. e.g. @@ -127,6 +128,48 @@ for _, p := []int{10, 11, 12, 13} { If you want to report all of lints (with some false-positives), you should use [looppointer](https://github.com/kyoh86/looppointer). +### Known false negatives + +Case 1: pass the pointer to function to export. + +Case 2: pass the pointer to local variable, and export it. + +```go +package main + +type List []*int + +func (l *List) AppendP(p *int) { + *l = append(*l, p) +} + +func main() { + var slice []*int + list := List{} + + println("loop expect exporting 10, 11, 12, 13") + for _, v := range []int{10, 11, 12, 13} { + list.AppendP(&v) // Case 1: wanted "exporting a pointer for the loop variable v", but cannot be found + + p := &v // p is the local variable + slice = append(slice, p) // Case 2: wanted "exporting a pointer for the loop variable v", but cannot be found + } + + println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) + for _, p := range slice { + printp(p) + } + println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) + for _, p := range ([]*int)(list) { + printp(p) + } +} + +func printp(p *int) { + println(*p) +} +``` + ## Install go: 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 { diff --git a/vendor/github.com/kyoh86/exportloopref/go.mod b/vendor/github.com/kyoh86/exportloopref/go.mod index 2b61b220b..34a53987a 100644 --- a/vendor/github.com/kyoh86/exportloopref/go.mod +++ b/vendor/github.com/kyoh86/exportloopref/go.mod @@ -2,4 +2,4 @@ module github.com/kyoh86/exportloopref go 1.14 -require golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed +require golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa diff --git a/vendor/github.com/kyoh86/exportloopref/go.sum b/vendor/github.com/kyoh86/exportloopref/go.sum index eb0e5ab1e..3b199f006 100644 --- a/vendor/github.com/kyoh86/exportloopref/go.sum +++ b/vendor/github.com/kyoh86/exportloopref/go.sum @@ -1,4 +1,4 @@ -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= @@ -12,8 +12,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed h1:OCZDlBlLYiUK6T33/8+3BnojrS2W+Dg1rKYJhR89xGE= -golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa h1:mMXQKlWCw9mIWgVLLfiycDZjMHMMYqiuakI4E/l2xcA= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= |
