.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / analysis / facts / typedness / typedness.go
1 package typedness
2
3 import (
4         "fmt"
5         "go/token"
6         "go/types"
7         "reflect"
8
9         "honnef.co/go/tools/go/ir"
10         "honnef.co/go/tools/go/ir/irutil"
11         "honnef.co/go/tools/internal/passes/buildir"
12
13         "golang.org/x/tools/go/analysis"
14 )
15
16 // alwaysTypedFact denotes that a function's return value will never
17 // be untyped nil. The analysis errs on the side of false negatives.
18 type alwaysTypedFact struct {
19         Rets uint8
20 }
21
22 func (*alwaysTypedFact) AFact() {}
23 func (fact *alwaysTypedFact) String() string {
24         return fmt.Sprintf("always typed: %08b", fact.Rets)
25 }
26
27 type Result struct {
28         m map[*types.Func]uint8
29 }
30
31 var Analysis = &analysis.Analyzer{
32         Name:       "typedness",
33         Doc:        "Annotates return values that are always typed values",
34         Run:        run,
35         Requires:   []*analysis.Analyzer{buildir.Analyzer},
36         FactTypes:  []analysis.Fact{(*alwaysTypedFact)(nil)},
37         ResultType: reflect.TypeOf((*Result)(nil)),
38 }
39
40 // MustReturnTyped reports whether the ret's return value of fn must
41 // be a typed value, i.e. an interface value containing a concrete
42 // type or trivially a concrete type. The value of ret is zero-based.
43 //
44 // The analysis has false negatives: MustReturnTyped may incorrectly
45 // report false, but never incorrectly reports true.
46 func (r *Result) MustReturnTyped(fn *types.Func, ret int) bool {
47         if _, ok := fn.Type().(*types.Signature).Results().At(ret).Type().Underlying().(*types.Interface); !ok {
48                 return true
49         }
50         return (r.m[fn] & (1 << ret)) != 0
51 }
52
53 func run(pass *analysis.Pass) (interface{}, error) {
54         seen := map[*ir.Function]struct{}{}
55         out := &Result{
56                 m: map[*types.Func]uint8{},
57         }
58         for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
59                 impl(pass, fn, seen)
60         }
61
62         for _, fact := range pass.AllObjectFacts() {
63                 out.m[fact.Object.(*types.Func)] = fact.Fact.(*alwaysTypedFact).Rets
64         }
65
66         return out, nil
67 }
68
69 func impl(pass *analysis.Pass, fn *ir.Function, seenFns map[*ir.Function]struct{}) (out uint8) {
70         if fn.Signature.Results().Len() > 8 {
71                 return 0
72         }
73         if fn.Object() == nil {
74                 // TODO(dh): support closures
75                 return 0
76         }
77         if fact := new(alwaysTypedFact); pass.ImportObjectFact(fn.Object(), fact) {
78                 return fact.Rets
79         }
80         if fn.Pkg != pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg {
81                 return 0
82         }
83         if fn.Blocks == nil {
84                 return 0
85         }
86         if irutil.IsStub(fn) {
87                 return 0
88         }
89         if _, ok := seenFns[fn]; ok {
90                 // break recursion
91                 return 0
92         }
93
94         seenFns[fn] = struct{}{}
95         defer func() {
96                 for i := 0; i < fn.Signature.Results().Len(); i++ {
97                         if _, ok := fn.Signature.Results().At(i).Type().Underlying().(*types.Interface); !ok {
98                                 // we don't need facts to know that non-interface
99                                 // types can't be untyped nil. zeroing out those bits
100                                 // may result in all bits being zero, in which case we
101                                 // don't have to save any fact.
102                                 out &= ^(1 << i)
103                         }
104                 }
105                 if out > 0 {
106                         pass.ExportObjectFact(fn.Object(), &alwaysTypedFact{out})
107                 }
108         }()
109
110         isUntypedNil := func(v ir.Value) bool {
111                 k, ok := v.(*ir.Const)
112                 if !ok {
113                         return false
114                 }
115                 if _, ok := k.Type().Underlying().(*types.Interface); !ok {
116                         return false
117                 }
118                 return k.Value == nil
119         }
120
121         var do func(v ir.Value, seen map[ir.Value]struct{}) bool
122         do = func(v ir.Value, seen map[ir.Value]struct{}) bool {
123                 if _, ok := seen[v]; ok {
124                         // break cycle
125                         return false
126                 }
127                 seen[v] = struct{}{}
128                 switch v := v.(type) {
129                 case *ir.Const:
130                         // can't be a typed nil, because then we'd be returning the
131                         // result of MakeInterface.
132                         return false
133                 case *ir.ChangeInterface:
134                         return do(v.X, seen)
135                 case *ir.Extract:
136                         call, ok := v.Tuple.(*ir.Call)
137                         if !ok {
138                                 // We only care about extracts of function results. For
139                                 // everything else (e.g. channel receives and map
140                                 // lookups), we can either not deduce any information, or
141                                 // will see a MakeInterface.
142                                 return false
143                         }
144                         if callee := call.Call.StaticCallee(); callee != nil {
145                                 return impl(pass, callee, seenFns)&(1<<v.Index) != 0
146                         } else {
147                                 // we don't know what function we're calling. no need
148                                 // to look at the signature, though. if it weren't an
149                                 // interface, we'd be seeing a MakeInterface
150                                 // instruction.
151                                 return false
152                         }
153                 case *ir.Call:
154                         if callee := v.Call.StaticCallee(); callee != nil {
155                                 return impl(pass, callee, seenFns)&1 != 0
156                         } else {
157                                 // we don't know what function we're calling. no need
158                                 // to look at the signature, though. if it weren't an
159                                 // interface, we'd be seeing a MakeInterface
160                                 // instruction.
161                                 return false
162                         }
163                 case *ir.Sigma:
164                         iff, ok := v.From.Control().(*ir.If)
165                         if !ok {
166                                 // give up
167                                 return false
168                         }
169
170                         binop, ok := iff.Cond.(*ir.BinOp)
171                         if !ok {
172                                 // give up
173                                 return false
174                         }
175
176                         if (binop.X == v.X && isUntypedNil(binop.Y)) || (isUntypedNil(binop.X) && binop.Y == v.X) {
177                                 op := binop.Op
178                                 if v.From.Succs[0] != v.Block() {
179                                         // we're in the false branch, negate op
180                                         switch op {
181                                         case token.EQL:
182                                                 op = token.NEQ
183                                         case token.NEQ:
184                                                 op = token.EQL
185                                         default:
186                                                 panic(fmt.Sprintf("internal error: unhandled token %v", op))
187                                         }
188                                 }
189
190                                 switch op {
191                                 case token.EQL:
192                                         // returned value equals untyped nil
193                                         return false
194                                 case token.NEQ:
195                                         // returned value does not equal untyped nil
196                                         return true
197                                 default:
198                                         panic(fmt.Sprintf("internal error: unhandled token %v", op))
199                                 }
200                         }
201
202                         // TODO(dh): handle comparison with typed nil
203
204                         // give up
205                         return false
206                 case *ir.Phi:
207                         for _, pv := range v.Edges {
208                                 if !do(pv, seen) {
209                                         return false
210                                 }
211                         }
212                         return true
213                 case *ir.MakeInterface:
214                         return true
215                 case *ir.TypeAssert:
216                         // type assertions fail for untyped nils. Either we have a
217                         // single lhs and the type assertion succeeds or panics,
218                         // or we have two lhs and we'll return Extract instead.
219                         return true
220                 case *ir.ChangeType:
221                         // we'll only see interface->interface conversions, which
222                         // don't tell us anything about the nilness.
223                         return false
224                 case *ir.MapLookup, *ir.Index, *ir.Recv, *ir.Parameter, *ir.Load, *ir.Field:
225                         // All other instructions that tell us nothing about the
226                         // typedness of interface values.
227                         return false
228                 default:
229                         panic(fmt.Sprintf("internal error: unhandled type %T", v))
230                 }
231         }
232
233         ret := fn.Exit.Control().(*ir.Return)
234         for i, v := range ret.Results {
235                 if _, ok := fn.Signature.Results().At(i).Type().Underlying().(*types.Interface); ok {
236                         if do(v, map[ir.Value]struct{}{}) {
237                                 out |= 1 << i
238                         }
239                 }
240         }
241         return out
242 }