gitee.com/wgliang/goreporter@v0.0.0-20180902115603-df1b20f7c5d0/linters/staticcheck/functions/pure.go (about) 1 package functions 2 3 import ( 4 "go/token" 5 "go/types" 6 7 "github.com/360EntSecGroup-Skylar/goreporter/linters/simpler/ssa" 8 "github.com/360EntSecGroup-Skylar/goreporter/linters/staticcheck/callgraph" 9 ) 10 11 func (d *Descriptions) IsPure(fn *ssa.Function) bool { 12 if fn.Signature.Results().Len() == 0 { 13 // A function with no return values is empty or is doing some 14 // work we cannot see (for example because of build tags); 15 // don't consider it pure. 16 return false 17 } 18 19 for _, param := range fn.Params { 20 if _, ok := param.Type().Underlying().(*types.Basic); !ok { 21 return false 22 } 23 } 24 25 if fn.Blocks == nil { 26 return false 27 } 28 checkCall := func(common *ssa.CallCommon) bool { 29 if common.IsInvoke() { 30 return false 31 } 32 builtin, ok := common.Value.(*ssa.Builtin) 33 if !ok { 34 if common.StaticCallee() != fn { 35 if common.StaticCallee() == nil { 36 return false 37 } 38 // TODO(dh): ideally, IsPure wouldn't be responsible 39 // for avoiding infinite recursion, but 40 // FunctionDescriptions would be. 41 node := d.CallGraph.CreateNode(common.StaticCallee()) 42 if callgraph.PathSearch(node, func(other *callgraph.Node) bool { 43 return other.Func == fn 44 }) != nil { 45 return false 46 } 47 if !d.Get(common.StaticCallee()).Pure { 48 return false 49 } 50 } 51 } else { 52 switch builtin.Name() { 53 case "len", "cap", "make", "new": 54 default: 55 return false 56 } 57 } 58 return true 59 } 60 for _, b := range fn.Blocks { 61 for _, ins := range b.Instrs { 62 switch ins := ins.(type) { 63 case *ssa.Call: 64 if !checkCall(ins.Common()) { 65 return false 66 } 67 case *ssa.Defer: 68 if !checkCall(&ins.Call) { 69 return false 70 } 71 case *ssa.Select: 72 return false 73 case *ssa.Send: 74 return false 75 case *ssa.Go: 76 return false 77 case *ssa.Panic: 78 return false 79 case *ssa.Store: 80 return false 81 case *ssa.FieldAddr: 82 return false 83 case *ssa.UnOp: 84 if ins.Op == token.MUL || ins.Op == token.AND { 85 return false 86 } 87 } 88 } 89 } 90 return true 91 }