Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / cache / analysis.go
1 // Copyright 2019 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 cache
6
7 import (
8         "context"
9         "fmt"
10         "go/ast"
11         "go/types"
12         "reflect"
13         "sort"
14         "sync"
15
16         "golang.org/x/sync/errgroup"
17         "golang.org/x/tools/go/analysis"
18         "golang.org/x/tools/internal/analysisinternal"
19         "golang.org/x/tools/internal/event"
20         "golang.org/x/tools/internal/lsp/debug/tag"
21         "golang.org/x/tools/internal/lsp/source"
22         "golang.org/x/tools/internal/memoize"
23         errors "golang.org/x/xerrors"
24 )
25
26 func (s *snapshot) Analyze(ctx context.Context, id string, analyzers ...*analysis.Analyzer) ([]*source.Error, error) {
27         var roots []*actionHandle
28
29         for _, a := range analyzers {
30                 ah, err := s.actionHandle(ctx, packageID(id), a)
31                 if err != nil {
32                         return nil, err
33                 }
34                 roots = append(roots, ah)
35         }
36
37         // Check if the context has been canceled before running the analyses.
38         if ctx.Err() != nil {
39                 return nil, ctx.Err()
40         }
41
42         var results []*source.Error
43         for _, ah := range roots {
44                 diagnostics, _, err := ah.analyze(ctx, s)
45                 if err != nil {
46                         return nil, err
47                 }
48                 results = append(results, diagnostics...)
49         }
50         return results, nil
51 }
52
53 type actionHandleKey string
54
55 // An action represents one unit of analysis work: the application of
56 // one analysis to one package. Actions form a DAG, both within a
57 // package (as different analyzers are applied, either in sequence or
58 // parallel), and across packages (as dependencies are analyzed).
59 type actionHandle struct {
60         handle *memoize.Handle
61
62         analyzer *analysis.Analyzer
63         pkg      *pkg
64 }
65
66 type actionData struct {
67         diagnostics  []*source.Error
68         result       interface{}
69         objectFacts  map[objectFactKey]analysis.Fact
70         packageFacts map[packageFactKey]analysis.Fact
71         err          error
72 }
73
74 type objectFactKey struct {
75         obj types.Object
76         typ reflect.Type
77 }
78
79 type packageFactKey struct {
80         pkg *types.Package
81         typ reflect.Type
82 }
83
84 func (s *snapshot) actionHandle(ctx context.Context, id packageID, a *analysis.Analyzer) (*actionHandle, error) {
85         ph := s.getPackage(id, source.ParseFull)
86         if ph == nil {
87                 return nil, errors.Errorf("no package for %s", id)
88         }
89         act := s.getActionHandle(id, ph.mode, a)
90         if act != nil {
91                 return act, nil
92         }
93         if len(ph.key) == 0 {
94                 return nil, errors.Errorf("no key for package %s", id)
95         }
96         pkg, err := ph.check(ctx, s)
97         if err != nil {
98                 return nil, err
99         }
100         act = &actionHandle{
101                 analyzer: a,
102                 pkg:      pkg,
103         }
104         var deps []*actionHandle
105         // Add a dependency on each required analyzers.
106         for _, req := range a.Requires {
107                 reqActionHandle, err := s.actionHandle(ctx, id, req)
108                 if err != nil {
109                         return nil, err
110                 }
111                 deps = append(deps, reqActionHandle)
112         }
113
114         // TODO(golang/go#35089): Re-enable this when we doesn't use ParseExported
115         // mode for dependencies. In the meantime, disable analysis for dependencies,
116         // since we don't get anything useful out of it.
117         if false {
118                 // An analysis that consumes/produces facts
119                 // must run on the package's dependencies too.
120                 if len(a.FactTypes) > 0 {
121                         importIDs := make([]string, 0, len(ph.m.deps))
122                         for _, importID := range ph.m.deps {
123                                 importIDs = append(importIDs, string(importID))
124                         }
125                         sort.Strings(importIDs) // for determinism
126                         for _, importID := range importIDs {
127                                 depActionHandle, err := s.actionHandle(ctx, packageID(importID), a)
128                                 if err != nil {
129                                         return nil, err
130                                 }
131                                 deps = append(deps, depActionHandle)
132                         }
133                 }
134         }
135
136         h := s.generation.Bind(buildActionKey(a, ph), func(ctx context.Context, arg memoize.Arg) interface{} {
137                 snapshot := arg.(*snapshot)
138                 // Analyze dependencies first.
139                 results, err := execAll(ctx, snapshot, deps)
140                 if err != nil {
141                         return &actionData{
142                                 err: err,
143                         }
144                 }
145                 return runAnalysis(ctx, snapshot, a, pkg, results)
146         })
147         act.handle = h
148
149         act = s.addActionHandle(act)
150         return act, nil
151 }
152
153 func (act *actionHandle) analyze(ctx context.Context, snapshot *snapshot) ([]*source.Error, interface{}, error) {
154         d, err := act.handle.Get(ctx, snapshot.generation, snapshot)
155         if err != nil {
156                 return nil, nil, err
157         }
158         data, ok := d.(*actionData)
159         if !ok {
160                 return nil, nil, errors.Errorf("unexpected type for %s:%s", act.pkg.ID(), act.analyzer.Name)
161         }
162         if data == nil {
163                 return nil, nil, errors.Errorf("unexpected nil analysis for %s:%s", act.pkg.ID(), act.analyzer.Name)
164         }
165         return data.diagnostics, data.result, data.err
166 }
167
168 func buildActionKey(a *analysis.Analyzer, ph *packageHandle) actionHandleKey {
169         return actionHandleKey(hashContents([]byte(fmt.Sprintf("%p %s", a, string(ph.key)))))
170 }
171
172 func (act *actionHandle) String() string {
173         return fmt.Sprintf("%s@%s", act.analyzer, act.pkg.PkgPath())
174 }
175
176 func execAll(ctx context.Context, snapshot *snapshot, actions []*actionHandle) (map[*actionHandle]*actionData, error) {
177         var mu sync.Mutex
178         results := make(map[*actionHandle]*actionData)
179
180         g, ctx := errgroup.WithContext(ctx)
181         for _, act := range actions {
182                 act := act
183                 g.Go(func() error {
184                         v, err := act.handle.Get(ctx, snapshot.generation, snapshot)
185                         if err != nil {
186                                 return err
187                         }
188                         data, ok := v.(*actionData)
189                         if !ok {
190                                 return errors.Errorf("unexpected type for %s: %T", act, v)
191                         }
192
193                         mu.Lock()
194                         defer mu.Unlock()
195                         results[act] = data
196
197                         return nil
198                 })
199         }
200         return results, g.Wait()
201 }
202
203 func runAnalysis(ctx context.Context, snapshot *snapshot, analyzer *analysis.Analyzer, pkg *pkg, deps map[*actionHandle]*actionData) (data *actionData) {
204         data = &actionData{
205                 objectFacts:  make(map[objectFactKey]analysis.Fact),
206                 packageFacts: make(map[packageFactKey]analysis.Fact),
207         }
208         defer func() {
209                 if r := recover(); r != nil {
210                         event.Log(ctx, fmt.Sprintf("analysis panicked: %s", r), tag.Package.Of(pkg.PkgPath()))
211                         data.err = errors.Errorf("analysis %s for package %s panicked: %v", analyzer.Name, pkg.PkgPath(), r)
212                 }
213         }()
214
215         // Plumb the output values of the dependencies
216         // into the inputs of this action.  Also facts.
217         inputs := make(map[*analysis.Analyzer]interface{})
218
219         for depHandle, depData := range deps {
220                 if depHandle.pkg == pkg {
221                         // Same package, different analysis (horizontal edge):
222                         // in-memory outputs of prerequisite analyzers
223                         // become inputs to this analysis pass.
224                         inputs[depHandle.analyzer] = depData.result
225                 } else if depHandle.analyzer == analyzer { // (always true)
226                         // Same analysis, different package (vertical edge):
227                         // serialized facts produced by prerequisite analysis
228                         // become available to this analysis pass.
229                         for key, fact := range depData.objectFacts {
230                                 // Filter out facts related to objects
231                                 // that are irrelevant downstream
232                                 // (equivalently: not in the compiler export data).
233                                 if !exportedFrom(key.obj, depHandle.pkg.types) {
234                                         continue
235                                 }
236                                 data.objectFacts[key] = fact
237                         }
238                         for key, fact := range depData.packageFacts {
239                                 // TODO: filter out facts that belong to
240                                 // packages not mentioned in the export data
241                                 // to prevent side channels.
242
243                                 data.packageFacts[key] = fact
244                         }
245                 }
246         }
247
248         var syntax []*ast.File
249         for _, cgf := range pkg.compiledGoFiles {
250                 syntax = append(syntax, cgf.File)
251         }
252
253         var diagnostics []*analysis.Diagnostic
254
255         // Run the analysis.
256         pass := &analysis.Pass{
257                 Analyzer:   analyzer,
258                 Fset:       snapshot.view.session.cache.fset,
259                 Files:      syntax,
260                 Pkg:        pkg.GetTypes(),
261                 TypesInfo:  pkg.GetTypesInfo(),
262                 TypesSizes: pkg.GetTypesSizes(),
263                 ResultOf:   inputs,
264                 Report: func(d analysis.Diagnostic) {
265                         // Prefix the diagnostic category with the analyzer's name.
266                         if d.Category == "" {
267                                 d.Category = analyzer.Name
268                         } else {
269                                 d.Category = analyzer.Name + "." + d.Category
270                         }
271                         diagnostics = append(diagnostics, &d)
272                 },
273                 ImportObjectFact: func(obj types.Object, ptr analysis.Fact) bool {
274                         if obj == nil {
275                                 panic("nil object")
276                         }
277                         key := objectFactKey{obj, factType(ptr)}
278
279                         if v, ok := data.objectFacts[key]; ok {
280                                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
281                                 return true
282                         }
283                         return false
284                 },
285                 ExportObjectFact: func(obj types.Object, fact analysis.Fact) {
286                         if obj.Pkg() != pkg.types {
287                                 panic(fmt.Sprintf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package",
288                                         analyzer, pkg.ID(), obj, fact))
289                         }
290                         key := objectFactKey{obj, factType(fact)}
291                         data.objectFacts[key] = fact // clobber any existing entry
292                 },
293                 ImportPackageFact: func(pkg *types.Package, ptr analysis.Fact) bool {
294                         if pkg == nil {
295                                 panic("nil package")
296                         }
297                         key := packageFactKey{pkg, factType(ptr)}
298                         if v, ok := data.packageFacts[key]; ok {
299                                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
300                                 return true
301                         }
302                         return false
303                 },
304                 ExportPackageFact: func(fact analysis.Fact) {
305                         key := packageFactKey{pkg.types, factType(fact)}
306                         data.packageFacts[key] = fact // clobber any existing entry
307                 },
308                 AllObjectFacts: func() []analysis.ObjectFact {
309                         facts := make([]analysis.ObjectFact, 0, len(data.objectFacts))
310                         for k := range data.objectFacts {
311                                 facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: data.objectFacts[k]})
312                         }
313                         return facts
314                 },
315                 AllPackageFacts: func() []analysis.PackageFact {
316                         facts := make([]analysis.PackageFact, 0, len(data.packageFacts))
317                         for k := range data.packageFacts {
318                                 facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: data.packageFacts[k]})
319                         }
320                         return facts
321                 },
322         }
323         analysisinternal.SetTypeErrors(pass, pkg.typeErrors)
324
325         if pkg.IsIllTyped() {
326                 data.err = errors.Errorf("analysis skipped due to errors in package: %v", pkg.GetErrors())
327                 return data
328         }
329         data.result, data.err = pass.Analyzer.Run(pass)
330         if data.err != nil {
331                 return data
332         }
333
334         if got, want := reflect.TypeOf(data.result), pass.Analyzer.ResultType; got != want {
335                 data.err = errors.Errorf(
336                         "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v",
337                         pass.Pkg.Path(), pass.Analyzer, got, want)
338                 return data
339         }
340
341         // disallow calls after Run
342         pass.ExportObjectFact = func(obj types.Object, fact analysis.Fact) {
343                 panic(fmt.Sprintf("%s:%s: Pass.ExportObjectFact(%s, %T) called after Run", analyzer.Name, pkg.PkgPath(), obj, fact))
344         }
345         pass.ExportPackageFact = func(fact analysis.Fact) {
346                 panic(fmt.Sprintf("%s:%s: Pass.ExportPackageFact(%T) called after Run", analyzer.Name, pkg.PkgPath(), fact))
347         }
348
349         for _, diag := range diagnostics {
350                 srcErr, err := sourceError(ctx, snapshot, pkg, diag)
351                 if err != nil {
352                         event.Error(ctx, "unable to compute analysis error position", err, tag.Category.Of(diag.Category), tag.Package.Of(pkg.ID()))
353                         continue
354                 }
355                 if ctx.Err() != nil {
356                         data.err = ctx.Err()
357                         return data
358                 }
359                 data.diagnostics = append(data.diagnostics, srcErr)
360         }
361         return data
362 }
363
364 // exportedFrom reports whether obj may be visible to a package that imports pkg.
365 // This includes not just the exported members of pkg, but also unexported
366 // constants, types, fields, and methods, perhaps belonging to oether packages,
367 // that find there way into the API.
368 // This is an overapproximation of the more accurate approach used by
369 // gc export data, which walks the type graph, but it's much simpler.
370 //
371 // TODO(adonovan): do more accurate filtering by walking the type graph.
372 func exportedFrom(obj types.Object, pkg *types.Package) bool {
373         switch obj := obj.(type) {
374         case *types.Func:
375                 return obj.Exported() && obj.Pkg() == pkg ||
376                         obj.Type().(*types.Signature).Recv() != nil
377         case *types.Var:
378                 return obj.Exported() && obj.Pkg() == pkg ||
379                         obj.IsField()
380         case *types.TypeName, *types.Const:
381                 return true
382         }
383         return false // Nil, Builtin, Label, or PkgName
384 }
385
386 func factType(fact analysis.Fact) reflect.Type {
387         t := reflect.TypeOf(fact)
388         if t.Kind() != reflect.Ptr {
389                 panic(fmt.Sprintf("invalid Fact type: got %T, want pointer", t))
390         }
391         return t
392 }