aboutsummaryrefslogtreecommitdiff
path: root/vendor/honnef.co/go/tools/functions
diff options
context:
space:
mode:
authorJoseph Richey <joerichey@google.com>2018-08-30 13:41:49 -0700
committerGitHub <noreply@github.com>2018-08-30 13:41:49 -0700
commit0f451a722918f39fa07bd9337e4a14ca154b13ae (patch)
tree9868ffed8cb74357a06e63b88c56d71b13b415af /vendor/honnef.co/go/tools/functions
parent1e1b67dae6c3ae3b5acb5ce377b01b286c3e676b (diff)
parent1c9bafdec78b8f238a82314b6d9c566a951486c2 (diff)
Merge pull request #107 from google/mod
Use Go Modules and support Go 1.11 building
Diffstat (limited to 'vendor/honnef.co/go/tools/functions')
-rw-r--r--vendor/honnef.co/go/tools/functions/concrete.go56
-rw-r--r--vendor/honnef.co/go/tools/functions/functions.go150
-rw-r--r--vendor/honnef.co/go/tools/functions/loops.go50
-rw-r--r--vendor/honnef.co/go/tools/functions/pure.go123
-rw-r--r--vendor/honnef.co/go/tools/functions/terminates.go24
5 files changed, 0 insertions, 403 deletions
diff --git a/vendor/honnef.co/go/tools/functions/concrete.go b/vendor/honnef.co/go/tools/functions/concrete.go
deleted file mode 100644
index 932acd0..0000000
--- a/vendor/honnef.co/go/tools/functions/concrete.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package functions
-
-import (
- "go/token"
- "go/types"
-
- "honnef.co/go/tools/ssa"
-)
-
-func concreteReturnTypes(fn *ssa.Function) []*types.Tuple {
- res := fn.Signature.Results()
- if res == nil {
- return nil
- }
- ifaces := make([]bool, res.Len())
- any := false
- for i := 0; i < res.Len(); i++ {
- _, ifaces[i] = res.At(i).Type().Underlying().(*types.Interface)
- any = any || ifaces[i]
- }
- if !any {
- return []*types.Tuple{res}
- }
- var out []*types.Tuple
- for _, block := range fn.Blocks {
- if len(block.Instrs) == 0 {
- continue
- }
- ret, ok := block.Instrs[len(block.Instrs)-1].(*ssa.Return)
- if !ok {
- continue
- }
- vars := make([]*types.Var, res.Len())
- for i, v := range ret.Results {
- var typ types.Type
- if !ifaces[i] {
- typ = res.At(i).Type()
- } else if mi, ok := v.(*ssa.MakeInterface); ok {
- // TODO(dh): if mi.X is a function call that returns
- // an interface, call concreteReturnTypes on that
- // function (or, really, go through Descriptions,
- // avoid infinite recursion etc, just like nil error
- // detection)
-
- // TODO(dh): support Phi nodes
- typ = mi.X.Type()
- } else {
- typ = res.At(i).Type()
- }
- vars[i] = types.NewParam(token.NoPos, nil, "", typ)
- }
- out = append(out, types.NewTuple(vars...))
- }
- // TODO(dh): deduplicate out
- return out
-}
diff --git a/vendor/honnef.co/go/tools/functions/functions.go b/vendor/honnef.co/go/tools/functions/functions.go
deleted file mode 100644
index c5fe2d7..0000000
--- a/vendor/honnef.co/go/tools/functions/functions.go
+++ /dev/null
@@ -1,150 +0,0 @@
-package functions
-
-import (
- "go/types"
- "sync"
-
- "honnef.co/go/tools/callgraph"
- "honnef.co/go/tools/callgraph/static"
- "honnef.co/go/tools/ssa"
- "honnef.co/go/tools/staticcheck/vrp"
-)
-
-var stdlibDescs = map[string]Description{
- "errors.New": Description{Pure: true},
-
- "fmt.Errorf": Description{Pure: true},
- "fmt.Sprintf": Description{Pure: true},
- "fmt.Sprint": Description{Pure: true},
-
- "sort.Reverse": Description{Pure: true},
-
- "strings.Map": Description{Pure: true},
- "strings.Repeat": Description{Pure: true},
- "strings.Replace": Description{Pure: true},
- "strings.Title": Description{Pure: true},
- "strings.ToLower": Description{Pure: true},
- "strings.ToLowerSpecial": Description{Pure: true},
- "strings.ToTitle": Description{Pure: true},
- "strings.ToTitleSpecial": Description{Pure: true},
- "strings.ToUpper": Description{Pure: true},
- "strings.ToUpperSpecial": Description{Pure: true},
- "strings.Trim": Description{Pure: true},
- "strings.TrimFunc": Description{Pure: true},
- "strings.TrimLeft": Description{Pure: true},
- "strings.TrimLeftFunc": Description{Pure: true},
- "strings.TrimPrefix": Description{Pure: true},
- "strings.TrimRight": Description{Pure: true},
- "strings.TrimRightFunc": Description{Pure: true},
- "strings.TrimSpace": Description{Pure: true},
- "strings.TrimSuffix": Description{Pure: true},
-
- "(*net/http.Request).WithContext": Description{Pure: true},
-
- "math/rand.Read": Description{NilError: true},
- "(*math/rand.Rand).Read": Description{NilError: true},
-}
-
-type Description struct {
- // The function is known to be pure
- Pure bool
- // The function is known to be a stub
- Stub bool
- // The function is known to never return (panics notwithstanding)
- Infinite bool
- // Variable ranges
- Ranges vrp.Ranges
- Loops []Loop
- // Function returns an error as its last argument, but it is
- // always nil
- NilError bool
- ConcreteReturnTypes []*types.Tuple
-}
-
-type descriptionEntry struct {
- ready chan struct{}
- result Description
-}
-
-type Descriptions struct {
- CallGraph *callgraph.Graph
- mu sync.Mutex
- cache map[*ssa.Function]*descriptionEntry
-}
-
-func NewDescriptions(prog *ssa.Program) *Descriptions {
- return &Descriptions{
- CallGraph: static.CallGraph(prog),
- cache: map[*ssa.Function]*descriptionEntry{},
- }
-}
-
-func (d *Descriptions) Get(fn *ssa.Function) Description {
- d.mu.Lock()
- fd := d.cache[fn]
- if fd == nil {
- fd = &descriptionEntry{
- ready: make(chan struct{}),
- }
- d.cache[fn] = fd
- d.mu.Unlock()
-
- {
- fd.result = stdlibDescs[fn.RelString(nil)]
- fd.result.Pure = fd.result.Pure || d.IsPure(fn)
- fd.result.Stub = fd.result.Stub || d.IsStub(fn)
- fd.result.Infinite = fd.result.Infinite || !terminates(fn)
- fd.result.Ranges = vrp.BuildGraph(fn).Solve()
- fd.result.Loops = findLoops(fn)
- fd.result.NilError = fd.result.NilError || IsNilError(fn)
- fd.result.ConcreteReturnTypes = concreteReturnTypes(fn)
- }
-
- close(fd.ready)
- } else {
- d.mu.Unlock()
- <-fd.ready
- }
- return fd.result
-}
-
-func IsNilError(fn *ssa.Function) bool {
- // TODO(dh): This is very simplistic, as we only look for constant
- // nil returns. A more advanced approach would work transitively.
- // An even more advanced approach would be context-aware and
- // determine nil errors based on inputs (e.g. io.WriteString to a
- // bytes.Buffer will always return nil, but an io.WriteString to
- // an os.File might not). Similarly, an os.File opened for reading
- // won't error on Close, but other files will.
- res := fn.Signature.Results()
- if res.Len() == 0 {
- return false
- }
- last := res.At(res.Len() - 1)
- if types.TypeString(last.Type(), nil) != "error" {
- return false
- }
-
- if fn.Blocks == nil {
- return false
- }
- for _, block := range fn.Blocks {
- if len(block.Instrs) == 0 {
- continue
- }
- ins := block.Instrs[len(block.Instrs)-1]
- ret, ok := ins.(*ssa.Return)
- if !ok {
- continue
- }
- v := ret.Results[len(ret.Results)-1]
- c, ok := v.(*ssa.Const)
- if !ok {
- return false
- }
- if !c.IsNil() {
- return false
- }
- }
- return true
-}
diff --git a/vendor/honnef.co/go/tools/functions/loops.go b/vendor/honnef.co/go/tools/functions/loops.go
deleted file mode 100644
index 63011cf..0000000
--- a/vendor/honnef.co/go/tools/functions/loops.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package functions
-
-import "honnef.co/go/tools/ssa"
-
-type Loop map[*ssa.BasicBlock]bool
-
-func findLoops(fn *ssa.Function) []Loop {
- if fn.Blocks == nil {
- return nil
- }
- tree := fn.DomPreorder()
- var sets []Loop
- for _, h := range tree {
- for _, n := range h.Preds {
- if !h.Dominates(n) {
- continue
- }
- // n is a back-edge to h
- // h is the loop header
- if n == h {
- sets = append(sets, Loop{n: true})
- continue
- }
- set := Loop{h: true, n: true}
- for _, b := range allPredsBut(n, h, nil) {
- set[b] = true
- }
- sets = append(sets, set)
- }
- }
- return sets
-}
-
-func allPredsBut(b, but *ssa.BasicBlock, list []*ssa.BasicBlock) []*ssa.BasicBlock {
-outer:
- for _, pred := range b.Preds {
- if pred == but {
- continue
- }
- for _, p := range list {
- // TODO improve big-o complexity of this function
- if pred == p {
- continue outer
- }
- }
- list = append(list, pred)
- list = allPredsBut(pred, but, list)
- }
- return list
-}
diff --git a/vendor/honnef.co/go/tools/functions/pure.go b/vendor/honnef.co/go/tools/functions/pure.go
deleted file mode 100644
index d1c4d03..0000000
--- a/vendor/honnef.co/go/tools/functions/pure.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package functions
-
-import (
- "go/token"
- "go/types"
-
- "honnef.co/go/tools/callgraph"
- "honnef.co/go/tools/lint"
- "honnef.co/go/tools/ssa"
-)
-
-// IsStub reports whether a function is a stub. A function is
-// considered a stub if it has no instructions or exactly one
-// instruction, which must be either returning only constant values or
-// a panic.
-func (d *Descriptions) IsStub(fn *ssa.Function) bool {
- if len(fn.Blocks) == 0 {
- return true
- }
- if len(fn.Blocks) > 1 {
- return false
- }
- instrs := lint.FilterDebug(fn.Blocks[0].Instrs)
- if len(instrs) != 1 {
- return false
- }
-
- switch instrs[0].(type) {
- case *ssa.Return:
- // Since this is the only instruction, the return value must
- // be a constant. We consider all constants as stubs, not just
- // the zero value. This does not, unfortunately, cover zero
- // initialised structs, as these cause additional
- // instructions.
- return true
- case *ssa.Panic:
- return true
- default:
- return false
- }
-}
-
-func (d *Descriptions) IsPure(fn *ssa.Function) bool {
- if fn.Signature.Results().Len() == 0 {
- // A function with no return values is empty or is doing some
- // work we cannot see (for example because of build tags);
- // don't consider it pure.
- return false
- }
-
- for _, param := range fn.Params {
- if _, ok := param.Type().Underlying().(*types.Basic); !ok {
- return false
- }
- }
-
- if fn.Blocks == nil {
- return false
- }
- checkCall := func(common *ssa.CallCommon) bool {
- if common.IsInvoke() {
- return false
- }
- builtin, ok := common.Value.(*ssa.Builtin)
- if !ok {
- if common.StaticCallee() != fn {
- if common.StaticCallee() == nil {
- return false
- }
- // TODO(dh): ideally, IsPure wouldn't be responsible
- // for avoiding infinite recursion, but
- // FunctionDescriptions would be.
- node := d.CallGraph.CreateNode(common.StaticCallee())
- if callgraph.PathSearch(node, func(other *callgraph.Node) bool {
- return other.Func == fn
- }) != nil {
- return false
- }
- if !d.Get(common.StaticCallee()).Pure {
- return false
- }
- }
- } else {
- switch builtin.Name() {
- case "len", "cap", "make", "new":
- default:
- return false
- }
- }
- return true
- }
- for _, b := range fn.Blocks {
- for _, ins := range b.Instrs {
- switch ins := ins.(type) {
- case *ssa.Call:
- if !checkCall(ins.Common()) {
- return false
- }
- case *ssa.Defer:
- if !checkCall(&ins.Call) {
- return false
- }
- case *ssa.Select:
- return false
- case *ssa.Send:
- return false
- case *ssa.Go:
- return false
- case *ssa.Panic:
- return false
- case *ssa.Store:
- return false
- case *ssa.FieldAddr:
- return false
- case *ssa.UnOp:
- if ins.Op == token.MUL || ins.Op == token.AND {
- return false
- }
- }
- }
- }
- return true
-}
diff --git a/vendor/honnef.co/go/tools/functions/terminates.go b/vendor/honnef.co/go/tools/functions/terminates.go
deleted file mode 100644
index 65f9e16..0000000
--- a/vendor/honnef.co/go/tools/functions/terminates.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package functions
-
-import "honnef.co/go/tools/ssa"
-
-// terminates reports whether fn is supposed to return, that is if it
-// has at least one theoretic path that returns from the function.
-// Explicit panics do not count as terminating.
-func terminates(fn *ssa.Function) bool {
- if fn.Blocks == nil {
- // assuming that a function terminates is the conservative
- // choice
- return true
- }
-
- for _, block := range fn.Blocks {
- if len(block.Instrs) == 0 {
- continue
- }
- if _, ok := block.Instrs[len(block.Instrs)-1].(*ssa.Return); ok {
- return true
- }
- }
- return false
-}