aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/kyoh86/exportloopref
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/kyoh86/exportloopref')
-rw-r--r--vendor/github.com/kyoh86/exportloopref/.golangci.yml4
-rw-r--r--vendor/github.com/kyoh86/exportloopref/.goreleaser.yml43
-rw-r--r--vendor/github.com/kyoh86/exportloopref/LICENSE21
-rw-r--r--vendor/github.com/kyoh86/exportloopref/Makefile16
-rw-r--r--vendor/github.com/kyoh86/exportloopref/README.md178
-rw-r--r--vendor/github.com/kyoh86/exportloopref/exportloopref.go276
-rw-r--r--vendor/github.com/kyoh86/exportloopref/go.mod5
-rw-r--r--vendor/github.com/kyoh86/exportloopref/go.sum20
8 files changed, 563 insertions, 0 deletions
diff --git a/vendor/github.com/kyoh86/exportloopref/.golangci.yml b/vendor/github.com/kyoh86/exportloopref/.golangci.yml
new file mode 100644
index 000000000..58667b215
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/.golangci.yml
@@ -0,0 +1,4 @@
+linters:
+ enable:
+ - unparam
+ - scopelint
diff --git a/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml b/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml
new file mode 100644
index 000000000..22ff44040
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml
@@ -0,0 +1,43 @@
+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
+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 }}
diff --git a/vendor/github.com/kyoh86/exportloopref/LICENSE b/vendor/github.com/kyoh86/exportloopref/LICENSE
new file mode 100644
index 000000000..7ac9dba4a
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 kyoh86
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/kyoh86/exportloopref/Makefile b/vendor/github.com/kyoh86/exportloopref/Makefile
new file mode 100644
index 000000000..4d3ef22f7
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/Makefile
@@ -0,0 +1,16 @@
+.PHONY: gen lint test install man
+
+VERSION := `git vertag get`
+COMMIT := `git rev-parse HEAD`
+
+gen:
+ go generate ./...
+
+lint: gen
+ golangci-lint run
+
+test: lint
+ go test -v --race ./...
+
+install: test
+ go install -a -ldflags "-X=main.version=$(VERSION) -X=main.commit=$(COMMIT)" ./...
diff --git a/vendor/github.com/kyoh86/exportloopref/README.md b/vendor/github.com/kyoh86/exportloopref/README.md
new file mode 100644
index 000000000..5b1549159
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/README.md
@@ -0,0 +1,178 @@
+# exportloopref
+
+An analyzer that finds exporting pointers for loop variables.
+
+[![Go Report Card](https://goreportcard.com/badge/github.com/kyoh86/exportloopref)](https://goreportcard.com/report/github.com/kyoh86/exportloopref)
+[![Coverage Status](https://img.shields.io/codecov/c/github/kyoh86/exportloopref.svg)](https://codecov.io/gh/kyoh86/exportloopref)
+[![Release](https://github.com/kyoh86/exportloopref/workflows/Release/badge.svg)](https://github.com/kyoh86/exportloopref/releases)
+
+## What's this?
+
+Sample problem code from: https://github.com/kyoh86/exportloopref/blob/master/testdata/simple/simple.go
+
+```go
+package main
+
+func main() {
+ var intArray [4]*int
+ var intSlice []*int
+ var intRef *int
+ var intStr struct{ x *int }
+
+ println("loop expecting 10, 11, 12, 13")
+ for i, p := range []int{10, 11, 12, 13} {
+ printp(&p) // not a diagnostic
+ intSlice = append(intSlice, &p) // want "exporting a pointer for the loop variable p"
+ intArray[i] = &p // want "exporting a pointer for the loop variable p"
+ if i%2 == 0 {
+ intRef = &p // want "exporting a pointer for the loop variable p"
+ intStr.x = &p // want "exporting a pointer for the loop variable p"
+ }
+ var vStr struct{ x *int }
+ 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)
+ vStr.x = &p
+ }
+ _ = v
+ }
+
+ println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
+ for _, p := range intSlice {
+ printp(p)
+ }
+ println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
+ for _, p := range intArray {
+ printp(p)
+ }
+ println(`captured value expecting "12" but "13"`)
+ printp(intRef)
+}
+
+func printp(p *int) {
+ println(*p)
+}
+```
+
+In Go, the `p` variable in the above loops is actually a single variable.
+So in many case (like the above), using it makes for us annoying bugs.
+
+You can find them with `exportloopref`, and fix it.
+
+```go
+package main
+
+func main() {
+ var intArray [4]*int
+ var intSlice []*int
+ var intRef *int
+ var intStr struct{ x *int }
+
+ println("loop expecting 10, 11, 12, 13")
+ for i, p := range []int{10, 11, 12, 13} {
+ p := p // FIX variable into the inner variable
+ printp(&p)
+ intSlice = append(intSlice, &p)
+ intArray[i] = &p
+ if i%2 == 0 {
+ intRef = &p
+ intStr.x = &p
+ }
+ var vStr struct{ x *int }
+ var vArray [4]*int
+ var v *int
+ if i%2 == 0 {
+ v = &p
+ vArray[1] = &p
+ vStr.x = &p
+ }
+ _ = v
+ }
+
+ println(`slice expecting "10, 11, 12, 13"`)
+ for _, p := range intSlice {
+ printp(p)
+ }
+ println(`array expecting "10, 11, 12, 13"`)
+ for _, p := range intArray {
+ printp(p)
+ }
+ println(`captured value expecting "12"`)
+ printp(intRef)
+}
+
+func printp(p *int) {
+ println(*p)
+}
+```
+
+ref: https://github.com/kyoh86/exportloopref/blob/master/testdata/fixed/fixed.go
+
+## Sensing policy
+
+I want to make exportloopref as accurately as possible.
+So some cases of lints will be ignored.
+
+e.g.
+
+```go
+var s Foo
+for _, p := []int{10, 11, 12, 13} {
+ s.Bar(&p) // If s stores the pointer, it will be bug.
+}
+```
+
+If you want to report all of lints (with some false-positives),
+you should use [looppointer](https://github.com/kyoh86/looppointer).
+
+## Install
+
+go:
+
+```console
+$ go get github.com/kyoh86/exportloopref/cmd/exportloopref
+```
+
+[homebrew](https://brew.sh/):
+
+```console
+$ brew install kyoh86/tap/exportloopref
+```
+
+[gordon](https://github.com/kyoh86/gordon):
+
+```console
+$ gordon install kyoh86/exportloopref
+```
+
+## Usage
+
+```
+exportloopref [-flag] [package]
+```
+
+### Flags
+
+| Flag | Description |
+| --- | --- |
+| -V | print version and exit |
+| -all | no effect (deprecated) |
+| -c int | display offending line with this many lines of context (default -1) |
+| -cpuprofile string | write CPU profile to this file |
+| -debug string | debug flags, any subset of "fpstv" |
+| -fix | apply all suggested fixes |
+| -flags | print analyzer flags in JSON |
+| -json | emit JSON output |
+| -memprofile string | write memory profile to this file |
+| -source | no effect (deprecated) |
+| -tags string | no effect (deprecated) |
+| -trace string | write trace log to this file |
+| -v | no effect (deprecated) |
+
+# LICENSE
+
+[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)](http://www.opensource.org/licenses/MIT)
+
+This is distributed under the [MIT License](http://www.opensource.org/licenses/MIT).
diff --git a/vendor/github.com/kyoh86/exportloopref/exportloopref.go b/vendor/github.com/kyoh86/exportloopref/exportloopref.go
new file mode 100644
index 000000000..0b310b3c9
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/exportloopref.go
@@ -0,0 +1,276 @@
+package exportloopref
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "exportloopref",
+ Doc: "checks for pointers to enclosing loop variables",
+ 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,
+ }
+
+ nodeFilter := []ast.Node{
+ (*ast.RangeStmt)(nil),
+ (*ast.ForStmt)(nil),
+ (*ast.DeclStmt)(nil),
+ (*ast.AssignStmt)(nil),
+ (*ast.UnaryExpr)(nil),
+ }
+
+ inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool {
+ id, digg := search.Check(n, stack)
+ if id != nil {
+ pass.ReportRangef(id, "exporting a pointer for the loop variable %s", id.Name)
+ }
+ return digg
+ })
+
+ return nil, nil
+}
+
+type Searcher struct {
+ // Statement variables : map to collect positions that
+ // variables are declared like below.
+ // - for <KEY>, <VALUE> := range ...
+ // - var <X> int
+ // - D := ...
+ Stats map[token.Pos]struct{}
+ // Internal 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) {
+ switch typed := n.(type) {
+ case *ast.RangeStmt:
+ s.parseRangeStmt(typed)
+ case *ast.ForStmt:
+ s.parseForStmt(typed)
+ case *ast.DeclStmt:
+ s.parseDeclStmt(typed, stack)
+ case *ast.AssignStmt:
+ s.parseAssignStmt(typed, stack)
+
+ case *ast.UnaryExpr:
+ return s.checkUnaryExpr(typed, stack)
+ }
+ return nil, true
+}
+
+func (s *Searcher) parseRangeStmt(n *ast.RangeStmt) {
+ s.addStat(n.Key)
+ s.addStat(n.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)
+ }
+ case *ast.IncDecStmt:
+ // e.g. for i := 0; i < n; i++
+ s.addStat(post.X)
+ }
+}
+
+func (s *Searcher) addStat(expr ast.Expr) {
+ if id, ok := expr.(*ast.Ident); ok {
+ s.Stats[id.Pos()] = struct{}{}
+ }
+}
+
+func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) {
+ 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)
+ }
+ }
+ }
+}
+
+func (s *Searcher) parseAssignStmt(n *ast.AssignStmt, stack []ast.Node) {
+ loop := s.innermostLoop(stack)
+ if loop == nil {
+ return
+ }
+
+ // Find statements declaring internal variable
+ if n.Tok == token.DEFINE {
+ for _, h := range n.Lhs {
+ s.addVar(loop, h)
+ }
+ }
+}
+
+func (s *Searcher) addVar(loop ast.Node, expr ast.Expr) {
+ loopPos := loop.Pos()
+ id, ok := expr.(*ast.Ident)
+ if !ok {
+ return
+ }
+ vars, ok := s.Vars[loopPos]
+ if !ok {
+ vars = map[token.Pos]struct{}{}
+ }
+ vars[id.Obj.Pos()] = struct{}{}
+ s.Vars[loopPos] = vars
+}
+
+func (s *Searcher) innermostLoop(stack []ast.Node) ast.Node {
+ for i := len(stack) - 1; i >= 0; i-- {
+ switch stack[i].(type) {
+ case *ast.RangeStmt, *ast.ForStmt:
+ return stack[i]
+ }
+ }
+ return nil
+}
+
+func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Ident, bool) {
+ loop := s.innermostLoop(stack)
+ if loop == nil {
+ return nil, true
+ }
+
+ if n.Op != token.AND {
+ return nil, true
+ }
+
+ // Get identity of the referred item
+ id := s.getIdentity(n.X)
+ if id == nil {
+ return nil, 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
+ }
+
+ // check stack append(), []X{}, map[Type]X{}, Struct{}, &Struct{}, X.(Type), (X)
+ // in the <outer> =
+ var mayRHPos token.Pos
+ for i := len(stack) - 2; i >= 0; i-- {
+ switch typed := stack[i].(type) {
+ case (*ast.UnaryExpr):
+ // noop
+ case (*ast.CompositeLit):
+ // noop
+ case (*ast.KeyValueExpr):
+ // noop
+ 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
+ }
+
+ if fun.Name != "append" {
+ return nil, 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
+ }
+
+ // search x where Rhs[x].Pos() == mayRHPos
+ var index int
+ for ri, rh := range typed.Rhs {
+ if rh.Pos() == mayRHPos {
+ index = ri
+ break
+ }
+ }
+
+ // check Lhs[x] is not inner variable
+ lh := typed.Lhs[index]
+ isVar := s.isVar(loop, lh)
+ if !isVar {
+ return id, false
+ }
+
+ return nil, true
+ default:
+ // Other statement is not able to be checked.
+ return nil, false
+ }
+
+ // memory an expr that may be right-hand in the AssignStmt
+ mayRHPos = stack[i].Pos()
+ }
+ return nil, true
+}
+
+func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool {
+ vars := s.Vars[loop.Pos()] // map[token.Pos]struct{}
+ if vars == nil {
+ return false
+ }
+ switch typed := expr.(type) {
+ case (*ast.Ident):
+ _, isVar := vars[typed.Obj.Pos()]
+ return isVar
+ case (*ast.IndexExpr): // like X[Y], check X
+ return s.isVar(loop, typed.X)
+ case (*ast.SelectorExpr): // like X.Y, check X
+ return s.isVar(loop, typed.X)
+ }
+ return false
+}
+
+// Get variable identity
+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 {
+ return nil
+ }
+
+ // Get parent identity; i.e. `a.b` of the `a.b.c`.
+ return s.getIdentity(typed.X)
+
+ case *ast.Ident:
+ // Get simple identity; i.e. `a` of the `a`.
+ if typed.Obj == nil {
+ return nil
+ }
+ return typed
+ }
+ return nil
+}
diff --git a/vendor/github.com/kyoh86/exportloopref/go.mod b/vendor/github.com/kyoh86/exportloopref/go.mod
new file mode 100644
index 000000000..2b61b220b
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/go.mod
@@ -0,0 +1,5 @@
+module github.com/kyoh86/exportloopref
+
+go 1.14
+
+require golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed
diff --git a/vendor/github.com/kyoh86/exportloopref/go.sum b/vendor/github.com/kyoh86/exportloopref/go.sum
new file mode 100644
index 000000000..eb0e5ab1e
--- /dev/null
+++ b/vendor/github.com/kyoh86/exportloopref/go.sum
@@ -0,0 +1,20 @@
+github.com/yuin/goldmark v1.1.25/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-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/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=