diff options
Diffstat (limited to 'vendor/github.com/kyoh86/exportloopref')
| -rw-r--r-- | vendor/github.com/kyoh86/exportloopref/.goreleaser.yml | 88 | ||||
| -rw-r--r-- | vendor/github.com/kyoh86/exportloopref/README.md | 8 | ||||
| -rw-r--r-- | vendor/github.com/kyoh86/exportloopref/exportloopref.go | 169 | ||||
| -rw-r--r-- | vendor/github.com/kyoh86/exportloopref/go.mod | 5 | ||||
| -rw-r--r-- | vendor/github.com/kyoh86/exportloopref/go.sum | 20 |
5 files changed, 152 insertions, 138 deletions
diff --git a/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml b/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml index 22ff44040..95d44aaac 100644 --- a/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml +++ b/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml @@ -1,43 +1,51 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json + project_name: exportloopref -release: - github: - owner: kyoh86 - name: exportloopref -brews: -- install: | - bin.install "exportloopref" - github: - owner: kyoh86 - name: homebrew-tap - folder: Formula - homepage: https://github.com/kyoh86/exportloopref - description: An analyzer that finds exporting pointers for loop variables. builds: -- goos: - - linux - - darwin - - windows - goarch: - - amd64 - - "386" - main: ./cmd/exportloopref - ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} - binary: exportloopref + - id: default + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + - "386" + main: ./cmd/exportloopref + binary: exportloopref +brews: + - install: | + bin.install "exportloopref" + tap: + owner: kyoh86 + name: homebrew-tap + folder: Formula + homepage: https://github.com/kyoh86/exportloopref + description: An analyzer that finds exporting pointers for loop variables. + license: MIT +nfpms: + - builds: + - default + maintainer: kyoh86 <me@kyoh86.dev> + homepage: https://github.com/kyoh86/exportloopref + description: An analyzer that finds exporting pointers for loop variables. + license: MIT + formats: + - apk + - deb + - rpm archives: -- id: gzip - format: tar.gz - format_overrides: - - goos: windows - format: zip - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" - files: - - licence* - - LICENCE* - - license* - - LICENSE* - - readme* - - README* - - changelog* - - CHANGELOG* -snapshot: - name_template: SNAPSHOT-{{ .Commit }} + - id: gzip + format: tar.gz + format_overrides: + - goos: windows + format: zip + files: + - licence* + - LICENCE* + - license* + - LICENSE* + - readme* + - README* + - changelog* + - CHANGELOG* diff --git a/vendor/github.com/kyoh86/exportloopref/README.md b/vendor/github.com/kyoh86/exportloopref/README.md index 5c019c738..0f581ffce 100644 --- a/vendor/github.com/kyoh86/exportloopref/README.md +++ b/vendor/github.com/kyoh86/exportloopref/README.md @@ -1,6 +1,8 @@ # exportloopref An analyzer that finds exporting pointers for loop variables. + +Pin them all! [](https://pkg.go.dev/kyoh86/exportloopref) [](https://goreportcard.com/report/github.com/kyoh86/exportloopref) @@ -9,7 +11,7 @@ An analyzer that finds exporting pointers for loop variables. ## What's this? -Sample problem code from: https://github.com/kyoh86/exportloopref/blob/master/testdata/src/simple/simple.go +Sample problem code from: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/simple/simple.go ```go package main @@ -109,7 +111,7 @@ func printp(p *int) { } ``` -ref: https://github.com/kyoh86/exportloopref/blob/master/testdata/src/fixed/fixed.go +ref: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/fixed/fixed.go ## Sensing policy @@ -120,7 +122,7 @@ e.g. ```go var s Foo -for _, p := []int{10, 11, 12, 13} { +for _, p := range []int{10, 11, 12, 13} { s.Bar(&p) // If s stores the pointer, it will be bug. } ``` diff --git a/vendor/github.com/kyoh86/exportloopref/exportloopref.go b/vendor/github.com/kyoh86/exportloopref/exportloopref.go index 4d1671a06..d071d5c35 100644 --- a/vendor/github.com/kyoh86/exportloopref/exportloopref.go +++ b/vendor/github.com/kyoh86/exportloopref/exportloopref.go @@ -17,21 +17,15 @@ var Analyzer = &analysis.Analyzer{ Run: run, RunDespiteErrors: true, Requires: []*analysis.Analyzer{inspect.Analyzer}, - // ResultType reflect.Type - // FactTypes []Fact -} - -func init() { - // Analyzer.Flags.StringVar(&v, "name", "default", "description") } func run(pass *analysis.Pass) (interface{}, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) search := &Searcher{ - Stats: map[token.Pos]struct{}{}, - Vars: map[token.Pos]map[token.Pos]struct{}{}, - Types: pass.TypesInfo.Types, + LoopVars: map[token.Pos]struct{}{}, + LocalVars: map[token.Pos]map[token.Pos]struct{}{}, + Pass: pass, } nodeFilter := []ast.Node{ @@ -42,50 +36,60 @@ func run(pass *analysis.Pass) (interface{}, error) { (*ast.UnaryExpr)(nil), } - inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool { - id, insert, digg := search.Check(n, stack) - if id != nil { - 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 - }) + inspect.WithStack(nodeFilter, search.CheckAndReport) return nil, nil } type Searcher struct { - // Statement variables : map to collect positions that - // variables are declared like below. + // LoopVars is positions that loop-variables are declared like below. // - for <KEY>, <VALUE> := range ... - // - var <X> int - // - D := ... - Stats map[token.Pos]struct{} - // 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 + // - for <VALUE> := <INIT>; <CONDITION>; <INCREMENT> + LoopVars map[token.Pos]struct{} + // LocalVars is positions of loops and the variables declared in them. + // Use this to determine if a point assignment is an export outside the loop. + LocalVars map[token.Pos]map[token.Pos]struct{} + + Pass *analysis.Pass +} + +// CheckAndReport inspects each node with stack. +// It is implemented as the I/F of the "golang.org/x/tools/go/analysis/passes/inspect".Analysis.WithStack. +func (s *Searcher) CheckAndReport(n ast.Node, push bool, stack []ast.Node) bool { + id, insert, digg := s.Check(n, stack) + if id == nil { + // no prob. + return digg + } + + // suggests fix + var suggest []analysis.SuggestedFix + if insert != token.NoPos { + suggest = []analysis.SuggestedFix{{ + Message: fmt.Sprintf("loop variable %s should be pinned", id.Name), + TextEdits: []analysis.TextEdit{{ + Pos: insert, + End: insert, + NewText: []byte(fmt.Sprintf("%[1]s := %[1]s\n", id.Name)), + }}, + }} + } + + // report a diagnostic + d := analysis.Diagnostic{Pos: id.Pos(), + End: id.End(), + Message: fmt.Sprintf("exporting a pointer for the loop variable %s", id.Name), + Category: "exportloopref", + SuggestedFixes: suggest, + } + s.Pass.Report(d) + return digg } -func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, token.Pos, bool) { +// Check each node and stack, whether it exports loop variables or not. +// Finding export, report the *ast.Ident of exported loop variable, +// and token.Pos to insert assignment to fix the diagnostic. +func (s *Searcher) Check(n ast.Node, stack []ast.Node) (loopVar *ast.Ident, insertPos token.Pos, digg bool) { switch typed := n.(type) { case *ast.RangeStmt: s.parseRangeStmt(typed) @@ -102,72 +106,92 @@ func (s *Searcher) Check(n ast.Node, stack []ast.Node) (*ast.Ident, token.Pos, b return nil, token.NoPos, true } +// parseRangeStmt will check range statement (i.e. `for <KEY>, <VALUE> := range ...`), +// and collect positions of <KEY> and <VALUE>. func (s *Searcher) parseRangeStmt(n *ast.RangeStmt) { - s.addStat(n.Key) - s.addStat(n.Value) + s.storeLoopVars(n.Key) + s.storeLoopVars(n.Value) } +// parseForStmt will check for statement (i.e. `for <VALUE> := <INIT>; <CONDITION>; <INCREMENT>`), +// and collect positions of <VALUE>. func (s *Searcher) parseForStmt(n *ast.ForStmt) { switch post := n.Post.(type) { case *ast.AssignStmt: // e.g. for p = head; p != nil; p = p.next for _, lhs := range post.Lhs { - s.addStat(lhs) + s.storeLoopVars(lhs) } case *ast.IncDecStmt: // e.g. for i := 0; i < n; i++ - s.addStat(post.X) + s.storeLoopVars(post.X) } } -func (s *Searcher) addStat(expr ast.Expr) { +func (s *Searcher) storeLoopVars(expr ast.Expr) { if id, ok := expr.(*ast.Ident); ok { - s.Stats[id.Pos()] = struct{}{} + s.LoopVars[id.Pos()] = struct{}{} } } +// parseDeclStmt will parse declaring statement (i.e. `var`, `type`, `const`), +// and store the position if it is "var" declaration and is in any loop. func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) { + genDecl, ok := n.Decl.(*ast.GenDecl) + if !ok { + // (dead branch) + // if the Decl is not GenDecl (i.e. `var`, `type` or `const` statement), it is ignored + return + } + if genDecl.Tok != token.VAR { + // if the Decl is not `var` (may be `type` or `const`), it is ignored + return + } + loop, _ := s.innermostLoop(stack) if loop == nil { return } - // Register declaring variables - if genDecl, ok := n.Decl.(*ast.GenDecl); ok && genDecl.Tok == token.VAR { - for _, spec := range genDecl.Specs { - for _, name := range spec.(*ast.ValueSpec).Names { - s.addVar(loop, name) - } + // Register declared variables + for _, spec := range genDecl.Specs { + for _, name := range spec.(*ast.ValueSpec).Names { + s.storeLocalVar(loop, name) } } } +// parseDeclStmt will parse assignment statement (i.e. `<VAR> = <VALUE>`), +// and store the position if it is . func (s *Searcher) parseAssignStmt(n *ast.AssignStmt, stack []ast.Node) { + if n.Tok != token.DEFINE { + // if the statement is simple assignment (without definement), it is ignored + return + } + loop, _ := s.innermostLoop(stack) if loop == nil { return } // Find statements declaring local variable - if n.Tok == token.DEFINE { - for _, h := range n.Lhs { - s.addVar(loop, h) - } + for _, h := range n.Lhs { + s.storeLocalVar(loop, h) } } -func (s *Searcher) addVar(loop ast.Node, expr ast.Expr) { +func (s *Searcher) storeLocalVar(loop ast.Node, expr ast.Expr) { loopPos := loop.Pos() id, ok := expr.(*ast.Ident) if !ok { return } - vars, ok := s.Vars[loopPos] + vars, ok := s.LocalVars[loopPos] if !ok { vars = map[token.Pos]struct{}{} } vars[id.Obj.Pos()] = struct{}{} - s.Vars[loopPos] = vars + s.LocalVars[loopPos] = vars } func insertionPosition(block *ast.BlockStmt) token.Pos { @@ -189,13 +213,15 @@ func (s *Searcher) innermostLoop(stack []ast.Node) (ast.Node, token.Pos) { return nil, token.NoPos } +// checkUnaryExpr check unary expression (i.e. <OPERATOR><VAR> like `-x`, `*p` or `&v`) and stack. +// THIS IS THE ESSENTIAL PART OF THIS PARSER. func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Ident, token.Pos, bool) { - loop, insert := s.innermostLoop(stack) - if loop == nil { + if n.Op != token.AND { return nil, token.NoPos, true } - if n.Op != token.AND { + loop, insert := s.innermostLoop(stack) + if loop == nil { return nil, token.NoPos, true } @@ -207,7 +233,7 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden // If the identity is not the loop statement variable, // it will not be reported. - if _, isStat := s.Stats[id.Obj.Pos()]; !isStat { + if _, isDecl := s.LoopVars[id.Obj.Pos()]; !isDecl { return nil, token.NoPos, true } @@ -266,12 +292,15 @@ func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Iden } func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool { - vars := s.Vars[loop.Pos()] // map[token.Pos]struct{} + vars := s.LocalVars[loop.Pos()] // map[token.Pos]struct{} if vars == nil { return false } switch typed := expr.(type) { case (*ast.Ident): + if typed.Obj == nil { + return false // global var in another file (ref: #13) + } _, isVar := vars[typed.Obj.Pos()] return isVar case (*ast.IndexExpr): // like X[Y], check X @@ -287,7 +316,7 @@ func (s *Searcher) getIdentity(expr ast.Expr) *ast.Ident { switch typed := expr.(type) { case *ast.SelectorExpr: // Ignore if the parent is pointer ref (fix for #2) - if _, ok := s.Types[typed.X].Type.(*types.Pointer); ok { + if _, ok := s.Pass.TypesInfo.Types[typed.X].Type.(*types.Pointer); ok { return nil } diff --git a/vendor/github.com/kyoh86/exportloopref/go.mod b/vendor/github.com/kyoh86/exportloopref/go.mod deleted file mode 100644 index 34a53987a..000000000 --- a/vendor/github.com/kyoh86/exportloopref/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/kyoh86/exportloopref - -go 1.14 - -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 deleted file mode 100644 index 3b199f006..000000000 --- a/vendor/github.com/kyoh86/exportloopref/go.sum +++ /dev/null @@ -1,20 +0,0 @@ -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= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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-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= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
