aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gostaticanalysis/analysisutil
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-09-15 18:05:35 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-09-15 19:34:30 +0200
commit712de1c63d9db97c81af68cd0dc4372c53d2e57a (patch)
treeae1761fec52c3ae4ddd003a4130ddbda8d0a2d69 /vendor/github.com/gostaticanalysis/analysisutil
parent298a69c38dd5c8a9bbd7a022e88f4ddbcf885e16 (diff)
vendor/github.com/golangci/golangci-lint: update to v1.31
Diffstat (limited to 'vendor/github.com/gostaticanalysis/analysisutil')
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/call.go405
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/diagnostic.go45
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/go.mod5
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/go.sum37
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/pkg.go29
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/ssa.go54
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/ssainspect.go37
-rw-r--r--vendor/github.com/gostaticanalysis/analysisutil/types.go198
8 files changed, 802 insertions, 8 deletions
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/call.go b/vendor/github.com/gostaticanalysis/analysisutil/call.go
new file mode 100644
index 000000000..e3d98d1dc
--- /dev/null
+++ b/vendor/github.com/gostaticanalysis/analysisutil/call.go
@@ -0,0 +1,405 @@
+package analysisutil
+
+import (
+ "go/types"
+
+ "golang.org/x/tools/go/ssa"
+)
+
+// CalledChecker checks a function is called.
+// See From and Func.
+type CalledChecker struct {
+ Ignore func(instr ssa.Instruction) bool
+}
+
+// NotIn checks whether receiver's method is called in a function.
+// If there is no methods calling at a path from an instruction
+// which type is receiver to all return instruction, NotIn returns these instructions.
+func (c *CalledChecker) NotIn(f *ssa.Function, receiver types.Type, methods ...*types.Func) []ssa.Instruction {
+ done := map[ssa.Value]bool{}
+ var instrs []ssa.Instruction
+ for _, b := range f.Blocks {
+ for i, instr := range b.Instrs {
+ v, _ := instr.(ssa.Value)
+ if v == nil || done[v] {
+ continue
+ }
+
+ if v, _ := v.(*ssa.UnOp); v != nil && done[v.X] {
+ continue
+ }
+
+ called, ok := c.From(b, i, receiver, methods...)
+ if ok && !called {
+ instrs = append(instrs, instr)
+ done[v] = true
+ if v, _ := v.(*ssa.UnOp); v != nil {
+ done[v.X] = true
+ }
+ }
+ }
+ }
+ return instrs
+}
+
+// Func returns true when f is called in the instr.
+// If recv is not nil, Func also checks the receiver.
+func (c *CalledChecker) Func(instr ssa.Instruction, recv ssa.Value, f *types.Func) bool {
+
+ if c.Ignore != nil && c.Ignore(instr) {
+ return false
+ }
+
+ call, ok := instr.(ssa.CallInstruction)
+ if !ok {
+ return false
+ }
+
+ common := call.Common()
+ if common == nil {
+ return false
+ }
+
+ callee := common.StaticCallee()
+ if callee == nil {
+ return false
+ }
+
+ fn, ok := callee.Object().(*types.Func)
+ if !ok {
+ return false
+ }
+
+ if recv != nil &&
+ common.Signature().Recv() != nil &&
+ (len(common.Args) == 0 && recv != nil || common.Args[0] != recv &&
+ !referrer(recv, common.Args[0])) {
+ return false
+ }
+
+ return fn == f
+}
+
+func referrer(a, b ssa.Value) bool {
+ return isReferrerOf(a, b) || isReferrerOf(b, a)
+}
+
+func isReferrerOf(a, b ssa.Value) bool {
+ if a == nil || b == nil {
+ return false
+ }
+ if b.Referrers() != nil {
+ brs := *b.Referrers()
+
+ for _, br := range brs {
+ brv, ok := br.(ssa.Value)
+ if !ok {
+ continue
+ }
+ if brv == a {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// From checks whether receiver's method is called in an instruction
+// which belogns to after i-th instructions, or in succsor blocks of b.
+// The first result is above value.
+// The second result is whether type of i-th instruction does not much receiver
+// or matches with ignore cases.
+func (c *CalledChecker) From(b *ssa.BasicBlock, i int, receiver types.Type, methods ...*types.Func) (called, ok bool) {
+ if b == nil || i < 0 || i >= len(b.Instrs) ||
+ receiver == nil || len(methods) == 0 {
+ return false, false
+ }
+
+ v, ok := b.Instrs[i].(ssa.Value)
+ if !ok {
+ return false, false
+ }
+
+ from := &calledFrom{recv: v, fs: methods, ignore: c.Ignore}
+
+ if !from.isRecv(receiver, v.Type()) {
+ return false, false
+ }
+
+ if from.ignored() {
+ return false, false
+ }
+
+ if from.instrs(b.Instrs[i+1:]) ||
+ from.succs(b) {
+ return true, true
+ }
+
+ from.done = nil
+ if from.storedInInstrs(b.Instrs[i+1:]) ||
+ from.storedInSuccs(b) {
+ return false, false
+ }
+
+ return false, true
+}
+
+type calledFrom struct {
+ recv ssa.Value
+ fs []*types.Func
+ done map[*ssa.BasicBlock]bool
+ ignore func(ssa.Instruction) bool
+}
+
+func (c *calledFrom) ignored() bool {
+
+ switch v := c.recv.(type) {
+ case *ssa.UnOp:
+ switch v.X.(type) {
+ case *ssa.FreeVar, *ssa.Global:
+ return true
+ }
+ }
+
+ refs := c.recv.Referrers()
+ if refs == nil {
+ return false
+ }
+
+ for _, ref := range *refs {
+ done := map[ssa.Instruction]bool{}
+ if !c.isOwn(ref) &&
+ ((c.ignore != nil && c.ignore(ref)) ||
+ c.isRet(ref, done) || c.isArg(ref)) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (c *calledFrom) isOwn(instr ssa.Instruction) bool {
+ v, ok := instr.(ssa.Value)
+ if !ok {
+ return false
+ }
+ return v == c.recv
+}
+
+func (c *calledFrom) isRet(instr ssa.Instruction, done map[ssa.Instruction]bool) bool {
+ if done[instr] {
+ return false
+ }
+ done[instr] = true
+
+ switch instr := instr.(type) {
+ case *ssa.Return:
+ return true
+ case *ssa.MapUpdate:
+ return c.isRetInRefs(instr.Map, done)
+ case *ssa.Store:
+ if instr, _ := instr.Addr.(ssa.Instruction); instr != nil {
+ return c.isRet(instr, done)
+ }
+ return c.isRetInRefs(instr.Addr, done)
+ case *ssa.FieldAddr:
+ return c.isRetInRefs(instr.X, done)
+ case ssa.Value:
+ return c.isRetInRefs(instr, done)
+ default:
+ return false
+ }
+}
+
+func (c *calledFrom) isRetInRefs(v ssa.Value, done map[ssa.Instruction]bool) bool {
+ refs := v.Referrers()
+ if refs == nil {
+ return false
+ }
+ for _, ref := range *refs {
+ if c.isRet(ref, done) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *calledFrom) isArg(instr ssa.Instruction) bool {
+
+ call, ok := instr.(ssa.CallInstruction)
+ if !ok {
+ return false
+ }
+
+ common := call.Common()
+ if common == nil {
+ return false
+ }
+
+ args := common.Args
+ if common.Signature().Recv() != nil {
+ args = args[1:]
+ }
+
+ for i := range args {
+ if args[i] == c.recv {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (c *calledFrom) instrs(instrs []ssa.Instruction) bool {
+ for _, instr := range instrs {
+ for _, f := range c.fs {
+ if Called(instr, c.recv, f) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func (c *calledFrom) succs(b *ssa.BasicBlock) bool {
+ if c.done == nil {
+ c.done = map[*ssa.BasicBlock]bool{}
+ }
+
+ if c.done[b] {
+ return true
+ }
+ c.done[b] = true
+
+ if len(b.Succs) == 0 {
+ return false
+ }
+
+ for _, s := range b.Succs {
+ if !c.instrs(s.Instrs) && !c.succs(s) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *calledFrom) storedInInstrs(instrs []ssa.Instruction) bool {
+ for _, instr := range instrs {
+ switch instr := instr.(type) {
+ case *ssa.Store:
+ if instr.Val == c.recv {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func (c *calledFrom) storedInSuccs(b *ssa.BasicBlock) bool {
+ if c.done == nil {
+ c.done = map[*ssa.BasicBlock]bool{}
+ }
+
+ if c.done[b] {
+ return true
+ }
+ c.done[b] = true
+
+ if len(b.Succs) == 0 {
+ return false
+ }
+
+ for _, s := range b.Succs {
+ if !c.storedInInstrs(s.Instrs) && !c.succs(s) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *calledFrom) isRecv(recv, typ types.Type) bool {
+ return recv == typ || identical(recv, typ) ||
+ c.isRecvInTuple(recv, typ) || c.isRecvInEmbedded(recv, typ)
+}
+
+func (c *calledFrom) isRecvInTuple(recv, typ types.Type) bool {
+ tuple, _ := typ.(*types.Tuple)
+ if tuple == nil {
+ return false
+ }
+
+ for i := 0; i < tuple.Len(); i++ {
+ if c.isRecv(recv, tuple.At(i).Type()) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (c *calledFrom) isRecvInEmbedded(recv, typ types.Type) bool {
+
+ var st *types.Struct
+ switch typ := typ.(type) {
+ case *types.Struct:
+ st = typ
+ case *types.Pointer:
+ return c.isRecvInEmbedded(recv, typ.Elem())
+ case *types.Named:
+ return c.isRecvInEmbedded(recv, typ.Underlying())
+ default:
+ return false
+ }
+
+ for i := 0; i < st.NumFields(); i++ {
+ field := st.Field(i)
+ if !field.Embedded() {
+ continue
+ }
+
+ ft := field.Type()
+ if c.isRecv(recv, ft) {
+ return true
+ }
+
+ var ptrOrUnptr types.Type
+ switch ft := ft.(type) {
+ case *types.Pointer:
+ // struct { *T } -> T
+ ptrOrUnptr = ft.Elem()
+ default:
+ // struct { T } -> *T
+ ptrOrUnptr = types.NewPointer(ft)
+ }
+
+ if c.isRecv(recv, ptrOrUnptr) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// NotCalledIn checks whether receiver's method is called in a function.
+// If there is no methods calling at a path from an instruction
+// which type is receiver to all return instruction, NotCalledIn returns these instructions.
+func NotCalledIn(f *ssa.Function, receiver types.Type, methods ...*types.Func) []ssa.Instruction {
+ return new(CalledChecker).NotIn(f, receiver, methods...)
+}
+
+// CalledFrom checks whether receiver's method is called in an instruction
+// which belogns to after i-th instructions, or in succsor blocks of b.
+// The first result is above value.
+// The second result is whether type of i-th instruction does not much receiver
+// or matches with ignore cases.
+func CalledFrom(b *ssa.BasicBlock, i int, receiver types.Type, methods ...*types.Func) (called, ok bool) {
+ return new(CalledChecker).From(b, i, receiver, methods...)
+}
+
+// Called returns true when f is called in the instr.
+// If recv is not nil, Called also checks the receiver.
+func Called(instr ssa.Instruction, recv ssa.Value, f *types.Func) bool {
+ return new(CalledChecker).Func(instr, recv, f)
+}
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/diagnostic.go b/vendor/github.com/gostaticanalysis/analysisutil/diagnostic.go
new file mode 100644
index 000000000..a911db6f1
--- /dev/null
+++ b/vendor/github.com/gostaticanalysis/analysisutil/diagnostic.go
@@ -0,0 +1,45 @@
+package analysisutil
+
+import (
+ "go/token"
+
+ "github.com/gostaticanalysis/comment"
+ "github.com/gostaticanalysis/comment/passes/commentmap"
+ "golang.org/x/tools/go/analysis"
+)
+
+// ReportWithoutIgnore returns a report function which can set to (analysis.Pass).Report.
+// The report function ignores a diagnostic which annotated by ignore comment as the below.
+// //lint:ignore Check1[,Check2,...,CheckN] reason
+// names is a list of checker names.
+// If names was omitted, the report function ignores by pass.Analyzer.Name.
+func ReportWithoutIgnore(pass *analysis.Pass, names ...string) func(analysis.Diagnostic) {
+ cmaps, _ := pass.ResultOf[commentmap.Analyzer].(comment.Maps)
+ if cmaps == nil {
+ cmaps = comment.New(pass.Fset, pass.Files)
+ }
+
+ if len(names) == 0 {
+ names = []string{pass.Analyzer.Name}
+ }
+
+ report := pass.Report // original report func
+
+ return func(d analysis.Diagnostic) {
+ start := pass.Fset.File(d.Pos).Line(d.Pos)
+ end := start
+ if d.End != token.NoPos {
+ end = pass.Fset.File(d.End).Line(d.End)
+ }
+
+ for l := start; l <= end; l++ {
+ for _, n := range names {
+ if cmaps.IgnoreLine(pass.Fset, l, n) {
+ return
+ }
+ }
+ }
+
+ report(d)
+ }
+}
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/go.mod b/vendor/github.com/gostaticanalysis/analysisutil/go.mod
index 7e3e55be1..5ca7c62b8 100644
--- a/vendor/github.com/gostaticanalysis/analysisutil/go.mod
+++ b/vendor/github.com/gostaticanalysis/analysisutil/go.mod
@@ -2,4 +2,7 @@ module github.com/gostaticanalysis/analysisutil
go 1.12
-require golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5
+require (
+ github.com/gostaticanalysis/comment v1.4.1
+ golang.org/x/tools v0.0.0-20200820010801-b793a1359eac
+)
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/go.sum b/vendor/github.com/gostaticanalysis/analysisutil/go.sum
index 16c8787c4..134e67dbd 100644
--- a/vendor/github.com/gostaticanalysis/analysisutil/go.sum
+++ b/vendor/github.com/gostaticanalysis/analysisutil/go.sum
@@ -1,6 +1,37 @@
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/gostaticanalysis/comment v1.3.0 h1:wTVgynbFu8/nz6SGgywA0TcyIoAVsYc7ai/Zp5xNGlw=
+github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI=
+github.com/gostaticanalysis/comment v1.4.1 h1:xHopR5L2lRz6OsjH4R2HG5wRhW9ySl3FsHIvi5pcXwc=
+github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+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/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+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/sync v0.0.0-20200625203802-6e8e738ad208/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/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5 h1:ZcPpqKMdoZeNQ/4GHlyY4COf8n8SmpPv6mcqF1+VPSM=
-golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3 h1:2oZsfYnKfYzL4I57uYiRFsUf0bqlLkiuw8nnj3+voUA=
+golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff h1:foic6oVZ4MKltJC6MXzuFZFswE7NCjjtc0Hxbyblawc=
+golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI=
+golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+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=
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/pkg.go b/vendor/github.com/gostaticanalysis/analysisutil/pkg.go
index c98710d18..b64150d81 100644
--- a/vendor/github.com/gostaticanalysis/analysisutil/pkg.go
+++ b/vendor/github.com/gostaticanalysis/analysisutil/pkg.go
@@ -2,14 +2,17 @@ package analysisutil
import (
"go/types"
+ "strconv"
"strings"
+
+ "golang.org/x/tools/go/analysis"
)
-// RemoVendor removes vendoring infomation from import path.
+// RemoVendor removes vendoring information from import path.
func RemoveVendor(path string) string {
- i := strings.Index(path, "vendor")
+ i := strings.Index(path, "vendor/")
if i >= 0 {
- return path[i+len("vendor")+1:]
+ return path[i+len("vendor/"):]
}
return path
}
@@ -24,3 +27,23 @@ func LookupFromImports(imports []*types.Package, path, name string) types.Object
}
return nil
}
+
+// Imported returns true when the given pass imports the pkg.
+func Imported(pkgPath string, pass *analysis.Pass) bool {
+ fs := pass.Files
+ if len(fs) == 0 {
+ return false
+ }
+ for _, f := range fs {
+ for _, i := range f.Imports {
+ path, err := strconv.Unquote(i.Path.Value)
+ if err != nil {
+ continue
+ }
+ if RemoveVendor(path) == pkgPath {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/ssa.go b/vendor/github.com/gostaticanalysis/analysisutil/ssa.go
index 379158667..ce3af580b 100644
--- a/vendor/github.com/gostaticanalysis/analysisutil/ssa.go
+++ b/vendor/github.com/gostaticanalysis/analysisutil/ssa.go
@@ -1,6 +1,8 @@
package analysisutil
-import "golang.org/x/tools/go/ssa"
+import (
+ "golang.org/x/tools/go/ssa"
+)
// IfInstr returns *ssa.If which is contained in the block b.
// If the block b has not any if instruction, IfInstr returns nil.
@@ -29,3 +31,53 @@ func Phi(b *ssa.BasicBlock) (phis []*ssa.Phi) {
}
return
}
+
+// Returns returns a slice of *ssa.Return in the function.
+func Returns(v ssa.Value) []*ssa.Return {
+ var fn *ssa.Function
+ switch v := v.(type) {
+ case *ssa.Function:
+ fn = v
+ case *ssa.MakeClosure:
+ return Returns(v.Fn)
+ default:
+ return nil
+ }
+
+ var rets []*ssa.Return
+ done := map[*ssa.BasicBlock]bool{}
+ for _, b := range fn.Blocks {
+ rets = append(rets, returnsInBlock(b, done)...)
+ }
+ return rets
+}
+
+func returnsInBlock(b *ssa.BasicBlock, done map[*ssa.BasicBlock]bool) (rets []*ssa.Return) {
+ if done[b] {
+ return
+ }
+ done[b] = true
+
+ if len(b.Instrs) != 0 {
+ switch instr := b.Instrs[len(b.Instrs)-1].(type) {
+ case *ssa.Return:
+ rets = append(rets, instr)
+ }
+ }
+
+ for _, s := range b.Succs {
+ rets = append(rets, returnsInBlock(s, done)...)
+ }
+ return
+}
+
+// BinOp returns binary operator values which are contained in the block b.
+func BinOp(b *ssa.BasicBlock) ([]*ssa.BinOp) {
+ var binops []*ssa.BinOp
+ for _, instr := range b.Instrs {
+ if binop, ok := instr.(*ssa.BinOp); ok {
+ binops = append(binops, binop)
+ }
+ }
+ return binops
+}
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/ssainspect.go b/vendor/github.com/gostaticanalysis/analysisutil/ssainspect.go
new file mode 100644
index 000000000..2f8a16576
--- /dev/null
+++ b/vendor/github.com/gostaticanalysis/analysisutil/ssainspect.go
@@ -0,0 +1,37 @@
+package analysisutil
+
+import "golang.org/x/tools/go/ssa"
+
+// InspectInstr inspects from i-th instruction of start block to succsessor blocks.
+func InspectInstr(start *ssa.BasicBlock, i int, f func(i int, instr ssa.Instruction) bool) {
+ new(instrInspector).block(start, i, f)
+}
+
+type instrInspector struct {
+ done map[*ssa.BasicBlock]bool
+}
+
+func (ins *instrInspector) block(b *ssa.BasicBlock, i int, f func(i int, instr ssa.Instruction) bool) {
+ if ins.done == nil {
+ ins.done = map[*ssa.BasicBlock]bool{}
+ }
+
+ if b == nil || ins.done[b] || len(b.Instrs) <= i {
+ return
+ }
+
+ ins.done[b] = true
+ ins.instrs(i, b.Instrs[i:], f)
+ for _, s := range b.Succs {
+ ins.block(s, 0, f)
+ }
+
+}
+
+func (ins *instrInspector) instrs(offset int, instrs []ssa.Instruction, f func(i int, instr ssa.Instruction) bool) {
+ for i, instr := range instrs {
+ if !f(offset+i, instr) {
+ break
+ }
+ }
+}
diff --git a/vendor/github.com/gostaticanalysis/analysisutil/types.go b/vendor/github.com/gostaticanalysis/analysisutil/types.go
new file mode 100644
index 000000000..4773ac43e
--- /dev/null
+++ b/vendor/github.com/gostaticanalysis/analysisutil/types.go
@@ -0,0 +1,198 @@
+package analysisutil
+
+import (
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var errType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+// ImplementsError return whether t implements error interface.
+func ImplementsError(t types.Type) bool {
+ return types.Implements(t, errType)
+}
+
+// ObjectOf returns types.Object by given name in the package.
+func ObjectOf(pass *analysis.Pass, pkg, name string) types.Object {
+ obj := LookupFromImports(pass.Pkg.Imports(), pkg, name)
+ if obj != nil {
+ return obj
+ }
+ if RemoveVendor(pass.Pkg.Name()) != RemoveVendor(pkg) {
+ return nil
+ }
+ return pass.Pkg.Scope().Lookup(name)
+}
+
+// TypeOf returns types.Type by given name in the package.
+// TypeOf accepts pointer types such as *T.
+func TypeOf(pass *analysis.Pass, pkg, name string) types.Type {
+ if name == "" {
+ return nil
+ }
+
+ if name[0] == '*' {
+ obj := TypeOf(pass, pkg, name[1:])
+ if obj == nil {
+ return nil
+ }
+ return types.NewPointer(obj)
+ }
+
+ obj := ObjectOf(pass, pkg, name)
+ if obj == nil {
+ return nil
+ }
+
+ return obj.Type()
+}
+
+// MethodOf returns a method which has given name in the type.
+func MethodOf(typ types.Type, name string) *types.Func {
+ switch typ := typ.(type) {
+ case *types.Named:
+ for i := 0; i < typ.NumMethods(); i++ {
+ if f := typ.Method(i); f.Name() == name {
+ return f
+ }
+ }
+ case *types.Pointer:
+ return MethodOf(typ.Elem(), name)
+ }
+ return nil
+}
+
+// see: https://github.com/golang/go/issues/19670
+func identical(x, y types.Type) (ret bool) {
+ defer func() {
+ r := recover()
+ switch r := r.(type) {
+ case string:
+ if r == "unreachable" {
+ ret = false
+ return
+ }
+ case nil:
+ return
+ }
+ panic(r)
+ }()
+ return types.Identical(x, y)
+}
+
+// Interfaces returns a map of interfaces which are declared in the package.
+func Interfaces(pkg *types.Package) map[string]*types.Interface {
+ ifs := map[string]*types.Interface{}
+
+ for _, n := range pkg.Scope().Names() {
+ o := pkg.Scope().Lookup(n)
+ if o != nil {
+ i, ok := o.Type().Underlying().(*types.Interface)
+ if ok {
+ ifs[n] = i
+ }
+ }
+ }
+
+ return ifs
+}
+
+// Structs returns a map of structs which are declared in the package.
+func Structs(pkg *types.Package) map[string]*types.Struct {
+ structs := map[string]*types.Struct{}
+
+ for _, n := range pkg.Scope().Names() {
+ o := pkg.Scope().Lookup(n)
+ if o != nil {
+ s, ok := o.Type().Underlying().(*types.Struct)
+ if ok {
+ structs[n] = s
+ }
+ }
+ }
+
+ return structs
+}
+
+// HasField returns whether the struct has the field.
+func HasField(s *types.Struct, f *types.Var) bool {
+ if s == nil || f == nil {
+ return false
+ }
+
+ for i := 0; i < s.NumFields(); i++ {
+ if s.Field(i) == f {
+ return true
+ }
+ }
+
+ return false
+}
+
+func TypesInfo(info ...*types.Info) *types.Info {
+ if len(info) == 0 {
+ return nil
+ }
+
+ var merged types.Info
+ for i := range info {
+ mergeTypesInfo(&merged, info[i])
+ }
+
+ return &merged
+}
+
+func mergeTypesInfo(i1, i2 *types.Info) {
+ // Types
+ if i1.Types == nil && i2.Types != nil {
+ i1.Types = map[ast.Expr]types.TypeAndValue{}
+ }
+ for expr, tv := range i2.Types {
+ i1.Types[expr] = tv
+ }
+
+ // Defs
+ if i1.Defs == nil && i2.Defs != nil {
+ i1.Defs = map[*ast.Ident]types.Object{}
+ }
+ for ident, obj := range i2.Defs {
+ i1.Defs[ident] = obj
+ }
+
+ // Uses
+ if i1.Uses == nil && i2.Uses != nil {
+ i1.Uses = map[*ast.Ident]types.Object{}
+ }
+ for ident, obj := range i2.Uses {
+ i1.Uses[ident] = obj
+ }
+
+ // Implicits
+ if i1.Implicits == nil && i2.Implicits != nil {
+ i1.Implicits = map[ast.Node]types.Object{}
+ }
+ for n, obj := range i2.Implicits {
+ i1.Implicits[n] = obj
+ }
+
+ // Selections
+ if i1.Selections == nil && i2.Selections != nil {
+ i1.Selections = map[*ast.SelectorExpr]*types.Selection{}
+ }
+ for expr, sel := range i2.Selections {
+ i1.Selections[expr] = sel
+ }
+
+ // Scopes
+ if i1.Scopes == nil && i2.Scopes != nil {
+ i1.Scopes = map[ast.Node]*types.Scope{}
+ }
+ for n, s := range i2.Scopes {
+ i1.Scopes[n] = s
+ }
+
+ // InitOrder
+ i1.InitOrder = append(i1.InitOrder, i2.InitOrder...)
+}