cuelang.org/go@v0.13.0/internal/golangorgx/gopls/cache/check.go (about) 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 "context" 9 "crypto/sha256" 10 "fmt" 11 "go/parser" 12 "go/token" 13 "go/types" 14 "regexp" 15 "sort" 16 "sync" 17 18 "cuelang.org/go/internal/golangorgx/gopls/cache/metadata" 19 "cuelang.org/go/internal/golangorgx/gopls/cache/typerefs" 20 "cuelang.org/go/internal/golangorgx/gopls/file" 21 "cuelang.org/go/internal/golangorgx/gopls/filecache" 22 "cuelang.org/go/internal/golangorgx/gopls/protocol" 23 "cuelang.org/go/internal/golangorgx/gopls/util/bug" 24 "cuelang.org/go/internal/golangorgx/gopls/util/safetoken" 25 "cuelang.org/go/internal/golangorgx/tools/analysisinternal" 26 "cuelang.org/go/internal/golangorgx/tools/event" 27 "cuelang.org/go/internal/golangorgx/tools/event/tag" 28 "cuelang.org/go/internal/golangorgx/tools/typesinternal" 29 ) 30 31 // Various optimizations that should not affect correctness. 32 const ( 33 preserveImportGraph = true // hold on to the import graph for open packages 34 ) 35 36 type unit = struct{} 37 38 // A typeCheckBatch holds data for a logical type-checking operation, which may 39 // type-check many unrelated packages. 40 // 41 // It shares state such as parsed files and imports, to optimize type-checking 42 // for packages with overlapping dependency graphs. 43 type typeCheckBatch struct { 44 activePackageCache interface { 45 getActivePackage(id PackageID) *Package 46 setActivePackage(id PackageID, pkg *Package) 47 } 48 syntaxIndex map[PackageID]int // requested ID -> index in ids 49 pre preTypeCheck 50 post postTypeCheck 51 handles map[PackageID]*packageHandle 52 parseCache *parseCache 53 fset *token.FileSet // describes all parsed or imported files 54 cpulimit chan unit // concurrency limiter for CPU-bound operations 55 56 mu sync.Mutex 57 syntaxPackages map[PackageID]*futurePackage // results of processing a requested package; may hold (nil, nil) 58 importPackages map[PackageID]*futurePackage // package results to use for importing 59 } 60 61 // A futurePackage is a future result of type checking or importing a package, 62 // to be cached in a map. 63 // 64 // The goroutine that creates the futurePackage is responsible for evaluating 65 // its value, and closing the done channel. 66 type futurePackage struct { 67 done chan unit 68 v pkgOrErr 69 } 70 71 type pkgOrErr struct { 72 pkg *types.Package 73 err error 74 } 75 76 // An importGraph holds selected results of a type-checking pass, to be re-used 77 // by subsequent snapshots. 78 type importGraph struct { 79 fset *token.FileSet // fileset used for type checking imports 80 depKeys map[PackageID]file.Hash // hash of direct dependencies for this graph 81 imports map[PackageID]pkgOrErr // results of type checking 82 } 83 84 // Package visiting functions used by forEachPackage; see the documentation of 85 // forEachPackage for details. 86 type ( 87 preTypeCheck = func(int, *packageHandle) bool // false => don't type check 88 postTypeCheck = func(int, *Package) 89 ) 90 91 // forEachPackage does a pre- and post- order traversal of the packages 92 // specified by ids using the provided pre and post functions. 93 // 94 // The pre func is optional. If set, pre is evaluated after the package 95 // handle has been constructed, but before type-checking. If pre returns false, 96 // type-checking is skipped for this package handle. 97 // 98 // post is called with a syntax package after type-checking completes 99 // successfully. It is only called if pre returned true. 100 // 101 // Both pre and post may be called concurrently. 102 func (s *Snapshot) forEachPackage(ctx context.Context, ids []PackageID, pre preTypeCheck, post postTypeCheck) error { 103 ctx, done := event.Start(ctx, "cache.forEachPackage", tag.PackageCount.Of(len(ids))) 104 defer done() 105 106 return nil 107 } 108 109 // A packageHandle holds inputs required to compute a Package, including 110 // metadata, derived diagnostics, files, and settings. Additionally, 111 // packageHandles manage a key for these inputs, to use in looking up 112 // precomputed results. 113 // 114 // packageHandles may be invalid following an invalidation via snapshot.clone, 115 // but the handles returned by getPackageHandles will always be valid. 116 // 117 // packageHandles are critical for implementing "precise pruning" in gopls: 118 // packageHandle.key is a hash of a precise set of inputs, such as package 119 // files and "reachable" syntax, that may affect type checking. 120 // 121 // packageHandles also keep track of state that allows gopls to compute, and 122 // then quickly recompute, these keys. This state is split into two categories: 123 // - local state, which depends only on the package's local files and metadata 124 // - other state, which includes data derived from dependencies. 125 // 126 // Dividing the data in this way allows gopls to minimize invalidation when a 127 // package is modified. For example, any change to a package file fully 128 // invalidates the package handle. On the other hand, if that change was not 129 // metadata-affecting it may be the case that packages indirectly depending on 130 // the modified package are unaffected by the change. For that reason, we have 131 // two types of invalidation, corresponding to the two types of data above: 132 // - deletion of the handle, which occurs when the package itself changes 133 // - clearing of the validated field, which marks the package as possibly 134 // invalid. 135 // 136 // With the second type of invalidation, packageHandles are re-evaluated from the 137 // bottom up. If this process encounters a packageHandle whose deps have not 138 // changed (as detected by the depkeys field), then the packageHandle in 139 // question must also not have changed, and we need not re-evaluate its key. 140 type packageHandle struct { 141 mp *metadata.Package 142 143 // loadDiagnostics memoizes the result of processing error messages from 144 // go/packages (i.e. `go list`). 145 // 146 // These are derived from metadata using a snapshot. Since they depend on 147 // file contents (for translating positions), they should theoretically be 148 // invalidated by file changes, but historically haven't been. In practice 149 // they are rare and indicate a fundamental error that needs to be corrected 150 // before development can continue, so it may not be worth significant 151 // engineering effort to implement accurate invalidation here. 152 // 153 // TODO(rfindley): loadDiagnostics are out of place here, as they don't 154 // directly relate to type checking. We should perhaps move the caching of 155 // load diagnostics to an entirely separate component, so that Packages need 156 // only be concerned with parsing and type checking. 157 // (Nevertheless, since the lifetime of load diagnostics matches that of the 158 // Metadata, it is convenient to memoize them here.) 159 loadDiagnostics []*Diagnostic 160 161 // Local data: 162 163 // localInputs holds all local type-checking localInputs, excluding 164 // dependencies. 165 localInputs typeCheckInputs 166 // localKey is a hash of localInputs. 167 localKey file.Hash 168 // refs is the result of syntactic dependency analysis produced by the 169 // typerefs package. 170 refs map[string][]typerefs.Symbol 171 172 // Data derived from dependencies: 173 174 // validated indicates whether the current packageHandle is known to have a 175 // valid key. Invalidated package handles are stored for packages whose 176 // type information may have changed. 177 validated bool 178 // depKeys records the key of each dependency that was used to calculate the 179 // key above. If the handle becomes invalid, we must re-check that each still 180 // matches. 181 depKeys map[PackageID]file.Hash 182 // key is the hashed key for the package. 183 // 184 // It includes the all bits of the transitive closure of 185 // dependencies's sources. 186 key file.Hash 187 } 188 189 // clone returns a copy of the receiver with the validated bit set to the 190 // provided value. 191 func (ph *packageHandle) clone(validated bool) *packageHandle { 192 copy := *ph 193 copy.validated = validated 194 return © 195 } 196 197 // A packageHandleBuilder computes a batch of packageHandles concurrently, 198 // sharing computed transitive reachability sets used to compute package keys. 199 type packageHandleBuilder struct { 200 s *Snapshot 201 202 // nodes are assembled synchronously. 203 nodes map[typerefs.IndexID]*handleNode 204 205 // transitiveRefs is incrementally evaluated as package handles are built. 206 transitiveRefsMu sync.Mutex 207 transitiveRefs map[typerefs.IndexID]*partialRefs // see getTransitiveRefs 208 } 209 210 // A handleNode represents a to-be-computed packageHandle within a graph of 211 // predecessors and successors. 212 // 213 // It is used to implement a bottom-up construction of packageHandles. 214 type handleNode struct { 215 mp *metadata.Package 216 idxID typerefs.IndexID 217 ph *packageHandle 218 err error 219 preds []*handleNode 220 succs map[PackageID]*handleNode 221 unfinishedSuccs int32 222 } 223 224 // partialRefs maps names declared by a given package to their set of 225 // transitive references. 226 // 227 // If complete is set, refs is known to be complete for the package in 228 // question. Otherwise, it may only map a subset of all names declared by the 229 // package. 230 type partialRefs struct { 231 refs map[string]*typerefs.PackageSet 232 complete bool 233 } 234 235 // getTransitiveRefs gets or computes the set of transitively reachable 236 // packages for each exported name in the package specified by id. 237 // 238 // The operation may fail if building a predecessor failed. If and only if this 239 // occurs, the result will be nil. 240 func (b *packageHandleBuilder) getTransitiveRefs(pkgID PackageID) map[string]*typerefs.PackageSet { 241 b.transitiveRefsMu.Lock() 242 defer b.transitiveRefsMu.Unlock() 243 244 idxID := b.s.pkgIndex.IndexID(pkgID) 245 trefs, ok := b.transitiveRefs[idxID] 246 if !ok { 247 trefs = &partialRefs{ 248 refs: make(map[string]*typerefs.PackageSet), 249 } 250 b.transitiveRefs[idxID] = trefs 251 } 252 253 if !trefs.complete { 254 trefs.complete = true 255 ph := b.nodes[idxID].ph 256 for name := range ph.refs { 257 if ('A' <= name[0] && name[0] <= 'Z') || token.IsExported(name) { 258 if _, ok := trefs.refs[name]; !ok { 259 pkgs := b.s.pkgIndex.NewSet() 260 for _, sym := range ph.refs[name] { 261 pkgs.Add(sym.Package) 262 otherSet := b.getOneTransitiveRefLocked(sym) 263 pkgs.Union(otherSet) 264 } 265 trefs.refs[name] = pkgs 266 } 267 } 268 } 269 } 270 271 return trefs.refs 272 } 273 274 // getOneTransitiveRefLocked computes the full set packages transitively 275 // reachable through the given sym reference. 276 // 277 // It may return nil if the reference is invalid (i.e. the referenced name does 278 // not exist). 279 func (b *packageHandleBuilder) getOneTransitiveRefLocked(sym typerefs.Symbol) *typerefs.PackageSet { 280 assert(token.IsExported(sym.Name), "expected exported symbol") 281 282 trefs := b.transitiveRefs[sym.Package] 283 if trefs == nil { 284 trefs = &partialRefs{ 285 refs: make(map[string]*typerefs.PackageSet), 286 complete: false, 287 } 288 b.transitiveRefs[sym.Package] = trefs 289 } 290 291 pkgs, ok := trefs.refs[sym.Name] 292 if ok && pkgs == nil { 293 // See below, where refs is set to nil before recursing. 294 bug.Reportf("cycle detected to %q in reference graph", sym.Name) 295 } 296 297 // Note that if (!ok && trefs.complete), the name does not exist in the 298 // referenced package, and we should not write to trefs as that may introduce 299 // a race. 300 if !ok && !trefs.complete { 301 n := b.nodes[sym.Package] 302 if n == nil { 303 // We should always have IndexID in our node set, because symbol references 304 // should only be recorded for packages that actually exist in the import graph. 305 // 306 // However, it is not easy to prove this (typerefs are serialized and 307 // deserialized), so make this code temporarily defensive while we are on a 308 // point release. 309 // 310 // TODO(rfindley): in the future, we should turn this into an assertion. 311 bug.Reportf("missing reference to package %s", b.s.pkgIndex.PackageID(sym.Package)) 312 return nil 313 } 314 315 // Break cycles. This is perhaps overly defensive as cycles should not 316 // exist at this point: metadata cycles should have been broken at load 317 // time, and intra-package reference cycles should have been contracted by 318 // the typerefs algorithm. 319 // 320 // See the "cycle detected" bug report above. 321 trefs.refs[sym.Name] = nil 322 323 pkgs := b.s.pkgIndex.NewSet() 324 for _, sym2 := range n.ph.refs[sym.Name] { 325 pkgs.Add(sym2.Package) 326 otherSet := b.getOneTransitiveRefLocked(sym2) 327 pkgs.Union(otherSet) 328 } 329 trefs.refs[sym.Name] = pkgs 330 } 331 332 return pkgs 333 } 334 335 // evaluatePackageHandle validates and/or computes the key of ph, setting key, 336 // depKeys, and the validated flag on ph. 337 // 338 // It uses prevPH to avoid recomputing keys that can't have changed, since 339 // their depKeys did not change. 340 // 341 // See the documentation for packageHandle for more details about packageHandle 342 // state, and see the documentation for the typerefs package for more details 343 // about precise reachability analysis. 344 func (b *packageHandleBuilder) evaluatePackageHandle(prevPH *packageHandle, n *handleNode) error { 345 // Opt: if no dep keys have changed, we need not re-evaluate the key. 346 if prevPH != nil { 347 depsChanged := false 348 assert(len(prevPH.depKeys) == len(n.succs), "mismatching dep count") 349 for id, succ := range n.succs { 350 oldKey, ok := prevPH.depKeys[id] 351 assert(ok, "missing dep") 352 if oldKey != succ.ph.key { 353 depsChanged = true 354 break 355 } 356 } 357 if !depsChanged { 358 return nil // key cannot have changed 359 } 360 } 361 362 // Deps have changed, so we must re-evaluate the key. 363 n.ph.depKeys = make(map[PackageID]file.Hash) 364 365 // See the typerefs package: the reachable set of packages is defined to be 366 // the set of packages containing syntax that is reachable through the 367 // exported symbols in the dependencies of n.ph. 368 reachable := b.s.pkgIndex.NewSet() 369 for depID, succ := range n.succs { 370 n.ph.depKeys[depID] = succ.ph.key 371 reachable.Add(succ.idxID) 372 trefs := b.getTransitiveRefs(succ.mp.ID) 373 if trefs == nil { 374 // A predecessor failed to build due to e.g. context cancellation. 375 return fmt.Errorf("missing transitive refs for %s", succ.mp.ID) 376 } 377 for _, set := range trefs { 378 reachable.Union(set) 379 } 380 } 381 382 // Collect reachable handles. 383 var reachableHandles []*packageHandle 384 // In the presence of context cancellation, any package may be missing. 385 // We need all dependencies to produce a valid key. 386 missingReachablePackage := false 387 reachable.Elems(func(id typerefs.IndexID) { 388 dh := b.nodes[id] 389 if dh == nil { 390 missingReachablePackage = true 391 } else { 392 assert(dh.ph.validated, "unvalidated dependency") 393 reachableHandles = append(reachableHandles, dh.ph) 394 } 395 }) 396 if missingReachablePackage { 397 return fmt.Errorf("missing reachable package") 398 } 399 // Sort for stability. 400 sort.Slice(reachableHandles, func(i, j int) bool { 401 return reachableHandles[i].mp.ID < reachableHandles[j].mp.ID 402 }) 403 404 // Key is the hash of the local key, and the local key of all reachable 405 // packages. 406 depHasher := sha256.New() 407 depHasher.Write(n.ph.localKey[:]) 408 for _, rph := range reachableHandles { 409 depHasher.Write(rph.localKey[:]) 410 } 411 depHasher.Sum(n.ph.key[:0]) 412 413 return nil 414 } 415 416 // typerefData retrieves encoded typeref data from the filecache, or computes it on 417 // a cache miss. 418 func (s *Snapshot) typerefData(ctx context.Context, id PackageID, imports map[ImportPath]*metadata.Package, cgfs []file.Handle) ([]byte, error) { 419 key := typerefsKey(id, imports, cgfs) 420 if data, err := filecache.Get(typerefsKind, key); err == nil { 421 return data, nil 422 } else if err != filecache.ErrNotFound { 423 bug.Reportf("internal error reading typerefs data: %v", err) 424 } 425 426 pgfs, err := s.view.parseCache.parseFiles(ctx, token.NewFileSet(), ParseFull&^parser.ParseComments, true, cgfs...) 427 if err != nil { 428 return nil, err 429 } 430 data := typerefs.Encode(pgfs, imports) 431 432 // Store the resulting data in the cache. 433 go func() { 434 if err := filecache.Set(typerefsKind, key, data); err != nil { 435 event.Error(ctx, fmt.Sprintf("storing typerefs data for %s", id), err) 436 } 437 }() 438 439 return data, nil 440 } 441 442 // typerefsKey produces a key for the reference information produced by the 443 // typerefs package. 444 func typerefsKey(id PackageID, imports map[ImportPath]*metadata.Package, compiledGoFiles []file.Handle) file.Hash { 445 hasher := sha256.New() 446 447 fmt.Fprintf(hasher, "typerefs: %s\n", id) 448 449 importPaths := make([]string, 0, len(imports)) 450 for impPath := range imports { 451 importPaths = append(importPaths, string(impPath)) 452 } 453 sort.Strings(importPaths) 454 for _, importPath := range importPaths { 455 imp := imports[ImportPath(importPath)] 456 // TODO(rfindley): strength reduce the typerefs.Export API to guarantee 457 // that it only depends on these attributes of dependencies. 458 fmt.Fprintf(hasher, "import %s %s %s", importPath, imp.ID, imp.Name) 459 } 460 461 fmt.Fprintf(hasher, "compiledGoFiles: %d\n", len(compiledGoFiles)) 462 for _, fh := range compiledGoFiles { 463 fmt.Fprintln(hasher, fh.Identity()) 464 } 465 466 var hash [sha256.Size]byte 467 hasher.Sum(hash[:0]) 468 return hash 469 } 470 471 // typeCheckInputs contains the inputs of a call to typeCheckImpl, which 472 // type-checks a package. 473 // 474 // Part of the purpose of this type is to keep type checking in-sync with the 475 // package handle key, by explicitly identifying the inputs to type checking. 476 type typeCheckInputs struct { 477 id PackageID 478 479 // Used for type checking: 480 pkgPath PackagePath 481 name PackageName 482 goFiles, compiledGoFiles []file.Handle 483 sizes types.Sizes 484 depsByImpPath map[ImportPath]PackageID 485 goVersion string // packages.Module.GoVersion, e.g. "1.18" 486 487 // Used for type check diagnostics: 488 // TODO(rfindley): consider storing less data in gobDiagnostics, and 489 // interpreting each diagnostic in the context of a fixed set of options. 490 // Then these fields need not be part of the type checking inputs. 491 relatedInformation bool 492 linkTarget string 493 moduleMode bool 494 } 495 496 func (s *Snapshot) typeCheckInputs(ctx context.Context, mp *metadata.Package) (typeCheckInputs, error) { 497 // Read both lists of files of this package. 498 // 499 // Parallelism is not necessary here as the files will have already been 500 // pre-read at load time. 501 // 502 // goFiles aren't presented to the type checker--nor 503 // are they included in the key, unsoundly--but their 504 // syntax trees are available from (*pkg).File(URI). 505 // TODO(adonovan): consider parsing them on demand? 506 // The need should be rare. 507 goFiles, err := readFiles(ctx, s, mp.GoFiles) 508 if err != nil { 509 return typeCheckInputs{}, err 510 } 511 compiledGoFiles, err := readFiles(ctx, s, mp.CompiledGoFiles) 512 if err != nil { 513 return typeCheckInputs{}, err 514 } 515 516 goVersion := "" 517 if mp.Module != nil && mp.Module.GoVersion != "" { 518 goVersion = mp.Module.GoVersion 519 } 520 521 return typeCheckInputs{ 522 id: mp.ID, 523 pkgPath: mp.PkgPath, 524 name: mp.Name, 525 goFiles: goFiles, 526 compiledGoFiles: compiledGoFiles, 527 sizes: mp.TypesSizes, 528 depsByImpPath: mp.DepsByImpPath, 529 goVersion: goVersion, 530 531 relatedInformation: s.Options().RelatedInformationSupported, 532 linkTarget: s.Options().LinkTarget, 533 moduleMode: s.view.moduleMode(), 534 }, nil 535 } 536 537 // readFiles reads the content of each file URL from the source 538 // (e.g. snapshot or cache). 539 func readFiles(ctx context.Context, fs file.Source, uris []protocol.DocumentURI) (_ []file.Handle, err error) { 540 fhs := make([]file.Handle, len(uris)) 541 for i, uri := range uris { 542 fhs[i], err = fs.ReadFile(ctx, uri) 543 if err != nil { 544 return nil, err 545 } 546 } 547 return fhs, nil 548 } 549 550 // localPackageKey returns a key for local inputs into type-checking, excluding 551 // dependency information: files, metadata, and configuration. 552 func localPackageKey(inputs typeCheckInputs) file.Hash { 553 hasher := sha256.New() 554 555 // In principle, a key must be the hash of an 556 // unambiguous encoding of all the relevant data. 557 // If it's ambiguous, we risk collisions. 558 559 // package identifiers 560 fmt.Fprintf(hasher, "package: %s %s %s\n", inputs.id, inputs.name, inputs.pkgPath) 561 562 // module Go version 563 fmt.Fprintf(hasher, "go %s\n", inputs.goVersion) 564 565 // import map 566 importPaths := make([]string, 0, len(inputs.depsByImpPath)) 567 for impPath := range inputs.depsByImpPath { 568 importPaths = append(importPaths, string(impPath)) 569 } 570 sort.Strings(importPaths) 571 for _, impPath := range importPaths { 572 fmt.Fprintf(hasher, "import %s %s", impPath, string(inputs.depsByImpPath[ImportPath(impPath)])) 573 } 574 575 // file names and contents 576 fmt.Fprintf(hasher, "compiledGoFiles: %d\n", len(inputs.compiledGoFiles)) 577 for _, fh := range inputs.compiledGoFiles { 578 fmt.Fprintln(hasher, fh.Identity()) 579 } 580 fmt.Fprintf(hasher, "goFiles: %d\n", len(inputs.goFiles)) 581 for _, fh := range inputs.goFiles { 582 fmt.Fprintln(hasher, fh.Identity()) 583 } 584 585 // types sizes 586 wordSize := inputs.sizes.Sizeof(types.Typ[types.Int]) 587 maxAlign := inputs.sizes.Alignof(types.NewPointer(types.Typ[types.Int64])) 588 fmt.Fprintf(hasher, "sizes: %d %d\n", wordSize, maxAlign) 589 590 fmt.Fprintf(hasher, "relatedInformation: %t\n", inputs.relatedInformation) 591 fmt.Fprintf(hasher, "linkTarget: %s\n", inputs.linkTarget) 592 fmt.Fprintf(hasher, "moduleMode: %t\n", inputs.moduleMode) 593 594 var hash [sha256.Size]byte 595 hasher.Sum(hash[:0]) 596 return hash 597 } 598 599 // e.g. "go1" or "go1.2" or "go1.2.3" 600 var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*(?:\.(0|[1-9][0-9]*)){0,2}$`) 601 602 // typeErrorsToDiagnostics translates a slice of types.Errors into a slice of 603 // Diagnostics. 604 // 605 // In addition to simply mapping data such as position information and error 606 // codes, this function interprets related go/types "continuation" errors as 607 // protocol.DiagnosticRelatedInformation. Continuation errors are go/types 608 // errors whose messages starts with "\t". By convention, these errors relate 609 // to the previous error in the errs slice (such as if they were printed in 610 // sequence to a terminal). 611 // 612 // The linkTarget, moduleMode, and supportsRelatedInformation parameters affect 613 // the construction of protocol objects (see the code for details). 614 func typeErrorsToDiagnostics(pkg *syntaxPackage, errs []types.Error, linkTarget string, moduleMode, supportsRelatedInformation bool) []*Diagnostic { 615 var result []*Diagnostic 616 617 // batch records diagnostics for a set of related types.Errors. 618 batch := func(related []types.Error) { 619 var diags []*Diagnostic 620 for i, e := range related { 621 code, start, end, ok := typesinternal.ReadGo116ErrorData(e) 622 if !ok || !start.IsValid() || !end.IsValid() { 623 start, end = e.Pos, e.Pos 624 code = 0 625 } 626 if !start.IsValid() { 627 // Type checker errors may be missing position information if they 628 // relate to synthetic syntax, such as if the file were fixed. In that 629 // case, we should have a parse error anyway, so skipping the type 630 // checker error is likely benign. 631 // 632 // TODO(golang/go#64335): we should eventually verify that all type 633 // checked syntax has valid positions, and promote this skip to a bug 634 // report. 635 continue 636 } 637 posn := safetoken.StartPosition(e.Fset, start) 638 if !posn.IsValid() { 639 // All valid positions produced by the type checker should described by 640 // its fileset. 641 // 642 // Note: in golang/go#64488, we observed an error that was positioned 643 // over fixed syntax, which overflowed its file. So it's definitely 644 // possible that we get here (it's hard to reason about fixing up the 645 // AST). Nevertheless, it's a bug. 646 bug.Reportf("internal error: type checker error %q outside its Fset", e) 647 continue 648 } 649 pgf, err := pkg.File(protocol.URIFromPath(posn.Filename)) 650 if err != nil { 651 // Sometimes type-checker errors refer to positions in other packages, 652 // such as when a declaration duplicates a dot-imported name. 653 // 654 // In these cases, we don't want to report an error in the other 655 // package (the message would be rather confusing), but we do want to 656 // report an error in the current package (golang/go#59005). 657 if i == 0 { 658 bug.Reportf("internal error: could not locate file for primary type checker error %v: %v", e, err) 659 } 660 continue 661 } 662 if !end.IsValid() || end == start { 663 // Expand the end position to a more meaningful span. 664 end = analysisinternal.TypeErrorEndPos(e.Fset, pgf.Src, start) 665 } 666 rng, err := pgf.Mapper.PosRange(pgf.Tok, start, end) 667 if err != nil { 668 bug.Reportf("internal error: could not compute pos to range for %v: %v", e, err) 669 continue 670 } 671 msg := related[0].Msg 672 if i > 0 { 673 if supportsRelatedInformation { 674 msg += " (see details)" 675 } else { 676 msg += fmt.Sprintf(" (this error: %v)", e.Msg) 677 } 678 } 679 diag := &Diagnostic{ 680 URI: pgf.URI, 681 Range: rng, 682 Severity: protocol.SeverityError, 683 Source: TypeError, 684 Message: msg, 685 } 686 if code != 0 { 687 diag.Code = code.String() 688 diag.CodeHref = typesCodeHref(linkTarget, code) 689 } 690 if code == typesinternal.UnusedVar || code == typesinternal.UnusedImport { 691 diag.Tags = append(diag.Tags, protocol.Unnecessary) 692 } 693 if match := importErrorRe.FindStringSubmatch(e.Msg); match != nil { 694 diag.SuggestedFixes = append(diag.SuggestedFixes, goGetQuickFixes(moduleMode, pgf.URI, match[1])...) 695 } 696 if match := unsupportedFeatureRe.FindStringSubmatch(e.Msg); match != nil { 697 diag.SuggestedFixes = append(diag.SuggestedFixes, editGoDirectiveQuickFix(moduleMode, pgf.URI, match[1])...) 698 } 699 700 // Link up related information. For the primary error, all related errors 701 // are treated as related information. For secondary errors, only the 702 // primary is related. 703 // 704 // This is because go/types assumes that errors are read top-down, such as 705 // in the cycle error "A refers to...". The structure of the secondary 706 // error set likely only makes sense for the primary error. 707 if i > 0 { 708 primary := diags[0] 709 primary.Related = append(primary.Related, protocol.DiagnosticRelatedInformation{ 710 Location: protocol.Location{URI: diag.URI, Range: diag.Range}, 711 Message: related[i].Msg, // use the unmodified secondary error for related errors. 712 }) 713 diag.Related = []protocol.DiagnosticRelatedInformation{{ 714 Location: protocol.Location{URI: primary.URI, Range: primary.Range}, 715 }} 716 } 717 diags = append(diags, diag) 718 } 719 result = append(result, diags...) 720 } 721 722 // Process batches of related errors. 723 for len(errs) > 0 { 724 related := []types.Error{errs[0]} 725 for i := 1; i < len(errs); i++ { 726 spl := errs[i] 727 if len(spl.Msg) == 0 || spl.Msg[0] != '\t' { 728 break 729 } 730 spl.Msg = spl.Msg[len("\t"):] 731 related = append(related, spl) 732 } 733 batch(related) 734 errs = errs[len(related):] 735 } 736 737 return result 738 } 739 740 // An importFunc is an implementation of the single-method 741 // types.Importer interface based on a function value. 742 type importerFunc func(path string) (*types.Package, error) 743 744 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }