aboutsummaryrefslogtreecommitdiff
path: root/vendor/honnef.co/go/tools/functions/pure.go
diff options
context:
space:
mode:
authorJoseph Richey <joerichey@google.com>2018-02-11 21:43:56 -0800
committerGitHub <noreply@github.com>2018-02-11 21:43:56 -0800
commit8b6cbfcca9d1f3fb5b05a91b4ac0bca66f75f19e (patch)
tree5f6fdc40c7518bc23a63fdac9a92b516dd0c6d36 /vendor/honnef.co/go/tools/functions/pure.go
parentaebae1aae2fc61185a8bbc96313d8462727ad202 (diff)
parentb330463662825a7d7b22efabb2b7a40640d2b18e (diff)
Merge pull request #85 from google/depfix
Complete the new Build System
Diffstat (limited to 'vendor/honnef.co/go/tools/functions/pure.go')
-rw-r--r--vendor/honnef.co/go/tools/functions/pure.go123
1 files changed, 123 insertions, 0 deletions
diff --git a/vendor/honnef.co/go/tools/functions/pure.go b/vendor/honnef.co/go/tools/functions/pure.go
new file mode 100644
index 0000000..d1c4d03
--- /dev/null
+++ b/vendor/honnef.co/go/tools/functions/pure.go
@@ -0,0 +1,123 @@
+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
+}