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