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