diff options
| author | Joseph Richey <joerichey@google.com> | 2018-08-30 13:41:49 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-30 13:41:49 -0700 |
| commit | 0f451a722918f39fa07bd9337e4a14ca154b13ae (patch) | |
| tree | 9868ffed8cb74357a06e63b88c56d71b13b415af /vendor/honnef.co/go/tools/functions | |
| parent | 1e1b67dae6c3ae3b5acb5ce377b01b286c3e676b (diff) | |
| parent | 1c9bafdec78b8f238a82314b6d9c566a951486c2 (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.go | 56 | ||||
| -rw-r--r-- | vendor/honnef.co/go/tools/functions/functions.go | 150 | ||||
| -rw-r--r-- | vendor/honnef.co/go/tools/functions/loops.go | 50 | ||||
| -rw-r--r-- | vendor/honnef.co/go/tools/functions/pure.go | 123 | ||||
| -rw-r--r-- | vendor/honnef.co/go/tools/functions/terminates.go | 24 |
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 -} |