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 &copy
   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) }