Source file src/cmd/vendor/golang.org/x/tools/go/analysis/internal/facts/facts.go
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
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
57
58
59
60
61
62
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
72 t reflect.Type
73 }
74
75
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
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
99 s.mu.Unlock()
100 }
101
102
103 func (s *Set) ImportPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
104 if pkg == nil {
105 panic("nil package")
106 }
107 key := key{pkg: pkg, t: reflect.TypeOf(ptr)}
108 s.mu.Lock()
109 defer s.mu.Unlock()
110 if v, ok := s.m[key]; ok {
111 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
112 return true
113 }
114 return false
115 }
116
117
118 func (s *Set) ExportPackageFact(fact analysis.Fact) {
119 key := key{pkg: s.pkg, t: reflect.TypeOf(fact)}
120 s.mu.Lock()
121 s.m[key] = fact
122 s.mu.Unlock()
123 }
124
125
126 type gobFact struct {
127 PkgPath string
128 Object objectpath.Path
129 Fact analysis.Fact
130 }
131
132
133
134
135
136
137
138
139 func Decode(pkg *types.Package, read func(packagePath string) ([]byte, error)) (*Set, error) {
140
141
142 packages := importMap(pkg.Imports())
143
144
145
146 m := make(map[key]analysis.Fact)
147 for _, imp := range pkg.Imports() {
148 logf := func(format string, args ...interface{}) {
149 if debug {
150 prefix := fmt.Sprintf("in %s, importing %s: ",
151 pkg.Path(), imp.Path())
152 log.Print(prefix, fmt.Sprintf(format, args...))
153 }
154 }
155
156
157 data, err := read(imp.Path())
158 if err != nil {
159 return nil, fmt.Errorf("in %s, can't import facts for package %q: %v",
160 pkg.Path(), imp.Path(), err)
161 }
162 if len(data) == 0 {
163 continue
164 }
165 var gobFacts []gobFact
166 if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil {
167 return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err)
168 }
169 if debug {
170 logf("decoded %d facts: %v", len(gobFacts), gobFacts)
171 }
172
173
174 for _, f := range gobFacts {
175 factPkg := packages[f.PkgPath]
176 if factPkg == nil {
177
178
179 logf("no package %q; discarding %v", f.PkgPath, f.Fact)
180 continue
181 }
182 key := key{pkg: factPkg, t: reflect.TypeOf(f.Fact)}
183 if f.Object != "" {
184
185 obj, err := objectpath.Object(factPkg, f.Object)
186 if err != nil {
187
188
189 logf("no object for path: %v; discarding %s", err, f.Fact)
190 continue
191 }
192 key.obj = obj
193 logf("read %T fact %s for %v", f.Fact, f.Fact, key.obj)
194 } else {
195
196 logf("read %T fact %s for %v", f.Fact, f.Fact, factPkg)
197 }
198 m[key] = f.Fact
199 }
200 }
201
202 return &Set{pkg: pkg, m: m}, nil
203 }
204
205
206
207
208
209 func (s *Set) Encode() []byte {
210
211
212
213
214
215 var gobFacts []gobFact
216
217 s.mu.Lock()
218 for k, fact := range s.m {
219 if debug {
220 log.Printf("%v => %s\n", k, fact)
221 }
222 var object objectpath.Path
223 if k.obj != nil {
224 path, err := objectpath.For(k.obj)
225 if err != nil {
226 if debug {
227 log.Printf("discarding fact %s about %s\n", fact, k.obj)
228 }
229 continue
230 }
231 object = path
232 }
233 gobFacts = append(gobFacts, gobFact{
234 PkgPath: k.pkg.Path(),
235 Object: object,
236 Fact: fact,
237 })
238 }
239 s.mu.Unlock()
240
241
242 sort.Slice(gobFacts, func(i, j int) bool {
243 x, y := gobFacts[i], gobFacts[j]
244 if x.PkgPath != y.PkgPath {
245 return x.PkgPath < y.PkgPath
246 }
247 if x.Object != y.Object {
248 return x.Object < y.Object
249 }
250 tx := reflect.TypeOf(x.Fact)
251 ty := reflect.TypeOf(y.Fact)
252 if tx != ty {
253 return tx.String() < ty.String()
254 }
255 return false
256 })
257
258 var buf bytes.Buffer
259 if len(gobFacts) > 0 {
260 if err := gob.NewEncoder(&buf).Encode(gobFacts); err != nil {
261
262 for _, gf := range gobFacts {
263 if err := gob.NewEncoder(ioutil.Discard).Encode(gf); err != nil {
264 fact := gf.Fact
265 pkgpath := reflect.TypeOf(fact).Elem().PkgPath()
266 log.Panicf("internal error: gob encoding of analysis fact %s failed: %v; please report a bug against fact %T in package %q",
267 fact, err, fact, pkgpath)
268 }
269 }
270 }
271 }
272
273 if debug {
274 log.Printf("package %q: encode %d facts, %d bytes\n",
275 s.pkg.Path(), len(gobFacts), buf.Len())
276 }
277
278 return buf.Bytes()
279 }
280
281
282
283 func (s *Set) String() string {
284 var buf bytes.Buffer
285 buf.WriteString("{")
286 for k, f := range s.m {
287 if buf.Len() > 1 {
288 buf.WriteString(", ")
289 }
290 if k.obj != nil {
291 buf.WriteString(k.obj.String())
292 } else {
293 buf.WriteString(k.pkg.Path())
294 }
295 fmt.Fprintf(&buf, ": %v", f)
296 }
297 buf.WriteString("}")
298 return buf.String()
299 }
300
View as plain text