.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / 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/scanner"
13         "go/types"
14         "path"
15         "path/filepath"
16         "sort"
17         "strings"
18         "sync"
19
20         "golang.org/x/mod/module"
21         "golang.org/x/tools/go/ast/astutil"
22         "golang.org/x/tools/go/packages"
23         "golang.org/x/tools/internal/event"
24         "golang.org/x/tools/internal/lsp/debug/tag"
25         "golang.org/x/tools/internal/lsp/protocol"
26         "golang.org/x/tools/internal/lsp/source"
27         "golang.org/x/tools/internal/memoize"
28         "golang.org/x/tools/internal/packagesinternal"
29         "golang.org/x/tools/internal/span"
30         "golang.org/x/tools/internal/typesinternal"
31         errors "golang.org/x/xerrors"
32 )
33
34 type packageHandleKey string
35
36 type packageHandle struct {
37         handle *memoize.Handle
38
39         goFiles, compiledGoFiles []*parseGoHandle
40
41         // mode is the mode the files were parsed in.
42         mode source.ParseMode
43
44         // m is the metadata associated with the package.
45         m *metadata
46
47         // key is the hashed key for the package.
48         key packageHandleKey
49 }
50
51 func (ph *packageHandle) packageKey() packageKey {
52         return packageKey{
53                 id:   ph.m.id,
54                 mode: ph.mode,
55         }
56 }
57
58 // packageData contains the data produced by type-checking a package.
59 type packageData struct {
60         pkg *pkg
61         err error
62 }
63
64 // buildPackageHandle returns a packageHandle for a given package and mode.
65 func (s *snapshot) buildPackageHandle(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, error) {
66         if ph := s.getPackage(id, mode); ph != nil {
67                 return ph, nil
68         }
69
70         // Build the packageHandle for this ID and its dependencies.
71         ph, deps, err := s.buildKey(ctx, id, mode)
72         if err != nil {
73                 return nil, err
74         }
75
76         // Do not close over the packageHandle or the snapshot in the Bind function.
77         // This creates a cycle, which causes the finalizers to never run on the handles.
78         // The possible cycles are:
79         //
80         //     packageHandle.h.function -> packageHandle
81         //     packageHandle.h.function -> snapshot -> packageHandle
82         //
83
84         m := ph.m
85         key := ph.key
86
87         h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
88                 snapshot := arg.(*snapshot)
89
90                 // Begin loading the direct dependencies, in parallel.
91                 var wg sync.WaitGroup
92                 for _, dep := range deps {
93                         wg.Add(1)
94                         go func(dep *packageHandle) {
95                                 dep.check(ctx, snapshot)
96                                 wg.Done()
97                         }(dep)
98                 }
99
100                 data := &packageData{}
101                 data.pkg, data.err = typeCheck(ctx, snapshot, m, mode, deps)
102                 // Make sure that the workers above have finished before we return,
103                 // especially in case of cancellation.
104                 wg.Wait()
105
106                 return data
107         }, nil)
108         ph.handle = h
109
110         // Cache the handle in the snapshot. If a package handle has already
111         // been cached, addPackage will return the cached value. This is fine,
112         // since the original package handle above will have no references and be
113         // garbage collected.
114         ph = s.addPackageHandle(ph)
115
116         return ph, nil
117 }
118
119 // buildKey computes the key for a given packageHandle.
120 func (s *snapshot) buildKey(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, map[packagePath]*packageHandle, error) {
121         m := s.getMetadata(id)
122         if m == nil {
123                 return nil, nil, errors.Errorf("no metadata for %s", id)
124         }
125         goFiles, err := s.parseGoHandles(ctx, m.goFiles, mode)
126         if err != nil {
127                 return nil, nil, err
128         }
129         compiledGoFiles, err := s.parseGoHandles(ctx, m.compiledGoFiles, mode)
130         if err != nil {
131                 return nil, nil, err
132         }
133         ph := &packageHandle{
134                 m:               m,
135                 goFiles:         goFiles,
136                 compiledGoFiles: compiledGoFiles,
137                 mode:            mode,
138         }
139         // Make sure all of the depList are sorted.
140         depList := append([]packageID{}, m.deps...)
141         sort.Slice(depList, func(i, j int) bool {
142                 return depList[i] < depList[j]
143         })
144
145         deps := make(map[packagePath]*packageHandle)
146
147         // Begin computing the key by getting the depKeys for all dependencies.
148         var depKeys []packageHandleKey
149         for _, depID := range depList {
150                 depHandle, err := s.buildPackageHandle(ctx, depID, s.workspaceParseMode(depID))
151                 if err != nil {
152                         event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", id, depID), err, tag.Snapshot.Of(s.id))
153                         if ctx.Err() != nil {
154                                 return nil, nil, ctx.Err()
155                         }
156                         // One bad dependency should not prevent us from checking the entire package.
157                         // Add a special key to mark a bad dependency.
158                         depKeys = append(depKeys, packageHandleKey(fmt.Sprintf("%s import not found", id)))
159                         continue
160                 }
161                 deps[depHandle.m.pkgPath] = depHandle
162                 depKeys = append(depKeys, depHandle.key)
163         }
164         experimentalKey := s.View().Options().ExperimentalPackageCacheKey
165         ph.key = checkPackageKey(ctx, ph.m.id, compiledGoFiles, m.config, depKeys, mode, experimentalKey)
166         return ph, deps, nil
167 }
168
169 func (s *snapshot) workspaceParseMode(id packageID) source.ParseMode {
170         if _, ws := s.isWorkspacePackage(id); ws {
171                 return source.ParseFull
172         } else {
173                 return source.ParseExported
174         }
175 }
176
177 func checkPackageKey(ctx context.Context, id packageID, pghs []*parseGoHandle, cfg *packages.Config, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
178         b := bytes.NewBuffer(nil)
179         b.WriteString(string(id))
180         if !experimentalKey {
181                 // cfg was used to produce the other hashed inputs (package ID, parsed Go
182                 // files, and deps). It should not otherwise affect the inputs to the type
183                 // checker, so this experiment omits it. This should increase cache hits on
184                 // the daemon as cfg contains the environment and working directory.
185                 b.WriteString(hashConfig(cfg))
186         }
187         b.WriteByte(byte(mode))
188         for _, dep := range deps {
189                 b.WriteString(string(dep))
190         }
191         for _, cgf := range pghs {
192                 b.WriteString(cgf.file.FileIdentity().String())
193         }
194         return packageHandleKey(hashContents(b.Bytes()))
195 }
196
197 // hashEnv returns a hash of the snapshot's configuration.
198 func hashEnv(s *snapshot) string {
199         s.view.optionsMu.Lock()
200         env := s.view.options.EnvSlice()
201         s.view.optionsMu.Unlock()
202
203         b := &bytes.Buffer{}
204         for _, e := range env {
205                 b.WriteString(e)
206         }
207         return hashContents(b.Bytes())
208 }
209
210 // hashConfig returns the hash for the *packages.Config.
211 func hashConfig(config *packages.Config) string {
212         b := bytes.NewBuffer(nil)
213
214         // Dir, Mode, Env, BuildFlags are the parts of the config that can change.
215         b.WriteString(config.Dir)
216         b.WriteString(string(rune(config.Mode)))
217
218         for _, e := range config.Env {
219                 b.WriteString(e)
220         }
221         for _, f := range config.BuildFlags {
222                 b.WriteString(f)
223         }
224         return hashContents(b.Bytes())
225 }
226
227 func (ph *packageHandle) Check(ctx context.Context, s source.Snapshot) (source.Package, error) {
228         return ph.check(ctx, s.(*snapshot))
229 }
230
231 func (ph *packageHandle) check(ctx context.Context, s *snapshot) (*pkg, error) {
232         v, err := ph.handle.Get(ctx, s.generation, s)
233         if err != nil {
234                 return nil, err
235         }
236         data := v.(*packageData)
237         return data.pkg, data.err
238 }
239
240 func (ph *packageHandle) CompiledGoFiles() []span.URI {
241         return ph.m.compiledGoFiles
242 }
243
244 func (ph *packageHandle) ID() string {
245         return string(ph.m.id)
246 }
247
248 func (ph *packageHandle) cached(g *memoize.Generation) (*pkg, error) {
249         v := ph.handle.Cached(g)
250         if v == nil {
251                 return nil, errors.Errorf("no cached type information for %s", ph.m.pkgPath)
252         }
253         data := v.(*packageData)
254         return data.pkg, data.err
255 }
256
257 func (s *snapshot) parseGoHandles(ctx context.Context, files []span.URI, mode source.ParseMode) ([]*parseGoHandle, error) {
258         pghs := make([]*parseGoHandle, 0, len(files))
259         for _, uri := range files {
260                 fh, err := s.GetFile(ctx, uri)
261                 if err != nil {
262                         return nil, err
263                 }
264                 pghs = append(pghs, s.parseGoHandle(ctx, fh, mode))
265         }
266         return pghs, nil
267 }
268
269 func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source.ParseMode, deps map[packagePath]*packageHandle) (*pkg, error) {
270         ctx, done := event.Start(ctx, "cache.importer.typeCheck", tag.Package.Of(string(m.id)))
271         defer done()
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([]scanner.ErrorList, len(m.compiledGoFiles))
305                 actualErrors = make([]error, len(m.compiledGoFiles))
306                 wg           sync.WaitGroup
307
308                 mu             sync.Mutex
309                 haveFixedFiles 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                         // If we have fixed parse errors in any of the files, we should hide type
330                         // errors, as they may be completely nonsensical.
331                         mu.Lock()
332                         haveFixedFiles = haveFixedFiles || fixed
333                         mu.Unlock()
334                 }(i, cgf)
335         }
336         for i, gf := range m.goFiles {
337                 wg.Add(1)
338                 // We need to parse the non-compiled go files, but we don't care about their errors.
339                 go func(i int, gf span.URI) {
340                         defer wg.Done()
341                         fh, err := snapshot.GetFile(ctx, gf)
342                         if err != nil {
343                                 return
344                         }
345                         pgf, _ := snapshot.ParseGo(ctx, fh, mode)
346                         pkg.goFiles[i] = pgf
347                 }(i, gf)
348         }
349         wg.Wait()
350         for _, err := range actualErrors {
351                 if err != nil {
352                         return nil, err
353                 }
354         }
355
356         var i int
357         for _, e := range parseErrors {
358                 if e != nil {
359                         parseErrors[i] = e
360                         i++
361                 }
362         }
363         parseErrors = parseErrors[:i]
364
365         i = 0
366         for _, f := range files {
367                 if f != nil {
368                         files[i] = f
369                         i++
370                 }
371         }
372         files = files[:i]
373
374         // Use the default type information for the unsafe package.
375         if pkg.m.pkgPath == "unsafe" {
376                 pkg.types = types.Unsafe
377                 // Don't type check Unsafe: it's unnecessary, and doing so exposes a data
378                 // race to Unsafe.completed.
379                 return pkg, nil
380         } else if len(files) == 0 { // not the unsafe package, no parsed files
381                 // Try to attach error messages to the file as much as possible.
382                 var found bool
383                 for _, e := range m.errors {
384                         srcDiags, err := goPackagesErrorDiagnostics(ctx, snapshot, pkg, e)
385                         if err != nil {
386                                 continue
387                         }
388                         found = true
389                         pkg.diagnostics = append(pkg.diagnostics, srcDiags...)
390                 }
391                 if found {
392                         return pkg, nil
393                 }
394                 return nil, errors.Errorf("no parsed files for package %s, expected: %v, errors: %v", pkg.m.pkgPath, pkg.compiledGoFiles, m.errors)
395         } else {
396                 pkg.types = types.NewPackage(string(m.pkgPath), string(m.name))
397         }
398
399         var typeErrors []types.Error
400         cfg := &types.Config{
401                 Error: func(e error) {
402                         typeErrors = append(typeErrors, e.(types.Error))
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                 return pkg, nil
441         }
442
443         if len(m.errors) != 0 {
444                 pkg.hasListOrParseErrors = true
445                 for _, e := range m.errors {
446                         diags, err := goPackagesErrorDiagnostics(ctx, snapshot, pkg, e)
447                         if err != nil {
448                                 event.Error(ctx, "unable to compute positions for list errors", err, tag.Package.Of(pkg.ID()))
449                                 continue
450                         }
451                         pkg.diagnostics = append(pkg.diagnostics, diags...)
452                 }
453         }
454
455         // Our heuristic for whether to show type checking errors is:
456         //  + If any file was 'fixed', don't show type checking errors as we
457         //    can't guarantee that they reference accurate locations in the source.
458         //  + If there is a parse error _in the current file_, suppress type
459         //    errors in that file.
460         //  + Otherwise, show type errors even in the presence of parse errors in
461         //    other package files. go/types attempts to suppress follow-on errors
462         //    due to bad syntax, so on balance type checking errors still provide
463         //    a decent signal/noise ratio as long as the file in question parses.
464
465         // Track URIs with parse errors so that we can suppress type errors for these
466         // files.
467         unparseable := map[span.URI]bool{}
468         if len(parseErrors) != 0 {
469                 pkg.hasListOrParseErrors = true
470                 for _, e := range parseErrors {
471                         diags, err := parseErrorDiagnostics(ctx, snapshot, pkg, e)
472                         if err != nil {
473                                 event.Error(ctx, "unable to compute positions for parse errors", err, tag.Package.Of(pkg.ID()))
474                                 continue
475                         }
476                         for _, diag := range diags {
477                                 unparseable[diag.URI] = true
478                                 pkg.diagnostics = append(pkg.diagnostics, diag)
479                         }
480                 }
481         }
482
483         if haveFixedFiles {
484                 return pkg, nil
485         }
486
487         for _, e := range expandErrors(typeErrors, snapshot.View().Options().RelatedInformationSupported) {
488                 pkg.hasTypeErrors = true
489                 diags, err := typeErrorDiagnostics(ctx, snapshot, pkg, e)
490                 if err != nil {
491                         event.Error(ctx, "unable to compute positions for type errors", err, tag.Package.Of(pkg.ID()))
492                         continue
493                 }
494                 pkg.typeErrors = append(pkg.typeErrors, e.primary)
495                 for _, diag := range diags {
496                         // If the file didn't parse cleanly, it is highly likely that type
497                         // checking errors will be confusing or redundant. But otherwise, type
498                         // checking usually provides a good enough signal to include.
499                         if !unparseable[diag.URI] {
500                                 pkg.diagnostics = append(pkg.diagnostics, diag)
501                         }
502                 }
503         }
504
505         depsErrors, err := snapshot.depsErrors(ctx, pkg)
506         if err != nil {
507                 return nil, err
508         }
509         pkg.diagnostics = append(pkg.diagnostics, depsErrors...)
510
511         return pkg, nil
512 }
513
514 func (s *snapshot) depsErrors(ctx context.Context, pkg *pkg) ([]*source.Diagnostic, error) {
515         // Select packages that can't be found, and were imported in non-workspace packages.
516         // Workspace packages already show their own errors.
517         var relevantErrors []*packagesinternal.PackageError
518         for _, depsError := range pkg.m.depsErrors {
519                 // Up to Go 1.15, the missing package was included in the stack, which
520                 // was presumably a bug. We want the next one up.
521                 directImporterIdx := len(depsError.ImportStack) - 1
522                 if s.view.goversion < 15 {
523                         directImporterIdx = len(depsError.ImportStack) - 2
524                 }
525                 if directImporterIdx < 0 {
526                         continue
527                 }
528
529                 directImporter := depsError.ImportStack[directImporterIdx]
530                 if _, ok := s.isWorkspacePackage(packageID(directImporter)); ok {
531                         continue
532                 }
533                 relevantErrors = append(relevantErrors, depsError)
534         }
535
536         // Don't build the import index for nothing.
537         if len(relevantErrors) == 0 {
538                 return nil, nil
539         }
540
541         // Build an index of all imports in the package.
542         type fileImport struct {
543                 cgf *source.ParsedGoFile
544                 imp *ast.ImportSpec
545         }
546         allImports := map[string][]fileImport{}
547         for _, cgf := range pkg.compiledGoFiles {
548                 for _, group := range astutil.Imports(s.FileSet(), cgf.File) {
549                         for _, imp := range group {
550                                 if imp.Path == nil {
551                                         continue
552                                 }
553                                 path := strings.Trim(imp.Path.Value, `"`)
554                                 allImports[path] = append(allImports[path], fileImport{cgf, imp})
555                         }
556                 }
557         }
558
559         // Apply a diagnostic to any import involved in the error, stopping once
560         // we reach the workspace.
561         var errors []*source.Diagnostic
562         for _, depErr := range relevantErrors {
563                 for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
564                         item := depErr.ImportStack[i]
565                         if _, ok := s.isWorkspacePackage(packageID(item)); ok {
566                                 break
567                         }
568
569                         for _, imp := range allImports[item] {
570                                 rng, err := source.NewMappedRange(s.FileSet(), imp.cgf.Mapper, imp.imp.Pos(), imp.imp.End()).Range()
571                                 if err != nil {
572                                         return nil, err
573                                 }
574                                 fixes, err := goGetQuickFixes(s, imp.cgf.URI, item)
575                                 if err != nil {
576                                         return nil, err
577                                 }
578                                 errors = append(errors, &source.Diagnostic{
579                                         URI:            imp.cgf.URI,
580                                         Range:          rng,
581                                         Severity:       protocol.SeverityError,
582                                         Source:         source.TypeError,
583                                         Message:        fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
584                                         SuggestedFixes: fixes,
585                                 })
586                         }
587                 }
588         }
589
590         if len(pkg.compiledGoFiles) == 0 {
591                 return errors, nil
592         }
593         mod := s.GoModForFile(pkg.compiledGoFiles[0].URI)
594         if mod == "" {
595                 return errors, nil
596         }
597         fh, err := s.GetFile(ctx, mod)
598         if err != nil {
599                 return nil, err
600         }
601         pm, err := s.ParseMod(ctx, fh)
602         if err != nil {
603                 return nil, err
604         }
605
606         // Add a diagnostic to the module that contained the lowest-level import of
607         // the missing package.
608         for _, depErr := range relevantErrors {
609                 for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
610                         item := depErr.ImportStack[i]
611                         m := s.getMetadata(packageID(item))
612                         if m == nil || m.module == nil {
613                                 continue
614                         }
615                         modVer := module.Version{Path: m.module.Path, Version: m.module.Version}
616                         reference := findModuleReference(pm.File, modVer)
617                         if reference == nil {
618                                 continue
619                         }
620                         rng, err := rangeFromPositions(pm.Mapper, reference.Start, reference.End)
621                         if err != nil {
622                                 return nil, err
623                         }
624                         fixes, err := goGetQuickFixes(s, pm.URI, item)
625                         if err != nil {
626                                 return nil, err
627                         }
628                         errors = append(errors, &source.Diagnostic{
629                                 URI:            pm.URI,
630                                 Range:          rng,
631                                 Severity:       protocol.SeverityError,
632                                 Source:         source.TypeError,
633                                 Message:        fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
634                                 SuggestedFixes: fixes,
635                         })
636                         break
637                 }
638         }
639         return errors, nil
640 }
641
642 // missingPkgError returns an error message for a missing package that varies
643 // based on the user's workspace mode.
644 func (s *snapshot) missingPkgError(pkgPath string) error {
645         if s.workspaceMode()&moduleMode != 0 {
646                 return fmt.Errorf("no required module provides package %q", pkgPath)
647         }
648         gorootSrcPkg := filepath.FromSlash(filepath.Join(s.view.goroot, "src", pkgPath))
649
650         var b strings.Builder
651         b.WriteString(fmt.Sprintf("cannot find package %q in any of \n\t%s (from $GOROOT)", pkgPath, gorootSrcPkg))
652
653         for _, gopath := range strings.Split(s.view.gopath, ":") {
654                 gopathSrcPkg := filepath.FromSlash(filepath.Join(gopath, "src", pkgPath))
655                 b.WriteString(fmt.Sprintf("\n\t%s (from $GOPATH)", gopathSrcPkg))
656         }
657         return errors.New(b.String())
658 }
659
660 type extendedError struct {
661         primary     types.Error
662         secondaries []types.Error
663 }
664
665 func (e extendedError) Error() string {
666         return e.primary.Error()
667 }
668
669 // expandErrors duplicates "secondary" errors by mapping them to their main
670 // error. Some errors returned by the type checker are followed by secondary
671 // errors which give more information about the error. These are errors in
672 // their own right, and they are marked by starting with \t. For instance, when
673 // there is a multiply-defined function, the secondary error points back to the
674 // definition first noticed.
675 //
676 // This function associates the secondary error with its primary error, which can
677 // then be used as RelatedInformation when the error becomes a diagnostic.
678 //
679 // If supportsRelatedInformation is false, the secondary is instead embedded as
680 // additional context in the primary error.
681 func expandErrors(errs []types.Error, supportsRelatedInformation bool) []extendedError {
682         var result []extendedError
683         for i := 0; i < len(errs); {
684                 original := extendedError{
685                         primary: errs[i],
686                 }
687                 for i++; i < len(errs); i++ {
688                         spl := errs[i]
689                         if len(spl.Msg) == 0 || spl.Msg[0] != '\t' {
690                                 break
691                         }
692                         spl.Msg = spl.Msg[1:]
693                         original.secondaries = append(original.secondaries, spl)
694                 }
695
696                 // Clone the error to all its related locations -- VS Code, at least,
697                 // doesn't do it for us.
698                 result = append(result, original)
699                 for i, mainSecondary := range original.secondaries {
700                         // Create the new primary error, with a tweaked message, in the
701                         // secondary's location. We need to start from the secondary to
702                         // capture its unexported location fields.
703                         relocatedSecondary := mainSecondary
704                         if supportsRelatedInformation {
705                                 relocatedSecondary.Msg = fmt.Sprintf("%v (see details)", original.primary.Msg)
706                         } else {
707                                 relocatedSecondary.Msg = fmt.Sprintf("%v (this error: %v)", original.primary.Msg, mainSecondary.Msg)
708                         }
709                         relocatedSecondary.Soft = original.primary.Soft
710
711                         // Copy over the secondary errors, noting the location of the
712                         // current error we're cloning.
713                         clonedError := extendedError{primary: relocatedSecondary, secondaries: []types.Error{original.primary}}
714                         for j, secondary := range original.secondaries {
715                                 if i == j {
716                                         secondary.Msg += " (this error)"
717                                 }
718                                 clonedError.secondaries = append(clonedError.secondaries, secondary)
719                         }
720                         result = append(result, clonedError)
721                 }
722
723         }
724         return result
725 }
726
727 // resolveImportPath resolves an import path in pkg to a package from deps.
728 // It should produce the same results as resolveImportPath:
729 // https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/load/pkg.go;drc=641918ee09cb44d282a30ee8b66f99a0b63eaef9;l=990.
730 func resolveImportPath(importPath string, pkg *pkg, deps map[packagePath]*packageHandle) *packageHandle {
731         if dep := deps[packagePath(importPath)]; dep != nil {
732                 return dep
733         }
734         // We may be in GOPATH mode, in which case we need to check vendor dirs.
735         searchDir := path.Dir(pkg.PkgPath())
736         for {
737                 vdir := packagePath(path.Join(searchDir, "vendor", importPath))
738                 if vdep := deps[vdir]; vdep != nil {
739                         return vdep
740                 }
741
742                 // Search until Dir doesn't take us anywhere new, e.g. "." or "/".
743                 next := path.Dir(searchDir)
744                 if searchDir == next {
745                         break
746                 }
747                 searchDir = next
748         }
749
750         // Vendor didn't work. Let's try minimal module compatibility mode.
751         // In MMC, the packagePath is the canonical (.../vN/...) path, which
752         // is hard to calculate. But the go command has already resolved the ID
753         // to the non-versioned path, and we can take advantage of that.
754         for _, dep := range deps {
755                 if dep.ID() == importPath {
756                         return dep
757                 }
758         }
759         return nil
760 }
761
762 func isValidImport(pkgPath, importPkgPath packagePath) bool {
763         i := strings.LastIndex(string(importPkgPath), "/internal/")
764         if i == -1 {
765                 return true
766         }
767         if pkgPath == "command-line-arguments" {
768                 return true
769         }
770         return strings.HasPrefix(string(pkgPath), string(importPkgPath[:i]))
771 }
772
773 // An importFunc is an implementation of the single-method
774 // types.Importer interface based on a function value.
775 type importerFunc func(path string) (*types.Package, error)
776
777 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }