internal/lsp/cache: fix mod file change check

The modfiles function only works with Go 1.14. When it is enabled,
it reenters the view, causing a deadlock. Stop using it, and move the
process env under a separate lock so to break the deadlock.

Change-Id: I34c528c2be1f32c06b423ead44e90155f60c2214
Reviewed-on: https://go-review.googlesource.com/c/tools/+/215679
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 16fe0ae..c43d986 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -60,6 +60,8 @@
 	// mod is the module information for this view.
 	mod *moduleInformation
 
+	// importsMu guards imports-related state, particularly the ProcessEnv.
+	importsMu sync.Mutex
 	// process is the process env for this view.
 	// Note: this contains cached module and filesystem state.
 	//
@@ -274,8 +276,9 @@
 }
 
 func (v *view) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error {
-	v.mu.Lock()
-	defer v.mu.Unlock()
+	v.importsMu.Lock()
+	defer v.importsMu.Unlock()
+
 	if v.processEnv == nil {
 		var err error
 		if v.processEnv, err = v.buildProcessEnv(ctx); err != nil {
@@ -284,11 +287,12 @@
 	}
 
 	// In module mode, check if the mod file has changed.
-	if mod, _, err := v.Snapshot().ModFiles(ctx); err == nil && mod != nil {
-		if mod.Identity() != v.cachedModFileVersion {
+	if v.gomod != "" && v.gomod != os.DevNull {
+		mod, err := v.Snapshot().GetFile(span.FileURI(v.gomod))
+		if err == nil && mod.Identity() != v.cachedModFileVersion {
 			v.processEnv.GetResolver().(*imports.ModuleResolver).ClearForNewMod()
+			v.cachedModFileVersion = mod.Identity()
 		}
-		v.cachedModFileVersion = mod.Identity()
 	}
 
 	// Run the user function.
@@ -323,20 +327,20 @@
 func (v *view) refreshProcessEnv() {
 	start := time.Now()
 
-	v.mu.Lock()
+	v.importsMu.Lock()
 	env := v.processEnv
 	env.GetResolver().ClearForNewScan()
-	v.mu.Unlock()
+	v.importsMu.Unlock()
 
 	// We don't have a context handy to use for logging, so use the stdlib for now.
 	stdlog.Printf("background imports cache refresh starting")
 	err := imports.PrimeCache(context.Background(), env)
 	stdlog.Printf("background refresh finished after %v with err: %v", time.Since(start), err)
 
-	v.mu.Lock()
+	v.importsMu.Lock()
 	v.cacheRefreshDuration = time.Since(start)
 	v.cacheRefreshTimer = nil
-	v.mu.Unlock()
+	v.importsMu.Unlock()
 }
 
 func (v *view) buildProcessEnv(ctx context.Context) (*imports.ProcessEnv, error) {