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.
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"
34 type packageHandleKey string
36 type packageHandle struct {
37 handle *memoize.Handle
39 goFiles, compiledGoFiles []*parseGoHandle
41 // mode is the mode the files were parsed in.
44 // m is the metadata associated with the package.
47 // key is the hashed key for the package.
51 func (ph *packageHandle) packageKey() packageKey {
58 // packageData contains the data produced by type-checking a package.
59 type packageData struct {
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 {
70 // Build the packageHandle for this ID and its dependencies.
71 ph, deps, err := s.buildKey(ctx, id, mode)
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:
80 // packageHandle.h.function -> packageHandle
81 // packageHandle.h.function -> snapshot -> packageHandle
87 h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
88 snapshot := arg.(*snapshot)
90 // Begin loading the direct dependencies, in parallel.
92 for _, dep := range deps {
94 go func(dep *packageHandle) {
95 dep.check(ctx, snapshot)
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.
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)
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)
123 return nil, nil, errors.Errorf("no metadata for %s", id)
125 goFiles, err := s.parseGoHandles(ctx, m.goFiles, mode)
129 compiledGoFiles, err := s.parseGoHandles(ctx, m.compiledGoFiles, mode)
133 ph := &packageHandle{
136 compiledGoFiles: compiledGoFiles,
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]
145 deps := make(map[packagePath]*packageHandle)
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))
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()
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)))
161 deps[depHandle.m.pkgPath] = depHandle
162 depKeys = append(depKeys, depHandle.key)
164 experimentalKey := s.View().Options().ExperimentalPackageCacheKey
165 ph.key = checkPackageKey(ctx, ph.m.id, compiledGoFiles, m.config, depKeys, mode, experimentalKey)
169 func (s *snapshot) workspaceParseMode(id packageID) source.ParseMode {
170 if _, ws := s.isWorkspacePackage(id); ws {
171 return source.ParseFull
173 return source.ParseExported
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))
187 b.WriteByte(byte(mode))
188 for _, dep := range deps {
189 b.WriteString(string(dep))
191 for _, cgf := range pghs {
192 b.WriteString(cgf.file.FileIdentity().String())
194 return packageHandleKey(hashContents(b.Bytes()))
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()
204 for _, e := range env {
207 return hashContents(b.Bytes())
210 // hashConfig returns the hash for the *packages.Config.
211 func hashConfig(config *packages.Config) string {
212 b := bytes.NewBuffer(nil)
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)))
218 for _, e := range config.Env {
221 for _, f := range config.BuildFlags {
224 return hashContents(b.Bytes())
227 func (ph *packageHandle) Check(ctx context.Context, s source.Snapshot) (source.Package, error) {
228 return ph.check(ctx, s.(*snapshot))
231 func (ph *packageHandle) check(ctx context.Context, s *snapshot) (*pkg, error) {
232 v, err := ph.handle.Get(ctx, s.generation, s)
236 data := v.(*packageData)
237 return data.pkg, data.err
240 func (ph *packageHandle) CompiledGoFiles() []span.URI {
241 return ph.m.compiledGoFiles
244 func (ph *packageHandle) ID() string {
245 return string(ph.m.id)
248 func (ph *packageHandle) cached(g *memoize.Generation) (*pkg, error) {
249 v := ph.handle.Cached(g)
251 return nil, errors.Errorf("no cached type information for %s", ph.m.pkgPath)
253 data := v.(*packageData)
254 return data.pkg, data.err
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)
264 pghs = append(pghs, s.parseGoHandle(ctx, fh, mode))
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)))
273 fset := snapshot.view.session.cache.fset
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),
290 // If this is a replaced module in the workspace, the version is
291 // meaningless, and we don't want clients to access it.
293 version := m.module.Version
294 if source.IsWorkspaceModuleVersion(version) {
297 pkg.version = &module.Version{
303 files = make([]*ast.File, len(m.compiledGoFiles))
304 parseErrors = make([]scanner.ErrorList, len(m.compiledGoFiles))
305 actualErrors = make([]error, len(m.compiledGoFiles))
311 for i, cgf := range m.compiledGoFiles {
313 go func(i int, cgf span.URI) {
315 fh, err := snapshot.GetFile(ctx, cgf)
317 actualErrors[i] = err
320 pgh := snapshot.parseGoHandle(ctx, fh, mode)
321 pgf, fixed, err := snapshot.parseGo(ctx, pgh)
323 actualErrors[i] = err
326 pkg.compiledGoFiles[i] = pgf
327 files[i], parseErrors[i], actualErrors[i] = pgf.File, pgf.ParseErr, err
329 // If we have fixed parse errors in any of the files, we should hide type
330 // errors, as they may be completely nonsensical.
332 haveFixedFiles = haveFixedFiles || fixed
336 for i, gf := range m.goFiles {
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) {
341 fh, err := snapshot.GetFile(ctx, gf)
345 pgf, _ := snapshot.ParseGo(ctx, fh, mode)
350 for _, err := range actualErrors {
357 for _, e := range parseErrors {
363 parseErrors = parseErrors[:i]
366 for _, f := range files {
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.
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.
383 for _, e := range m.errors {
384 srcDiags, err := goPackagesErrorDiagnostics(ctx, snapshot, pkg, e)
389 pkg.diagnostics = append(pkg.diagnostics, srcDiags...)
394 return nil, errors.Errorf("no parsed files for package %s, expected: %v, errors: %v", pkg.m.pkgPath, pkg.compiledGoFiles, m.errors)
396 pkg.types = types.NewPackage(string(m.pkgPath), string(m.name))
399 var typeErrors []types.Error
400 cfg := &types.Config{
401 Error: func(e error) {
402 typeErrors = append(typeErrors, e.(types.Error))
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()
409 dep := resolveImportPath(pkgPath, pkg, deps)
411 return nil, snapshot.missingPkgError(pkgPath)
413 if !isValidImport(m.pkgPath, dep.m.pkgPath) {
414 return nil, errors.Errorf("invalid use of internal package %s", pkgPath)
416 depPkg, err := dep.check(ctx, snapshot)
420 pkg.imports[depPkg.m.pkgPath] = depPkg
421 return depPkg.types, nil
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)
428 check := types.NewChecker(cfg, fset, pkg.types, pkg.typesInfo)
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()
438 // We don't care about a package's errors unless we have parsed it in full.
439 if mode != source.ParseFull {
443 if len(m.errors) != 0 {
444 pkg.hasListOrParseErrors = true
445 for _, e := range m.errors {
446 diags, err := goPackagesErrorDiagnostics(ctx, snapshot, pkg, e)
448 event.Error(ctx, "unable to compute positions for list errors", err, tag.Package.Of(pkg.ID()))
451 pkg.diagnostics = append(pkg.diagnostics, diags...)
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.
465 // Track URIs with parse errors so that we can suppress type errors for these
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)
473 event.Error(ctx, "unable to compute positions for parse errors", err, tag.Package.Of(pkg.ID()))
476 for _, diag := range diags {
477 unparseable[diag.URI] = true
478 pkg.diagnostics = append(pkg.diagnostics, diag)
487 for _, e := range expandErrors(typeErrors, snapshot.View().Options().RelatedInformationSupported) {
488 pkg.hasTypeErrors = true
489 diags, err := typeErrorDiagnostics(ctx, snapshot, pkg, e)
491 event.Error(ctx, "unable to compute positions for type errors", err, tag.Package.Of(pkg.ID()))
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)
505 depsErrors, err := snapshot.depsErrors(ctx, pkg)
509 pkg.diagnostics = append(pkg.diagnostics, depsErrors...)
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
525 if directImporterIdx < 0 {
529 directImporter := depsError.ImportStack[directImporterIdx]
530 if _, ok := s.isWorkspacePackage(packageID(directImporter)); ok {
533 relevantErrors = append(relevantErrors, depsError)
536 // Don't build the import index for nothing.
537 if len(relevantErrors) == 0 {
541 // Build an index of all imports in the package.
542 type fileImport struct {
543 cgf *source.ParsedGoFile
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 {
553 path := strings.Trim(imp.Path.Value, `"`)
554 allImports[path] = append(allImports[path], fileImport{cgf, imp})
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 {
569 for _, imp := range allImports[item] {
570 rng, err := source.NewMappedRange(s.FileSet(), imp.cgf.Mapper, imp.imp.Pos(), imp.imp.End()).Range()
574 fixes, err := goGetQuickFixes(s, imp.cgf.URI, item)
578 errors = append(errors, &source.Diagnostic{
581 Severity: protocol.SeverityError,
582 Source: source.TypeError,
583 Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
584 SuggestedFixes: fixes,
590 if len(pkg.compiledGoFiles) == 0 {
593 mod := s.GoModForFile(pkg.compiledGoFiles[0].URI)
597 fh, err := s.GetFile(ctx, mod)
601 pm, err := s.ParseMod(ctx, fh)
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 {
615 modVer := module.Version{Path: m.module.Path, Version: m.module.Version}
616 reference := findModuleReference(pm.File, modVer)
617 if reference == nil {
620 rng, err := rangeFromPositions(pm.Mapper, reference.Start, reference.End)
624 fixes, err := goGetQuickFixes(s, pm.URI, item)
628 errors = append(errors, &source.Diagnostic{
631 Severity: protocol.SeverityError,
632 Source: source.TypeError,
633 Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
634 SuggestedFixes: fixes,
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)
648 gorootSrcPkg := filepath.FromSlash(filepath.Join(s.view.goroot, "src", pkgPath))
650 var b strings.Builder
651 b.WriteString(fmt.Sprintf("cannot find package %q in any of \n\t%s (from $GOROOT)", pkgPath, gorootSrcPkg))
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))
657 return errors.New(b.String())
660 type extendedError struct {
662 secondaries []types.Error
665 func (e extendedError) Error() string {
666 return e.primary.Error()
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.
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.
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{
687 for i++; i < len(errs); i++ {
689 if len(spl.Msg) == 0 || spl.Msg[0] != '\t' {
692 spl.Msg = spl.Msg[1:]
693 original.secondaries = append(original.secondaries, spl)
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)
707 relocatedSecondary.Msg = fmt.Sprintf("%v (this error: %v)", original.primary.Msg, mainSecondary.Msg)
709 relocatedSecondary.Soft = original.primary.Soft
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 {
716 secondary.Msg += " (this error)"
718 clonedError.secondaries = append(clonedError.secondaries, secondary)
720 result = append(result, clonedError)
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 {
734 // We may be in GOPATH mode, in which case we need to check vendor dirs.
735 searchDir := path.Dir(pkg.PkgPath())
737 vdir := packagePath(path.Join(searchDir, "vendor", importPath))
738 if vdep := deps[vdir]; vdep != nil {
742 // Search until Dir doesn't take us anywhere new, e.g. "." or "/".
743 next := path.Dir(searchDir)
744 if searchDir == next {
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 {
762 func isValidImport(pkgPath, importPkgPath packagePath) bool {
763 i := strings.LastIndex(string(importPkgPath), "/internal/")
767 if pkgPath == "command-line-arguments" {
770 return strings.HasPrefix(string(pkgPath), string(importPkgPath[:i]))
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)
777 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }