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