Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / analysis / internal / facts / facts.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package facts defines a serializable set of analysis.Fact.
6 //
7 // It provides a partial implementation of the Fact-related parts of the
8 // analysis.Pass interface for use in analysis drivers such as "go vet"
9 // and other build systems.
10 //
11 // The serial format is unspecified and may change, so the same version
12 // of this package must be used for reading and writing serialized facts.
13 //
14 // The handling of facts in the analysis system parallels the handling
15 // of type information in the compiler: during compilation of package P,
16 // the compiler emits an export data file that describes the type of
17 // every object (named thing) defined in package P, plus every object
18 // indirectly reachable from one of those objects. Thus the downstream
19 // compiler of package Q need only load one export data file per direct
20 // import of Q, and it will learn everything about the API of package P
21 // and everything it needs to know about the API of P's dependencies.
22 //
23 // Similarly, analysis of package P emits a fact set containing facts
24 // about all objects exported from P, plus additional facts about only
25 // those objects of P's dependencies that are reachable from the API of
26 // package P; the downstream analysis of Q need only load one fact set
27 // per direct import of Q.
28 //
29 // The notion of "exportedness" that matters here is that of the
30 // compiler. According to the language spec, a method pkg.T.f is
31 // unexported simply because its name starts with lowercase. But the
32 // compiler must nonetheless export f so that downstream compilations can
33 // accurately ascertain whether pkg.T implements an interface pkg.I
34 // defined as interface{f()}. Exported thus means "described in export
35 // data".
36 //
37 package facts
38
39 import (
40         "bytes"
41         "encoding/gob"
42         "fmt"
43         "go/types"
44         "io/ioutil"
45         "log"
46         "reflect"
47         "sort"
48         "sync"
49
50         "golang.org/x/tools/go/analysis"
51         "golang.org/x/tools/go/types/objectpath"
52 )
53
54 const debug = false
55
56 // A Set is a set of analysis.Facts.
57 //
58 // Decode creates a Set of facts by reading from the imports of a given
59 // package, and Encode writes out the set. Between these operation,
60 // the Import and Export methods will query and update the set.
61 //
62 // All of Set's methods except String are safe to call concurrently.
63 type Set struct {
64         pkg *types.Package
65         mu  sync.Mutex
66         m   map[key]analysis.Fact
67 }
68
69 type key struct {
70         pkg *types.Package
71         obj types.Object // (object facts only)
72         t   reflect.Type
73 }
74
75 // ImportObjectFact implements analysis.Pass.ImportObjectFact.
76 func (s *Set) ImportObjectFact(obj types.Object, ptr analysis.Fact) bool {
77         if obj == nil {
78                 panic("nil object")
79         }
80         key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(ptr)}
81         s.mu.Lock()
82         defer s.mu.Unlock()
83         if v, ok := s.m[key]; ok {
84                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
85                 return true
86         }
87         return false
88 }
89
90 // ExportObjectFact implements analysis.Pass.ExportObjectFact.
91 func (s *Set) ExportObjectFact(obj types.Object, fact analysis.Fact) {
92         if obj.Pkg() != s.pkg {
93                 log.Panicf("in package %s: ExportObjectFact(%s, %T): can't set fact on object belonging another package",
94                         s.pkg, obj, fact)
95         }
96         key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(fact)}
97         s.mu.Lock()
98         s.m[key] = fact // clobber any existing entry
99         s.mu.Unlock()
100 }
101
102 func (s *Set) AllObjectFacts(filter map[reflect.Type]bool) []analysis.ObjectFact {
103         var facts []analysis.ObjectFact
104         s.mu.Lock()
105         for k, v := range s.m {
106                 if k.obj != nil && filter[k.t] {
107                         facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: v})
108                 }
109         }
110         s.mu.Unlock()
111         return facts
112 }
113
114 // ImportPackageFact implements analysis.Pass.ImportPackageFact.
115 func (s *Set) ImportPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
116         if pkg == nil {
117                 panic("nil package")
118         }
119         key := key{pkg: pkg, t: reflect.TypeOf(ptr)}
120         s.mu.Lock()
121         defer s.mu.Unlock()
122         if v, ok := s.m[key]; ok {
123                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
124                 return true
125         }
126         return false
127 }
128
129 // ExportPackageFact implements analysis.Pass.ExportPackageFact.
130 func (s *Set) ExportPackageFact(fact analysis.Fact) {
131         key := key{pkg: s.pkg, t: reflect.TypeOf(fact)}
132         s.mu.Lock()
133         s.m[key] = fact // clobber any existing entry
134         s.mu.Unlock()
135 }
136
137 func (s *Set) AllPackageFacts(filter map[reflect.Type]bool) []analysis.PackageFact {
138         var facts []analysis.PackageFact
139         s.mu.Lock()
140         for k, v := range s.m {
141                 if k.obj == nil && filter[k.t] {
142                         facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: v})
143                 }
144         }
145         s.mu.Unlock()
146         return facts
147 }
148
149 // gobFact is the Gob declaration of a serialized fact.
150 type gobFact struct {
151         PkgPath string          // path of package
152         Object  objectpath.Path // optional path of object relative to package itself
153         Fact    analysis.Fact   // type and value of user-defined Fact
154 }
155
156 // Decode decodes all the facts relevant to the analysis of package pkg.
157 // The read function reads serialized fact data from an external source
158 // for one of of pkg's direct imports. The empty file is a valid
159 // encoding of an empty fact set.
160 //
161 // It is the caller's responsibility to call gob.Register on all
162 // necessary fact types.
163 func Decode(pkg *types.Package, read func(packagePath string) ([]byte, error)) (*Set, error) {
164         // Compute the import map for this package.
165         // See the package doc comment.
166         packages := importMap(pkg.Imports())
167
168         // Read facts from imported packages.
169         // Facts may describe indirectly imported packages, or their objects.
170         m := make(map[key]analysis.Fact) // one big bucket
171         for _, imp := range pkg.Imports() {
172                 logf := func(format string, args ...interface{}) {
173                         if debug {
174                                 prefix := fmt.Sprintf("in %s, importing %s: ",
175                                         pkg.Path(), imp.Path())
176                                 log.Print(prefix, fmt.Sprintf(format, args...))
177                         }
178                 }
179
180                 // Read the gob-encoded facts.
181                 data, err := read(imp.Path())
182                 if err != nil {
183                         return nil, fmt.Errorf("in %s, can't import facts for package %q: %v",
184                                 pkg.Path(), imp.Path(), err)
185                 }
186                 if len(data) == 0 {
187                         continue // no facts
188                 }
189                 var gobFacts []gobFact
190                 if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil {
191                         return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err)
192                 }
193                 if debug {
194                         logf("decoded %d facts: %v", len(gobFacts), gobFacts)
195                 }
196
197                 // Parse each one into a key and a Fact.
198                 for _, f := range gobFacts {
199                         factPkg := packages[f.PkgPath]
200                         if factPkg == nil {
201                                 // Fact relates to a dependency that was
202                                 // unused in this translation unit. Skip.
203                                 logf("no package %q; discarding %v", f.PkgPath, f.Fact)
204                                 continue
205                         }
206                         key := key{pkg: factPkg, t: reflect.TypeOf(f.Fact)}
207                         if f.Object != "" {
208                                 // object fact
209                                 obj, err := objectpath.Object(factPkg, f.Object)
210                                 if err != nil {
211                                         // (most likely due to unexported object)
212                                         // TODO(adonovan): audit for other possibilities.
213                                         logf("no object for path: %v; discarding %s", err, f.Fact)
214                                         continue
215                                 }
216                                 key.obj = obj
217                                 logf("read %T fact %s for %v", f.Fact, f.Fact, key.obj)
218                         } else {
219                                 // package fact
220                                 logf("read %T fact %s for %v", f.Fact, f.Fact, factPkg)
221                         }
222                         m[key] = f.Fact
223                 }
224         }
225
226         return &Set{pkg: pkg, m: m}, nil
227 }
228
229 // Encode encodes a set of facts to a memory buffer.
230 //
231 // It may fail if one of the Facts could not be gob-encoded, but this is
232 // a sign of a bug in an Analyzer.
233 func (s *Set) Encode() []byte {
234
235         // TODO(adonovan): opt: use a more efficient encoding
236         // that avoids repeating PkgPath for each fact.
237
238         // Gather all facts, including those from imported packages.
239         var gobFacts []gobFact
240
241         s.mu.Lock()
242         for k, fact := range s.m {
243                 if debug {
244                         log.Printf("%v => %s\n", k, fact)
245                 }
246                 var object objectpath.Path
247                 if k.obj != nil {
248                         path, err := objectpath.For(k.obj)
249                         if err != nil {
250                                 if debug {
251                                         log.Printf("discarding fact %s about %s\n", fact, k.obj)
252                                 }
253                                 continue // object not accessible from package API; discard fact
254                         }
255                         object = path
256                 }
257                 gobFacts = append(gobFacts, gobFact{
258                         PkgPath: k.pkg.Path(),
259                         Object:  object,
260                         Fact:    fact,
261                 })
262         }
263         s.mu.Unlock()
264
265         // Sort facts by (package, object, type) for determinism.
266         sort.Slice(gobFacts, func(i, j int) bool {
267                 x, y := gobFacts[i], gobFacts[j]
268                 if x.PkgPath != y.PkgPath {
269                         return x.PkgPath < y.PkgPath
270                 }
271                 if x.Object != y.Object {
272                         return x.Object < y.Object
273                 }
274                 tx := reflect.TypeOf(x.Fact)
275                 ty := reflect.TypeOf(y.Fact)
276                 if tx != ty {
277                         return tx.String() < ty.String()
278                 }
279                 return false // equal
280         })
281
282         var buf bytes.Buffer
283         if len(gobFacts) > 0 {
284                 if err := gob.NewEncoder(&buf).Encode(gobFacts); err != nil {
285                         // Fact encoding should never fail. Identify the culprit.
286                         for _, gf := range gobFacts {
287                                 if err := gob.NewEncoder(ioutil.Discard).Encode(gf); err != nil {
288                                         fact := gf.Fact
289                                         pkgpath := reflect.TypeOf(fact).Elem().PkgPath()
290                                         log.Panicf("internal error: gob encoding of analysis fact %s failed: %v; please report a bug against fact %T in package %q",
291                                                 fact, err, fact, pkgpath)
292                                 }
293                         }
294                 }
295         }
296
297         if debug {
298                 log.Printf("package %q: encode %d facts, %d bytes\n",
299                         s.pkg.Path(), len(gobFacts), buf.Len())
300         }
301
302         return buf.Bytes()
303 }
304
305 // String is provided only for debugging, and must not be called
306 // concurrent with any Import/Export method.
307 func (s *Set) String() string {
308         var buf bytes.Buffer
309         buf.WriteString("{")
310         for k, f := range s.m {
311                 if buf.Len() > 1 {
312                         buf.WriteString(", ")
313                 }
314                 if k.obj != nil {
315                         buf.WriteString(k.obj.String())
316                 } else {
317                         buf.WriteString(k.pkg.Path())
318                 }
319                 fmt.Fprintf(&buf, ": %v", f)
320         }
321         buf.WriteString("}")
322         return buf.String()
323 }