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