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 / internal / lsp / cache / check.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         "bytes"
9         "context"
10         "fmt"
11         "go/ast"
12         "go/types"
13         "path"
14         "sort"
15         "strings"
16         "sync"
17
18         "golang.org/x/mod/module"
19         "golang.org/x/tools/go/packages"
20         "golang.org/x/tools/internal/event"
21         "golang.org/x/tools/internal/lsp/debug/tag"
22         "golang.org/x/tools/internal/lsp/source"
23         "golang.org/x/tools/internal/memoize"
24         "golang.org/x/tools/internal/span"
25         "golang.org/x/tools/internal/typesinternal"
26         errors "golang.org/x/xerrors"
27 )
28
29 type packageHandleKey string
30
31 type packageHandle struct {
32         handle *memoize.Handle
33
34         goFiles, compiledGoFiles []*parseGoHandle
35
36         // mode is the mode the files were parsed in.
37         mode source.ParseMode
38
39         // m is the metadata associated with the package.
40         m *metadata
41
42         // key is the hashed key for the package.
43         key packageHandleKey
44 }
45
46 func (ph *packageHandle) packageKey() packageKey {
47         return packageKey{
48                 id:   ph.m.id,
49                 mode: ph.mode,
50         }
51 }
52
53 // packageData contains the data produced by type-checking a package.
54 type packageData struct {
55         pkg *pkg
56         err error
57 }
58
59 // buildPackageHandle returns a packageHandle for a given package and mode.
60 func (s *snapshot) buildPackageHandle(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, error) {
61         if ph := s.getPackage(id, mode); ph != nil {
62                 return ph, nil
63         }
64
65         // Build the packageHandle for this ID and its dependencies.
66         ph, deps, err := s.buildKey(ctx, id, mode)
67         if err != nil {
68                 return nil, err
69         }
70
71         // Do not close over the packageHandle or the snapshot in the Bind function.
72         // This creates a cycle, which causes the finalizers to never run on the handles.
73         // The possible cycles are:
74         //
75         //     packageHandle.h.function -> packageHandle
76         //     packageHandle.h.function -> snapshot -> packageHandle
77         //
78
79         m := ph.m
80         key := ph.key
81
82         h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
83                 snapshot := arg.(*snapshot)
84
85                 // Begin loading the direct dependencies, in parallel.
86                 var wg sync.WaitGroup
87                 for _, dep := range deps {
88                         wg.Add(1)
89                         go func(dep *packageHandle) {
90                                 dep.check(ctx, snapshot)
91                                 wg.Done()
92                         }(dep)
93                 }
94
95                 data := &packageData{}
96                 data.pkg, data.err = typeCheck(ctx, snapshot, m, mode, deps)
97                 // Make sure that the workers above have finished before we return,
98                 // especially in case of cancellation.
99                 wg.Wait()
100
101                 return data
102         }, nil)
103         ph.handle = h
104
105         // Cache the handle in the snapshot. If a package handle has already
106         // been cached, addPackage will return the cached value. This is fine,
107         // since the original package handle above will have no references and be
108         // garbage collected.
109         ph = s.addPackageHandle(ph)
110
111         return ph, nil
112 }
113
114 // buildKey computes the key for a given packageHandle.
115 func (s *snapshot) buildKey(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, map[packagePath]*packageHandle, error) {
116         m := s.getMetadata(id)
117         if m == nil {
118                 return nil, nil, errors.Errorf("no metadata for %s", id)
119         }
120         goFiles, err := s.parseGoHandles(ctx, m.goFiles, mode)
121         if err != nil {
122                 return nil, nil, err
123         }
124         compiledGoFiles, err := s.parseGoHandles(ctx, m.compiledGoFiles, mode)
125         if err != nil {
126                 return nil, nil, err
127         }
128         ph := &packageHandle{
129                 m:               m,
130                 goFiles:         goFiles,
131                 compiledGoFiles: compiledGoFiles,
132                 mode:            mode,
133         }
134         // Make sure all of the depList are sorted.
135         depList := append([]packageID{}, m.deps...)
136         sort.Slice(depList, func(i, j int) bool {
137                 return depList[i] < depList[j]
138         })
139
140         deps := make(map[packagePath]*packageHandle)
141
142         // Begin computing the key by getting the depKeys for all dependencies.
143         var depKeys []packageHandleKey
144         for _, depID := range depList {
145                 depHandle, err := s.buildPackageHandle(ctx, depID, s.workspaceParseMode(depID))
146                 if err != nil {
147                         event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", id, depID), err, tag.Snapshot.Of(s.id))
148                         if ctx.Err() != nil {
149                                 return nil, nil, ctx.Err()
150                         }
151                         // One bad dependency should not prevent us from checking the entire package.
152                         // Add a special key to mark a bad dependency.
153                         depKeys = append(depKeys, packageHandleKey(fmt.Sprintf("%s import not found", id)))
154                         continue
155                 }
156                 deps[depHandle.m.pkgPath] = depHandle
157                 depKeys = append(depKeys, depHandle.key)
158         }
159         experimentalKey := s.View().Options().ExperimentalPackageCacheKey
160         ph.key = checkPackageKey(ctx, ph.m.id, compiledGoFiles, m.config, depKeys, mode, experimentalKey)
161         return ph, deps, nil
162 }
163
164 func (s *snapshot) workspaceParseMode(id packageID) source.ParseMode {
165         if _, ws := s.isWorkspacePackage(id); ws {
166                 return source.ParseFull
167         } else {
168                 return source.ParseExported
169         }
170 }
171
172 func checkPackageKey(ctx context.Context, id packageID, pghs []*parseGoHandle, cfg *packages.Config, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
173         b := bytes.NewBuffer(nil)
174         b.WriteString(string(id))
175         if !experimentalKey {
176                 // cfg was used to produce the other hashed inputs (package ID, parsed Go
177                 // files, and deps). It should not otherwise affect the inputs to the type
178                 // checker, so this experiment omits it. This should increase cache hits on
179                 // the daemon as cfg contains the environment and working directory.
180                 b.WriteString(hashConfig(cfg))
181         }
182         b.WriteByte(byte(mode))
183         for _, dep := range deps {
184                 b.WriteString(string(dep))
185         }
186         for _, cgf := range pghs {
187                 b.WriteString(cgf.file.FileIdentity().String())
188         }
189         return packageHandleKey(hashContents(b.Bytes()))
190 }
191
192 // hashEnv returns a hash of the snapshot's configuration.
193 func hashEnv(s *snapshot) string {
194         s.view.optionsMu.Lock()
195         env := s.view.options.EnvSlice()
196         s.view.optionsMu.Unlock()
197
198         b := &bytes.Buffer{}
199         for _, e := range env {
200                 b.WriteString(e)
201         }
202         return hashContents(b.Bytes())
203 }
204
205 // hashConfig returns the hash for the *packages.Config.
206 func hashConfig(config *packages.Config) string {
207         b := bytes.NewBuffer(nil)
208
209         // Dir, Mode, Env, BuildFlags are the parts of the config that can change.
210         b.WriteString(config.Dir)
211         b.WriteString(string(rune(config.Mode)))
212
213         for _, e := range config.Env {
214                 b.WriteString(e)
215         }
216         for _, f := range config.BuildFlags {
217                 b.WriteString(f)
218         }
219         return hashContents(b.Bytes())
220 }
221
222 func (ph *packageHandle) Check(ctx context.Context, s source.Snapshot) (source.Package, error) {
223         return ph.check(ctx, s.(*snapshot))
224 }
225
226 func (ph *packageHandle) check(ctx context.Context, s *snapshot) (*pkg, error) {
227         v, err := ph.handle.Get(ctx, s.generation, s)
228         if err != nil {
229                 return nil, err
230         }
231         data := v.(*packageData)
232         return data.pkg, data.err
233 }
234
235 func (ph *packageHandle) CompiledGoFiles() []span.URI {
236         return ph.m.compiledGoFiles
237 }
238
239 func (ph *packageHandle) ID() string {
240         return string(ph.m.id)
241 }
242
243 func (ph *packageHandle) cached(g *memoize.Generation) (*pkg, error) {
244         v := ph.handle.Cached(g)
245         if v == nil {
246                 return nil, errors.Errorf("no cached type information for %s", ph.m.pkgPath)
247         }
248         data := v.(*packageData)
249         return data.pkg, data.err
250 }
251
252 func (s *snapshot) parseGoHandles(ctx context.Context, files []span.URI, mode source.ParseMode) ([]*parseGoHandle, error) {
253         pghs := make([]*parseGoHandle, 0, len(files))
254         for _, uri := range files {
255                 fh, err := s.GetFile(ctx, uri)
256                 if err != nil {
257                         return nil, err
258                 }
259                 pghs = append(pghs, s.parseGoHandle(ctx, fh, mode))
260         }
261         return pghs, nil
262 }
263
264 func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source.ParseMode, deps map[packagePath]*packageHandle) (*pkg, error) {
265         ctx, done := event.Start(ctx, "cache.importer.typeCheck", tag.Package.Of(string(m.id)))
266         defer done()
267
268         var rawErrors []error
269         for _, err := range m.errors {
270                 rawErrors = append(rawErrors, err)
271         }
272
273         fset := snapshot.view.session.cache.fset
274         pkg := &pkg{
275                 m:               m,
276                 mode:            mode,
277                 goFiles:         make([]*source.ParsedGoFile, len(m.goFiles)),
278                 compiledGoFiles: make([]*source.ParsedGoFile, len(m.compiledGoFiles)),
279                 imports:         make(map[packagePath]*pkg),
280                 typesSizes:      m.typesSizes,
281                 typesInfo: &types.Info{
282                         Types:      make(map[ast.Expr]types.TypeAndValue),
283                         Defs:       make(map[*ast.Ident]types.Object),
284                         Uses:       make(map[*ast.Ident]types.Object),
285                         Implicits:  make(map[ast.Node]types.Object),
286                         Selections: make(map[*ast.SelectorExpr]*types.Selection),
287                         Scopes:     make(map[ast.Node]*types.Scope),
288                 },
289         }
290         // If this is a replaced module in the workspace, the version is
291         // meaningless, and we don't want clients to access it.
292         if m.module != nil {
293                 version := m.module.Version
294                 if source.IsWorkspaceModuleVersion(version) {
295                         version = ""
296                 }
297                 pkg.version = &module.Version{
298                         Path:    m.module.Path,
299                         Version: version,
300                 }
301         }
302         var (
303                 files        = make([]*ast.File, len(m.compiledGoFiles))
304                 parseErrors  = make([]error, len(m.compiledGoFiles))
305                 actualErrors = make([]error, len(m.compiledGoFiles))
306                 wg           sync.WaitGroup
307
308                 mu             sync.Mutex
309                 skipTypeErrors bool
310         )
311         for i, cgf := range m.compiledGoFiles {
312                 wg.Add(1)
313                 go func(i int, cgf span.URI) {
314                         defer wg.Done()
315                         fh, err := snapshot.GetFile(ctx, cgf)
316                         if err != nil {
317                                 actualErrors[i] = err
318                                 return
319                         }
320                         pgh := snapshot.parseGoHandle(ctx, fh, mode)
321                         pgf, fixed, err := snapshot.parseGo(ctx, pgh)
322                         if err != nil {
323                                 actualErrors[i] = err
324                                 return
325                         }
326                         pkg.compiledGoFiles[i] = pgf
327                         files[i], parseErrors[i], actualErrors[i] = pgf.File, pgf.ParseErr, err
328
329                         mu.Lock()
330                         skipTypeErrors = skipTypeErrors || fixed
331                         mu.Unlock()
332                 }(i, cgf)
333         }
334         for i, gf := range m.goFiles {
335                 wg.Add(1)
336                 // We need to parse the non-compiled go files, but we don't care about their errors.
337                 go func(i int, gf span.URI) {
338                         defer wg.Done()
339                         fh, err := snapshot.GetFile(ctx, gf)
340                         if err != nil {
341                                 return
342                         }
343                         pgf, _ := snapshot.ParseGo(ctx, fh, mode)
344                         pkg.goFiles[i] = pgf
345                 }(i, gf)
346         }
347         wg.Wait()
348         for _, err := range actualErrors {
349                 if err != nil {
350                         return nil, err
351                 }
352         }
353
354         for _, e := range parseErrors {
355                 if e != nil {
356                         rawErrors = append(rawErrors, e)
357                 }
358         }
359
360         var i int
361         for _, f := range files {
362                 if f != nil {
363                         files[i] = f
364                         i++
365                 }
366         }
367         files = files[:i]
368
369         // Use the default type information for the unsafe package.
370         if pkg.m.pkgPath == "unsafe" {
371                 pkg.types = types.Unsafe
372                 // Don't type check Unsafe: it's unnecessary, and doing so exposes a data
373                 // race to Unsafe.completed.
374                 return pkg, nil
375         } else if len(files) == 0 { // not the unsafe package, no parsed files
376                 // Try to attach errors messages to the file as much as possible.
377                 var found bool
378                 for _, e := range rawErrors {
379                         srcErr, err := sourceError(ctx, snapshot, pkg, e)
380                         if err != nil {
381                                 continue
382                         }
383                         found = true
384                         pkg.errors = append(pkg.errors, srcErr)
385                 }
386                 if found {
387                         return pkg, nil
388                 }
389                 return nil, errors.Errorf("no parsed files for package %s, expected: %v, list errors: %v", pkg.m.pkgPath, pkg.compiledGoFiles, rawErrors)
390         } else {
391                 pkg.types = types.NewPackage(string(m.pkgPath), string(m.name))
392         }
393
394         cfg := &types.Config{
395                 Error: func(e error) {
396                         // If we have fixed parse errors in any of the files,
397                         // we should hide type errors, as they may be completely nonsensical.
398                         if skipTypeErrors {
399                                 return
400                         }
401                         rawErrors = append(rawErrors, e)
402                 },
403                 Importer: importerFunc(func(pkgPath string) (*types.Package, error) {
404                         // If the context was cancelled, we should abort.
405                         if ctx.Err() != nil {
406                                 return nil, ctx.Err()
407                         }
408                         dep := resolveImportPath(pkgPath, pkg, deps)
409                         if dep == nil {
410                                 return nil, errors.Errorf("no package for import %s", pkgPath)
411                         }
412                         if !isValidImport(m.pkgPath, dep.m.pkgPath) {
413                                 return nil, errors.Errorf("invalid use of internal package %s", pkgPath)
414                         }
415                         depPkg, err := dep.check(ctx, snapshot)
416                         if err != nil {
417                                 return nil, err
418                         }
419                         pkg.imports[depPkg.m.pkgPath] = depPkg
420                         return depPkg.types, nil
421                 }),
422         }
423         // We want to type check cgo code if go/types supports it.
424         // We passed typecheckCgo to go/packages when we Loaded.
425         typesinternal.SetUsesCgo(cfg)
426
427         check := types.NewChecker(cfg, fset, pkg.types, pkg.typesInfo)
428
429         // Type checking errors are handled via the config, so ignore them here.
430         _ = check.Files(files)
431         // If the context was cancelled, we may have returned a ton of transient
432         // errors to the type checker. Swallow them.
433         if ctx.Err() != nil {
434                 return nil, ctx.Err()
435         }
436
437         // We don't care about a package's errors unless we have parsed it in full.
438         if mode == source.ParseFull {
439                 expandErrors(rawErrors)
440                 for _, e := range rawErrors {
441                         srcErr, err := sourceError(ctx, snapshot, pkg, e)
442                         if err != nil {
443                                 event.Error(ctx, "unable to compute error positions", err, tag.Package.Of(pkg.ID()))
444                                 continue
445                         }
446                         pkg.errors = append(pkg.errors, srcErr)
447                         if err, ok := e.(extendedError); ok {
448                                 pkg.typeErrors = append(pkg.typeErrors, err.primary)
449                         }
450                 }
451         }
452
453         return pkg, nil
454 }
455
456 type extendedError struct {
457         primary     types.Error
458         secondaries []types.Error
459 }
460
461 func (e extendedError) Error() string {
462         return e.primary.Error()
463 }
464
465 // expandErrors duplicates "secondary" errors by mapping them to their main
466 // error. Some errors returned by the type checker are followed by secondary
467 // errors which give more information about the error. These are errors in
468 // their own right, and they are marked by starting with \t. For instance, when
469 // there is a multiply-defined function, the secondary error points back to the
470 // definition first noticed.
471 //
472 // This code associates the secondary error with its primary error, which can
473 // then be used as RelatedInformation when the error becomes a diagnostic.
474 func expandErrors(errs []error) []error {
475         for i := 0; i < len(errs); {
476                 e, ok := errs[i].(types.Error)
477                 if !ok {
478                         i++
479                         continue
480                 }
481                 enew := extendedError{
482                         primary: e,
483                 }
484                 j := i + 1
485                 for ; j < len(errs); j++ {
486                         spl, ok := errs[j].(types.Error)
487                         if !ok || len(spl.Msg) == 0 || spl.Msg[0] != '\t' {
488                                 break
489                         }
490                         enew.secondaries = append(enew.secondaries, spl)
491                 }
492                 errs[i] = enew
493                 i = j
494         }
495         return errs
496 }
497
498 // resolveImportPath resolves an import path in pkg to a package from deps.
499 // It should produce the same results as resolveImportPath:
500 // https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/load/pkg.go;drc=641918ee09cb44d282a30ee8b66f99a0b63eaef9;l=990.
501 func resolveImportPath(importPath string, pkg *pkg, deps map[packagePath]*packageHandle) *packageHandle {
502         if dep := deps[packagePath(importPath)]; dep != nil {
503                 return dep
504         }
505         // We may be in GOPATH mode, in which case we need to check vendor dirs.
506         searchDir := path.Dir(pkg.PkgPath())
507         for {
508                 vdir := packagePath(path.Join(searchDir, "vendor", importPath))
509                 if vdep := deps[vdir]; vdep != nil {
510                         return vdep
511                 }
512
513                 // Search until Dir doesn't take us anywhere new, e.g. "." or "/".
514                 next := path.Dir(searchDir)
515                 if searchDir == next {
516                         break
517                 }
518                 searchDir = next
519         }
520
521         // Vendor didn't work. Let's try minimal module compatibility mode.
522         // In MMC, the packagePath is the canonical (.../vN/...) path, which
523         // is hard to calculate. But the go command has already resolved the ID
524         // to the non-versioned path, and we can take advantage of that.
525         for _, dep := range deps {
526                 if dep.ID() == importPath {
527                         return dep
528                 }
529         }
530         return nil
531 }
532
533 func isValidImport(pkgPath, importPkgPath packagePath) bool {
534         i := strings.LastIndex(string(importPkgPath), "/internal/")
535         if i == -1 {
536                 return true
537         }
538         if pkgPath == "command-line-arguments" {
539                 return true
540         }
541         return strings.HasPrefix(string(pkgPath), string(importPkgPath[:i]))
542 }
543
544 // An importFunc is an implementation of the single-method
545 // types.Importer interface based on a function value.
546 type importerFunc func(path string) (*types.Package, error)
547
548 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }