.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / cache / view.go
1 // Copyright 2018 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 implements the caching layer for gopls.
6 package cache
7
8 import (
9         "context"
10         "encoding/json"
11         "fmt"
12         "io"
13         "io/ioutil"
14         "os"
15         "path"
16         "path/filepath"
17         "reflect"
18         "regexp"
19         "sort"
20         "strings"
21         "sync"
22
23         "golang.org/x/mod/modfile"
24         "golang.org/x/mod/semver"
25         exec "golang.org/x/sys/execabs"
26         "golang.org/x/tools/go/packages"
27         "golang.org/x/tools/internal/event"
28         "golang.org/x/tools/internal/gocommand"
29         "golang.org/x/tools/internal/imports"
30         "golang.org/x/tools/internal/lsp/protocol"
31         "golang.org/x/tools/internal/lsp/source"
32         "golang.org/x/tools/internal/memoize"
33         "golang.org/x/tools/internal/span"
34         "golang.org/x/tools/internal/xcontext"
35         errors "golang.org/x/xerrors"
36 )
37
38 type View struct {
39         session *Session
40         id      string
41
42         optionsMu sync.Mutex
43         options   *source.Options
44
45         // mu protects most mutable state of the view.
46         mu sync.Mutex
47
48         // baseCtx is the context handed to NewView. This is the parent of all
49         // background contexts created for this view.
50         baseCtx context.Context
51
52         // cancel is called when all action being performed by the current view
53         // should be stopped.
54         cancel context.CancelFunc
55
56         // name is the user visible name of this view.
57         name string
58
59         // folder is the folder with which this view was constructed.
60         folder span.URI
61
62         importsState *importsState
63
64         // moduleUpgrades tracks known upgrades for module paths.
65         moduleUpgrades map[string]string
66
67         // keep track of files by uri and by basename, a single file may be mapped
68         // to multiple uris, and the same basename may map to multiple files
69         filesByURI  map[span.URI]*fileBase
70         filesByBase map[string][]*fileBase
71
72         // initCancelFirstAttempt can be used to terminate the view's first
73         // attempt at initialization.
74         initCancelFirstAttempt context.CancelFunc
75
76         snapshotMu sync.Mutex
77         snapshot   *snapshot
78
79         // initialWorkspaceLoad is closed when the first workspace initialization has
80         // completed. If we failed to load, we only retry if the go.mod file changes,
81         // to avoid too many go/packages calls.
82         initialWorkspaceLoad chan struct{}
83
84         // initializationSema is used limit concurrent initialization of snapshots in
85         // the view. We use a channel instead of a mutex to avoid blocking when a
86         // context is canceled.
87         initializationSema chan struct{}
88
89         // rootURI is the rootURI directory of this view. If we are in GOPATH mode, this
90         // is just the folder. If we are in module mode, this is the module rootURI.
91         rootURI span.URI
92
93         // workspaceInformation tracks various details about this view's
94         // environment variables, go version, and use of modules.
95         workspaceInformation
96
97         // tempWorkspace is a temporary directory dedicated to holding the latest
98         // version of the workspace go.mod file. (TODO: also go.sum file)
99         tempWorkspace span.URI
100 }
101
102 type workspaceInformation struct {
103         // The Go version in use: X in Go 1.X.
104         goversion int
105
106         // hasGopackagesDriver is true if the user has a value set for the
107         // GOPACKAGESDRIVER environment variable or a gopackagesdriver binary on
108         // their machine.
109         hasGopackagesDriver bool
110
111         // `go env` variables that need to be tracked by gopls.
112         environmentVariables
113
114         // userGo111Module is the user's value of GO111MODULE.
115         userGo111Module go111module
116
117         // The value of GO111MODULE we want to run with.
118         effectiveGo111Module string
119
120         // goEnv is the `go env` output collected when a view is created.
121         // It includes the values of the environment variables above.
122         goEnv map[string]string
123 }
124
125 type go111module int
126
127 const (
128         off = go111module(iota)
129         auto
130         on
131 )
132
133 type environmentVariables struct {
134         gocache, gopath, goroot, goprivate, gomodcache, go111module string
135 }
136
137 type workspaceMode int
138
139 const (
140         moduleMode workspaceMode = 1 << iota
141
142         // tempModfile indicates whether or not the -modfile flag should be used.
143         tempModfile
144
145         // usesWorkspaceModule indicates support for the experimental workspace module
146         // feature.
147         usesWorkspaceModule
148 )
149
150 type builtinPackageHandle struct {
151         handle *memoize.Handle
152 }
153
154 type builtinPackageData struct {
155         parsed *source.BuiltinPackage
156         err    error
157 }
158
159 // fileBase holds the common functionality for all files.
160 // It is intended to be embedded in the file implementations
161 type fileBase struct {
162         uris  []span.URI
163         fname string
164
165         view *View
166 }
167
168 func (f *fileBase) URI() span.URI {
169         return f.uris[0]
170 }
171
172 func (f *fileBase) filename() string {
173         return f.fname
174 }
175
176 func (f *fileBase) addURI(uri span.URI) int {
177         f.uris = append(f.uris, uri)
178         return len(f.uris)
179 }
180
181 func (v *View) ID() string { return v.id }
182
183 // tempModFile creates a temporary go.mod file based on the contents of the
184 // given go.mod file. It is the caller's responsibility to clean up the files
185 // when they are done using them.
186 func tempModFile(modFh source.FileHandle, gosum []byte) (tmpURI span.URI, cleanup func(), err error) {
187         filenameHash := hashContents([]byte(modFh.URI().Filename()))
188         tmpMod, err := ioutil.TempFile("", fmt.Sprintf("go.%s.*.mod", filenameHash))
189         if err != nil {
190                 return "", nil, err
191         }
192         defer tmpMod.Close()
193
194         tmpURI = span.URIFromPath(tmpMod.Name())
195         tmpSumName := sumFilename(tmpURI)
196
197         content, err := modFh.Read()
198         if err != nil {
199                 return "", nil, err
200         }
201
202         if _, err := tmpMod.Write(content); err != nil {
203                 return "", nil, err
204         }
205
206         cleanup = func() {
207                 _ = os.Remove(tmpSumName)
208                 _ = os.Remove(tmpURI.Filename())
209         }
210
211         // Be careful to clean up if we return an error from this function.
212         defer func() {
213                 if err != nil {
214                         cleanup()
215                         cleanup = nil
216                 }
217         }()
218
219         // Create an analogous go.sum, if one exists.
220         if gosum != nil {
221                 if err := ioutil.WriteFile(tmpSumName, gosum, 0655); err != nil {
222                         return "", cleanup, err
223                 }
224         }
225
226         return tmpURI, cleanup, nil
227 }
228
229 // Name returns the user visible name of this view.
230 func (v *View) Name() string {
231         return v.name
232 }
233
234 // Folder returns the folder at the base of this view.
235 func (v *View) Folder() span.URI {
236         return v.folder
237 }
238
239 func (v *View) Options() *source.Options {
240         v.optionsMu.Lock()
241         defer v.optionsMu.Unlock()
242         return v.options
243 }
244
245 func minorOptionsChange(a, b *source.Options) bool {
246         // Check if any of the settings that modify our understanding of files have been changed
247         if !reflect.DeepEqual(a.Env, b.Env) {
248                 return false
249         }
250         if !reflect.DeepEqual(a.DirectoryFilters, b.DirectoryFilters) {
251                 return false
252         }
253         aBuildFlags := make([]string, len(a.BuildFlags))
254         bBuildFlags := make([]string, len(b.BuildFlags))
255         copy(aBuildFlags, a.BuildFlags)
256         copy(bBuildFlags, b.BuildFlags)
257         sort.Strings(aBuildFlags)
258         sort.Strings(bBuildFlags)
259         // the rest of the options are benign
260         return reflect.DeepEqual(aBuildFlags, bBuildFlags)
261 }
262
263 func (v *View) SetOptions(ctx context.Context, options *source.Options) (source.View, error) {
264         // no need to rebuild the view if the options were not materially changed
265         v.optionsMu.Lock()
266         if minorOptionsChange(v.options, options) {
267                 v.options = options
268                 v.optionsMu.Unlock()
269                 return v, nil
270         }
271         v.optionsMu.Unlock()
272         newView, err := v.session.updateView(ctx, v, options)
273         return newView, err
274 }
275
276 func (v *View) Rebuild(ctx context.Context) (source.Snapshot, func(), error) {
277         newView, err := v.session.updateView(ctx, v, v.Options())
278         if err != nil {
279                 return nil, func() {}, err
280         }
281         snapshot, release := newView.Snapshot(ctx)
282         return snapshot, release, nil
283 }
284
285 func (s *snapshot) WriteEnv(ctx context.Context, w io.Writer) error {
286         s.view.optionsMu.Lock()
287         env := s.view.options.EnvSlice()
288         buildFlags := append([]string{}, s.view.options.BuildFlags...)
289         s.view.optionsMu.Unlock()
290
291         fullEnv := make(map[string]string)
292         for k, v := range s.view.goEnv {
293                 fullEnv[k] = v
294         }
295         for _, v := range env {
296                 s := strings.SplitN(v, "=", 2)
297                 if len(s) != 2 {
298                         continue
299                 }
300                 if _, ok := fullEnv[s[0]]; ok {
301                         fullEnv[s[0]] = s[1]
302                 }
303         }
304         goVersion, err := s.view.session.gocmdRunner.Run(ctx, gocommand.Invocation{
305                 Verb:       "version",
306                 Env:        env,
307                 WorkingDir: s.view.rootURI.Filename(),
308         })
309         if err != nil {
310                 return err
311         }
312         fmt.Fprintf(w, `go env for %v
313 (root %s)
314 (go version %s)
315 (valid build configuration = %v)
316 (build flags: %v)
317 `,
318                 s.view.folder.Filename(),
319                 s.view.rootURI.Filename(),
320                 strings.TrimRight(goVersion.String(), "\n"),
321                 s.ValidBuildConfiguration(),
322                 buildFlags)
323         for k, v := range fullEnv {
324                 fmt.Fprintf(w, "%s=%s\n", k, v)
325         }
326         return nil
327 }
328
329 func (s *snapshot) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error {
330         return s.view.importsState.runProcessEnvFunc(ctx, s, fn)
331 }
332
333 func (v *View) contains(uri span.URI) bool {
334         inRoot := source.InDir(v.rootURI.Filename(), uri.Filename())
335         inFolder := source.InDir(v.folder.Filename(), uri.Filename())
336         if !inRoot && !inFolder {
337                 return false
338         }
339         // Filters are applied relative to the workspace folder.
340         if inFolder {
341                 return !pathExcludedByFilter(strings.TrimPrefix(uri.Filename(), v.folder.Filename()), v.Options())
342         }
343         return true
344 }
345
346 func (v *View) mapFile(uri span.URI, f *fileBase) {
347         v.filesByURI[uri] = f
348         if f.addURI(uri) == 1 {
349                 basename := basename(f.filename())
350                 v.filesByBase[basename] = append(v.filesByBase[basename], f)
351         }
352 }
353
354 func basename(filename string) string {
355         return strings.ToLower(filepath.Base(filename))
356 }
357
358 func (v *View) relevantChange(c source.FileModification) bool {
359         // If the file is known to the view, the change is relevant.
360         if v.knownFile(c.URI) {
361                 return true
362         }
363         // The gopls.mod may not be "known" because we first access it through the
364         // session. As a result, treat changes to the view's gopls.mod file as
365         // always relevant, even if they are only on-disk changes.
366         // TODO(rstambler): Make sure the gopls.mod is always known to the view.
367         if c.URI == goplsModURI(v.rootURI) {
368                 return true
369         }
370         // If the file is not known to the view, and the change is only on-disk,
371         // we should not invalidate the snapshot. This is necessary because Emacs
372         // sends didChangeWatchedFiles events for temp files.
373         if c.OnDisk && (c.Action == source.Change || c.Action == source.Delete) {
374                 return false
375         }
376         return v.contains(c.URI)
377 }
378
379 func (v *View) knownFile(uri span.URI) bool {
380         v.mu.Lock()
381         defer v.mu.Unlock()
382
383         f, err := v.findFile(uri)
384         return f != nil && err == nil
385 }
386
387 // getFile returns a file for the given URI.
388 func (v *View) getFile(uri span.URI) *fileBase {
389         v.mu.Lock()
390         defer v.mu.Unlock()
391
392         f, _ := v.findFile(uri)
393         if f != nil {
394                 return f
395         }
396         f = &fileBase{
397                 view:  v,
398                 fname: uri.Filename(),
399         }
400         v.mapFile(uri, f)
401         return f
402 }
403
404 // findFile checks the cache for any file matching the given uri.
405 //
406 // An error is only returned for an irreparable failure, for example, if the
407 // filename in question does not exist.
408 func (v *View) findFile(uri span.URI) (*fileBase, error) {
409         if f := v.filesByURI[uri]; f != nil {
410                 // a perfect match
411                 return f, nil
412         }
413         // no exact match stored, time to do some real work
414         // check for any files with the same basename
415         fname := uri.Filename()
416         basename := basename(fname)
417         if candidates := v.filesByBase[basename]; candidates != nil {
418                 pathStat, err := os.Stat(fname)
419                 if os.IsNotExist(err) {
420                         return nil, err
421                 }
422                 if err != nil {
423                         return nil, nil // the file may exist, return without an error
424                 }
425                 for _, c := range candidates {
426                         if cStat, err := os.Stat(c.filename()); err == nil {
427                                 if os.SameFile(pathStat, cStat) {
428                                         // same file, map it
429                                         v.mapFile(uri, c)
430                                         return c, nil
431                                 }
432                         }
433                 }
434         }
435         // no file with a matching name was found, it wasn't in our cache
436         return nil, nil
437 }
438
439 func (v *View) Shutdown(ctx context.Context) {
440         v.session.removeView(ctx, v)
441 }
442
443 // TODO(rFindley): probably some of this should also be one in View.Shutdown
444 // above?
445 func (v *View) shutdown(ctx context.Context) {
446         // Cancel the initial workspace load if it is still running.
447         v.initCancelFirstAttempt()
448
449         v.mu.Lock()
450         if v.cancel != nil {
451                 v.cancel()
452                 v.cancel = nil
453         }
454         v.mu.Unlock()
455         v.snapshotMu.Lock()
456         go v.snapshot.generation.Destroy()
457         v.snapshotMu.Unlock()
458         v.importsState.destroy()
459         if v.tempWorkspace != "" {
460                 if err := os.RemoveAll(v.tempWorkspace.Filename()); err != nil {
461                         event.Error(ctx, "removing temp workspace", err)
462                 }
463         }
464 }
465
466 func (v *View) Session() *Session {
467         return v.session
468 }
469
470 func (s *snapshot) IgnoredFile(uri span.URI) bool {
471         filename := uri.Filename()
472         var prefixes []string
473         if len(s.workspace.getActiveModFiles()) == 0 {
474                 for _, entry := range filepath.SplitList(s.view.gopath) {
475                         prefixes = append(prefixes, filepath.Join(entry, "src"))
476                 }
477         } else {
478                 prefixes = append(prefixes, s.view.gomodcache)
479                 for m := range s.workspace.getActiveModFiles() {
480                         prefixes = append(prefixes, dirURI(m).Filename())
481                 }
482         }
483         for _, prefix := range prefixes {
484                 if strings.HasPrefix(filename, prefix) {
485                         return checkIgnored(filename[len(prefix):])
486                 }
487         }
488         return false
489 }
490
491 // checkIgnored implements go list's exclusion rules. go help list:
492 //              Directory and file names that begin with "." or "_" are ignored
493 //              by the go tool, as are directories named "testdata".
494 func checkIgnored(suffix string) bool {
495         for _, component := range strings.Split(suffix, string(filepath.Separator)) {
496                 if len(component) == 0 {
497                         continue
498                 }
499                 if component[0] == '.' || component[0] == '_' || component == "testdata" {
500                         return true
501                 }
502         }
503         return false
504 }
505
506 func (v *View) Snapshot(ctx context.Context) (source.Snapshot, func()) {
507         return v.getSnapshot(ctx)
508 }
509
510 func (v *View) getSnapshot(ctx context.Context) (*snapshot, func()) {
511         v.snapshotMu.Lock()
512         defer v.snapshotMu.Unlock()
513         return v.snapshot, v.snapshot.generation.Acquire(ctx)
514 }
515
516 func (s *snapshot) initialize(ctx context.Context, firstAttempt bool) {
517         select {
518         case <-ctx.Done():
519                 return
520         case s.view.initializationSema <- struct{}{}:
521         }
522
523         defer func() {
524                 <-s.view.initializationSema
525         }()
526
527         if s.initializeOnce == nil {
528                 return
529         }
530         s.initializeOnce.Do(func() {
531                 defer func() {
532                         s.initializeOnce = nil
533                         if firstAttempt {
534                                 close(s.view.initialWorkspaceLoad)
535                         }
536                 }()
537
538                 // If we have multiple modules, we need to load them by paths.
539                 var scopes []interface{}
540                 var modDiagnostics []*source.Diagnostic
541                 addError := func(uri span.URI, err error) {
542                         modDiagnostics = append(modDiagnostics, &source.Diagnostic{
543                                 URI:      uri,
544                                 Severity: protocol.SeverityError,
545                                 Source:   source.ListError,
546                                 Message:  err.Error(),
547                         })
548                 }
549                 for modURI := range s.workspace.getActiveModFiles() {
550                         fh, err := s.GetFile(ctx, modURI)
551                         if err != nil {
552                                 addError(modURI, err)
553                                 continue
554                         }
555                         parsed, err := s.ParseMod(ctx, fh)
556                         if err != nil {
557                                 addError(modURI, err)
558                                 continue
559                         }
560                         if parsed.File == nil || parsed.File.Module == nil {
561                                 addError(modURI, fmt.Errorf("no module path for %s", modURI))
562                                 continue
563                         }
564                         path := parsed.File.Module.Mod.Path
565                         scopes = append(scopes, moduleLoadScope(path))
566                 }
567                 if len(scopes) == 0 {
568                         scopes = append(scopes, viewLoadScope("LOAD_VIEW"))
569                 }
570                 err := s.load(ctx, firstAttempt, append(scopes, packagePath("builtin"))...)
571                 if ctx.Err() != nil {
572                         return
573                 }
574                 if err != nil {
575                         event.Error(ctx, "initial workspace load failed", err)
576                         extractedDiags, _ := s.extractGoCommandErrors(ctx, err.Error())
577                         s.initializedErr = &source.CriticalError{
578                                 MainError: err,
579                                 DiagList:  append(modDiagnostics, extractedDiags...),
580                         }
581                 } else if len(modDiagnostics) != 0 {
582                         s.initializedErr = &source.CriticalError{
583                                 MainError: fmt.Errorf("error loading module names"),
584                                 DiagList:  modDiagnostics,
585                         }
586                 } else {
587                         // Clear out the initialization error, in case it had been set
588                         // previously.
589                         s.initializedErr = nil
590                 }
591         })
592 }
593
594 // invalidateContent invalidates the content of a Go file,
595 // including any position and type information that depends on it.
596 func (v *View) invalidateContent(ctx context.Context, changes map[span.URI]*fileChange, forceReloadMetadata bool) (*snapshot, func()) {
597         // Detach the context so that content invalidation cannot be canceled.
598         ctx = xcontext.Detach(ctx)
599
600         // Cancel all still-running previous requests, since they would be
601         // operating on stale data.
602         v.snapshot.cancel()
603
604         // Do not clone a snapshot until its view has finished initializing.
605         v.snapshot.AwaitInitialized(ctx)
606
607         // This should be the only time we hold the view's snapshot lock for any period of time.
608         v.snapshotMu.Lock()
609         defer v.snapshotMu.Unlock()
610
611         oldSnapshot := v.snapshot
612
613         var workspaceChanged bool
614         v.snapshot, workspaceChanged = oldSnapshot.clone(ctx, v.baseCtx, changes, forceReloadMetadata)
615         if workspaceChanged && v.tempWorkspace != "" {
616                 snap := v.snapshot
617                 go func() {
618                         wsdir, err := snap.getWorkspaceDir(ctx)
619                         if err != nil {
620                                 event.Error(ctx, "getting workspace dir", err)
621                         }
622                         if err := copyWorkspace(v.tempWorkspace, wsdir); err != nil {
623                                 event.Error(ctx, "copying workspace dir", err)
624                         }
625                 }()
626         }
627         go oldSnapshot.generation.Destroy()
628
629         return v.snapshot, v.snapshot.generation.Acquire(ctx)
630 }
631
632 func copyWorkspace(dst span.URI, src span.URI) error {
633         for _, name := range []string{"go.mod", "go.sum"} {
634                 srcname := filepath.Join(src.Filename(), name)
635                 srcf, err := os.Open(srcname)
636                 if err != nil {
637                         return errors.Errorf("opening snapshot %s: %w", name, err)
638                 }
639                 defer srcf.Close()
640                 dstname := filepath.Join(dst.Filename(), name)
641                 dstf, err := os.Create(dstname)
642                 if err != nil {
643                         return errors.Errorf("truncating view %s: %w", name, err)
644                 }
645                 defer dstf.Close()
646                 if _, err := io.Copy(dstf, srcf); err != nil {
647                         return errors.Errorf("copying %s: %w", name, err)
648                 }
649         }
650         return nil
651 }
652
653 func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI, options *source.Options) (*workspaceInformation, error) {
654         if err := checkPathCase(folder.Filename()); err != nil {
655                 return nil, errors.Errorf("invalid workspace configuration: %w", err)
656         }
657         var err error
658         inv := gocommand.Invocation{
659                 WorkingDir: folder.Filename(),
660                 Env:        options.EnvSlice(),
661         }
662         goversion, err := gocommand.GoVersion(ctx, inv, s.gocmdRunner)
663         if err != nil {
664                 return nil, err
665         }
666
667         go111module := os.Getenv("GO111MODULE")
668         if v, ok := options.Env["GO111MODULE"]; ok {
669                 go111module = v
670         }
671         // Make sure to get the `go env` before continuing with initialization.
672         envVars, env, err := s.getGoEnv(ctx, folder.Filename(), goversion, go111module, options.EnvSlice())
673         if err != nil {
674                 return nil, err
675         }
676         // If using 1.16, change the default back to auto. The primary effect of
677         // GO111MODULE=on is to break GOPATH, which we aren't too interested in.
678         if goversion >= 16 && go111module == "" {
679                 go111module = "auto"
680         }
681         // The value of GOPACKAGESDRIVER is not returned through the go command.
682         gopackagesdriver := os.Getenv("GOPACKAGESDRIVER")
683         for _, s := range env {
684                 split := strings.SplitN(s, "=", 2)
685                 if split[0] == "GOPACKAGESDRIVER" {
686                         gopackagesdriver = split[1]
687                 }
688         }
689
690         // A user may also have a gopackagesdriver binary on their machine, which
691         // works the same way as setting GOPACKAGESDRIVER.
692         tool, _ := exec.LookPath("gopackagesdriver")
693         hasGopackagesDriver := gopackagesdriver != "off" && (gopackagesdriver != "" || tool != "")
694
695         return &workspaceInformation{
696                 hasGopackagesDriver:  hasGopackagesDriver,
697                 effectiveGo111Module: go111module,
698                 userGo111Module:      go111moduleForVersion(go111module, goversion),
699                 goversion:            goversion,
700                 environmentVariables: envVars,
701                 goEnv:                env,
702         }, nil
703 }
704
705 func go111moduleForVersion(go111module string, goversion int) go111module {
706         // Off by default until Go 1.12.
707         if go111module == "off" || (goversion < 12 && go111module == "") {
708                 return off
709         }
710         // On by default as of Go 1.16.
711         if go111module == "on" || (goversion >= 16 && go111module == "") {
712                 return on
713         }
714         return auto
715 }
716
717 // findWorkspaceRoot searches for the best workspace root according to the
718 // following heuristics:
719 //   - First, look for a parent directory containing a gopls.mod file
720 //     (experimental only).
721 //   - Then, a parent directory containing a go.mod file.
722 //   - Then, a child directory containing a go.mod file, if there is exactly
723 //     one (non-experimental only).
724 // Otherwise, it returns folder.
725 // TODO (rFindley): move this to workspace.go
726 // TODO (rFindley): simplify this once workspace modules are enabled by default.
727 func findWorkspaceRoot(ctx context.Context, folder span.URI, fs source.FileSource, excludePath func(string) bool, experimental bool) (span.URI, error) {
728         patterns := []string{"go.mod"}
729         if experimental {
730                 patterns = []string{"gopls.mod", "go.mod"}
731         }
732         for _, basename := range patterns {
733                 dir, err := findRootPattern(ctx, folder, basename, fs)
734                 if err != nil {
735                         return "", errors.Errorf("finding %s: %w", basename, err)
736                 }
737                 if dir != "" {
738                         return dir, nil
739                 }
740         }
741
742         // The experimental workspace can handle nested modules at this point...
743         if experimental {
744                 return folder, nil
745         }
746
747         // ...else we should check if there's exactly one nested module.
748         all, err := findModules(ctx, folder, excludePath, 2)
749         if err == errExhausted {
750                 // Fall-back behavior: if we don't find any modules after searching 10000
751                 // files, assume there are none.
752                 event.Log(ctx, fmt.Sprintf("stopped searching for modules after %d files", fileLimit))
753                 return folder, nil
754         }
755         if err != nil {
756                 return "", err
757         }
758         if len(all) == 1 {
759                 // range to access first element.
760                 for uri := range all {
761                         return dirURI(uri), nil
762                 }
763         }
764         return folder, nil
765 }
766
767 func findRootPattern(ctx context.Context, folder span.URI, basename string, fs source.FileSource) (span.URI, error) {
768         dir := folder.Filename()
769         for dir != "" {
770                 target := filepath.Join(dir, basename)
771                 exists, err := fileExists(ctx, span.URIFromPath(target), fs)
772                 if err != nil {
773                         return "", err
774                 }
775                 if exists {
776                         return span.URIFromPath(dir), nil
777                 }
778                 next, _ := filepath.Split(dir)
779                 if next == dir {
780                         break
781                 }
782                 dir = next
783         }
784         return "", nil
785 }
786
787 // OS-specific path case check, for case-insensitive filesystems.
788 var checkPathCase = defaultCheckPathCase
789
790 func defaultCheckPathCase(path string) error {
791         return nil
792 }
793
794 func validBuildConfiguration(folder span.URI, ws *workspaceInformation, modFiles map[span.URI]struct{}) bool {
795         // Since we only really understand the `go` command, if the user has a
796         // different GOPACKAGESDRIVER, assume that their configuration is valid.
797         if ws.hasGopackagesDriver {
798                 return true
799         }
800         // Check if the user is working within a module or if we have found
801         // multiple modules in the workspace.
802         if len(modFiles) > 0 {
803                 return true
804         }
805         // The user may have a multiple directories in their GOPATH.
806         // Check if the workspace is within any of them.
807         for _, gp := range filepath.SplitList(ws.gopath) {
808                 if source.InDir(filepath.Join(gp, "src"), folder.Filename()) {
809                         return true
810                 }
811         }
812         return false
813 }
814
815 // getGoEnv gets the view's various GO* values.
816 func (s *Session) getGoEnv(ctx context.Context, folder string, goversion int, go111module string, configEnv []string) (environmentVariables, map[string]string, error) {
817         envVars := environmentVariables{}
818         vars := map[string]*string{
819                 "GOCACHE":     &envVars.gocache,
820                 "GOPATH":      &envVars.gopath,
821                 "GOROOT":      &envVars.goroot,
822                 "GOPRIVATE":   &envVars.goprivate,
823                 "GOMODCACHE":  &envVars.gomodcache,
824                 "GO111MODULE": &envVars.go111module,
825         }
826
827         // We can save ~200 ms by requesting only the variables we care about.
828         args := append([]string{"-json"}, imports.RequiredGoEnvVars...)
829         for k := range vars {
830                 args = append(args, k)
831         }
832
833         inv := gocommand.Invocation{
834                 Verb:       "env",
835                 Args:       args,
836                 Env:        configEnv,
837                 WorkingDir: folder,
838         }
839         // Don't go through runGoCommand, as we don't need a temporary -modfile to
840         // run `go env`.
841         stdout, err := s.gocmdRunner.Run(ctx, inv)
842         if err != nil {
843                 return environmentVariables{}, nil, err
844         }
845         env := make(map[string]string)
846         if err := json.Unmarshal(stdout.Bytes(), &env); err != nil {
847                 return environmentVariables{}, nil, err
848         }
849
850         for key, ptr := range vars {
851                 *ptr = env[key]
852         }
853
854         // Old versions of Go don't have GOMODCACHE, so emulate it.
855         if envVars.gomodcache == "" && envVars.gopath != "" {
856                 envVars.gomodcache = filepath.Join(filepath.SplitList(envVars.gopath)[0], "pkg/mod")
857         }
858         // GO111MODULE does not appear in `go env` output until Go 1.13.
859         if goversion < 13 {
860                 envVars.go111module = go111module
861         }
862         return envVars, env, err
863 }
864
865 func (v *View) IsGoPrivatePath(target string) bool {
866         return globsMatchPath(v.goprivate, target)
867 }
868
869 func (v *View) ModuleUpgrades() map[string]string {
870         v.mu.Lock()
871         defer v.mu.Unlock()
872
873         upgrades := map[string]string{}
874         for mod, ver := range v.moduleUpgrades {
875                 upgrades[mod] = ver
876         }
877         return upgrades
878 }
879
880 func (v *View) RegisterModuleUpgrades(upgrades map[string]string) {
881         v.mu.Lock()
882         defer v.mu.Unlock()
883
884         for mod, ver := range upgrades {
885                 v.moduleUpgrades[mod] = ver
886         }
887 }
888
889 // Copied from
890 // https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/str/path.go;l=58;drc=2910c5b4a01a573ebc97744890a07c1a3122c67a
891 func globsMatchPath(globs, target string) bool {
892         for globs != "" {
893                 // Extract next non-empty glob in comma-separated list.
894                 var glob string
895                 if i := strings.Index(globs, ","); i >= 0 {
896                         glob, globs = globs[:i], globs[i+1:]
897                 } else {
898                         glob, globs = globs, ""
899                 }
900                 if glob == "" {
901                         continue
902                 }
903
904                 // A glob with N+1 path elements (N slashes) needs to be matched
905                 // against the first N+1 path elements of target,
906                 // which end just before the N+1'th slash.
907                 n := strings.Count(glob, "/")
908                 prefix := target
909                 // Walk target, counting slashes, truncating at the N+1'th slash.
910                 for i := 0; i < len(target); i++ {
911                         if target[i] == '/' {
912                                 if n == 0 {
913                                         prefix = target[:i]
914                                         break
915                                 }
916                                 n--
917                         }
918                 }
919                 if n > 0 {
920                         // Not enough prefix elements.
921                         continue
922                 }
923                 matched, _ := path.Match(glob, prefix)
924                 if matched {
925                         return true
926                 }
927         }
928         return false
929 }
930
931 var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`)
932
933 // TODO(rstambler): Consolidate modURI and modContent back into a FileHandle
934 // after we have a version of the workspace go.mod file on disk. Getting a
935 // FileHandle from the cache for temporary files is problematic, since we
936 // cannot delete it.
937 func (s *snapshot) vendorEnabled(ctx context.Context, modURI span.URI, modContent []byte) (bool, error) {
938         if s.workspaceMode()&moduleMode == 0 {
939                 return false, nil
940         }
941         matches := modFlagRegexp.FindStringSubmatch(s.view.goEnv["GOFLAGS"])
942         var modFlag string
943         if len(matches) != 0 {
944                 modFlag = matches[1]
945         }
946         if modFlag != "" {
947                 // Don't override an explicit '-mod=vendor' argument.
948                 // We do want to override '-mod=readonly': it would break various module code lenses,
949                 // and on 1.16 we know -modfile is available, so we won't mess with go.mod anyway.
950                 return modFlag == "vendor", nil
951         }
952
953         modFile, err := modfile.Parse(modURI.Filename(), modContent, nil)
954         if err != nil {
955                 return false, err
956         }
957         if fi, err := os.Stat(filepath.Join(s.view.rootURI.Filename(), "vendor")); err != nil || !fi.IsDir() {
958                 return false, nil
959         }
960         vendorEnabled := modFile.Go != nil && modFile.Go.Version != "" && semver.Compare("v"+modFile.Go.Version, "v1.14") >= 0
961         return vendorEnabled, nil
962 }
963
964 func (v *View) allFilesExcluded(pkg *packages.Package) bool {
965         opts := v.Options()
966         folder := filepath.ToSlash(v.folder.Filename())
967         for _, f := range pkg.GoFiles {
968                 f = filepath.ToSlash(f)
969                 if !strings.HasPrefix(f, folder) {
970                         return false
971                 }
972                 if !pathExcludedByFilter(strings.TrimPrefix(f, folder), opts) {
973                         return false
974                 }
975         }
976         return true
977 }
978
979 func pathExcludedByFilterFunc(opts *source.Options) func(string) bool {
980         return func(path string) bool {
981                 return pathExcludedByFilter(path, opts)
982         }
983 }
984
985 func pathExcludedByFilter(path string, opts *source.Options) bool {
986         path = strings.TrimPrefix(filepath.ToSlash(path), "/")
987
988         excluded := false
989         for _, filter := range opts.DirectoryFilters {
990                 op, prefix := filter[0], filter[1:]
991                 // Non-empty prefixes have to be precise directory matches.
992                 if prefix != "" {
993                         prefix = prefix + "/"
994                         path = path + "/"
995                 }
996                 if !strings.HasPrefix(path, prefix) {
997                         continue
998                 }
999                 excluded = op == '-'
1000         }
1001         return excluded
1002 }