1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 package facts
37
38 import (
39 "bytes"
40 "encoding/gob"
41 "fmt"
42 "go/types"
43 "io"
44 "log"
45 "reflect"
46 "sort"
47 "sync"
48
49 "golang.org/x/tools/go/analysis"
50 "golang.org/x/tools/go/types/objectpath"
51 )
52
53 const debug = false
54
55
56
57
58
59
60
61
62 type Set struct {
63 pkg *types.Package
64 mu sync.Mutex
65 m map[key]analysis.Fact
66 }
67
68 type key struct {
69 pkg *types.Package
70 obj types.Object
71 t reflect.Type
72 }
73
74
75 func (s *Set) ImportObjectFact(obj types.Object, ptr analysis.Fact) bool {
76 if obj == nil {
77 panic("nil object")
78 }
79 key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(ptr)}
80 s.mu.Lock()
81 defer s.mu.Unlock()
82 if v, ok := s.m[key]; ok {
83 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
84 return true
85 }
86 return false
87 }
88
89
90 func (s *Set) ExportObjectFact(obj types.Object, fact analysis.Fact) {
91 if obj.Pkg() != s.pkg {
92 log.Panicf("in package %s: ExportObjectFact(%s, %T): can't set fact on object belonging another package",
93 s.pkg, obj, fact)
94 }
95 key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(fact)}
96 s.mu.Lock()
97 s.m[key] = fact
98 s.mu.Unlock()
99 }
100
101 func (s *Set) AllObjectFacts(filter map[reflect.Type]bool) []analysis.ObjectFact {
102 var facts []analysis.ObjectFact
103 s.mu.Lock()
104 for k, v := range s.m {
105 if k.obj != nil && filter[k.t] {
106 facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: v})
107 }
108 }
109 s.mu.Unlock()
110 return facts
111 }
112
113
114 func (s *Set) ImportPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
115 if pkg == nil {
116 panic("nil package")
117 }
118 key := key{pkg: pkg, t: reflect.TypeOf(ptr)}
119 s.mu.Lock()
120 defer s.mu.Unlock()
121 if v, ok := s.m[key]; ok {
122 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
123 return true
124 }
125 return false
126 }
127
128
129 func (s *Set) ExportPackageFact(fact analysis.Fact) {
130 key := key{pkg: s.pkg, t: reflect.TypeOf(fact)}
131 s.mu.Lock()
132 s.m[key] = fact
133 s.mu.Unlock()
134 }
135
136 func (s *Set) AllPackageFacts(filter map[reflect.Type]bool) []analysis.PackageFact {
137 var facts []analysis.PackageFact
138 s.mu.Lock()
139 for k, v := range s.m {
140 if k.obj == nil && filter[k.t] {
141 facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: v})
142 }
143 }
144 s.mu.Unlock()
145 return facts
146 }
147
148
149 type gobFact struct {
150 PkgPath string
151 Object objectpath.Path
152 Fact analysis.Fact
153 }
154
155
156
157
158
159
160 type Decoder struct {
161 pkg *types.Package
162 getPackage GetPackageFunc
163 }
164
165
166
167
168
169
170
171 func NewDecoder(pkg *types.Package) *Decoder {
172
173
174 m := importMap(pkg.Imports())
175 getPackageFunc := func(path string) *types.Package { return m[path] }
176 return NewDecoderFunc(pkg, getPackageFunc)
177 }
178
179
180
181
182
183
184
185
186
187 func NewDecoderFunc(pkg *types.Package, getPackage GetPackageFunc) *Decoder {
188 return &Decoder{
189 pkg: pkg,
190 getPackage: getPackage,
191 }
192 }
193
194
195 type GetPackageFunc = func(pkgPath string) *types.Package
196
197
198
199
200
201
202
203
204
205
206
207 func (d *Decoder) Decode(read func(pkgPath string) ([]byte, error)) (*Set, error) {
208
209
210 m := make(map[key]analysis.Fact)
211 for _, imp := range d.pkg.Imports() {
212 logf := func(format string, args ...interface{}) {
213 if debug {
214 prefix := fmt.Sprintf("in %s, importing %s: ",
215 d.pkg.Path(), imp.Path())
216 log.Print(prefix, fmt.Sprintf(format, args...))
217 }
218 }
219
220
221 data, err := read(imp.Path())
222 if err != nil {
223 return nil, fmt.Errorf("in %s, can't import facts for package %q: %v",
224 d.pkg.Path(), imp.Path(), err)
225 }
226 if len(data) == 0 {
227 continue
228 }
229 var gobFacts []gobFact
230 if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil {
231 return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err)
232 }
233 logf("decoded %d facts: %v", len(gobFacts), gobFacts)
234
235
236 for _, f := range gobFacts {
237 factPkg := d.getPackage(f.PkgPath)
238 if factPkg == nil {
239
240
241 logf("no package %q; discarding %v", f.PkgPath, f.Fact)
242 continue
243 }
244 key := key{pkg: factPkg, t: reflect.TypeOf(f.Fact)}
245 if f.Object != "" {
246
247 obj, err := objectpath.Object(factPkg, f.Object)
248 if err != nil {
249
250
251 logf("no object for path: %v; discarding %s", err, f.Fact)
252 continue
253 }
254 key.obj = obj
255 logf("read %T fact %s for %v", f.Fact, f.Fact, key.obj)
256 } else {
257
258 logf("read %T fact %s for %v", f.Fact, f.Fact, factPkg)
259 }
260 m[key] = f.Fact
261 }
262 }
263
264 return &Set{pkg: d.pkg, m: m}, nil
265 }
266
267
268
269
270
271 func (s *Set) Encode() []byte {
272 encoder := new(objectpath.Encoder)
273
274
275
276
277
278 var gobFacts []gobFact
279
280 s.mu.Lock()
281 for k, fact := range s.m {
282 if debug {
283 log.Printf("%v => %s\n", k, fact)
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 if k.pkg != s.pkg {
303 if k.obj == nil {
304 continue
305 }
306 if _, isType := k.obj.(*types.TypeName); !isType &&
307 k.obj.Parent() == k.obj.Pkg().Scope() {
308 continue
309 }
310 }
311
312 var object objectpath.Path
313 if k.obj != nil {
314 path, err := encoder.For(k.obj)
315 if err != nil {
316 if debug {
317 log.Printf("discarding fact %s about %s\n", fact, k.obj)
318 }
319 continue
320 }
321 object = path
322 }
323 gobFacts = append(gobFacts, gobFact{
324 PkgPath: k.pkg.Path(),
325 Object: object,
326 Fact: fact,
327 })
328 }
329 s.mu.Unlock()
330
331
332 sort.Slice(gobFacts, func(i, j int) bool {
333 x, y := gobFacts[i], gobFacts[j]
334 if x.PkgPath != y.PkgPath {
335 return x.PkgPath < y.PkgPath
336 }
337 if x.Object != y.Object {
338 return x.Object < y.Object
339 }
340 tx := reflect.TypeOf(x.Fact)
341 ty := reflect.TypeOf(y.Fact)
342 if tx != ty {
343 return tx.String() < ty.String()
344 }
345 return false
346 })
347
348 var buf bytes.Buffer
349 if len(gobFacts) > 0 {
350 if err := gob.NewEncoder(&buf).Encode(gobFacts); err != nil {
351
352 for _, gf := range gobFacts {
353 if err := gob.NewEncoder(io.Discard).Encode(gf); err != nil {
354 fact := gf.Fact
355 pkgpath := reflect.TypeOf(fact).Elem().PkgPath()
356 log.Panicf("internal error: gob encoding of analysis fact %s failed: %v; please report a bug against fact %T in package %q",
357 fact, err, fact, pkgpath)
358 }
359 }
360 }
361 }
362
363 if debug {
364 log.Printf("package %q: encode %d facts, %d bytes\n",
365 s.pkg.Path(), len(gobFacts), buf.Len())
366 }
367
368 return buf.Bytes()
369 }
370
371
372
373 func (s *Set) String() string {
374 var buf bytes.Buffer
375 buf.WriteString("{")
376 for k, f := range s.m {
377 if buf.Len() > 1 {
378 buf.WriteString(", ")
379 }
380 if k.obj != nil {
381 buf.WriteString(k.obj.String())
382 } else {
383 buf.WriteString(k.pkg.Path())
384 }
385 fmt.Fprintf(&buf, ": %v", f)
386 }
387 buf.WriteString("}")
388 return buf.String()
389 }
390
View as plain text