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