Skip to content

Commit 39c2fd8

Browse files
committed
internal/lsp/cache: simplify importsState modfile hashing logic
While checking for changes to go.mod files in the importsState, there is no reason for special handling based on workspace mode: we can simply hash all active modfiles. This moves us towards an improved API for the workspace: it should simply be responsible for tracking active modfiles. This also incidentally avoids the panic reported in golang/go#55837. Fixes golang/go#55837 Change-Id: I8cb345d1689be12382683186afe3f9addb19d467 Reviewed-on: https://go-review.googlesource.com/c/tools/+/447956 gopls-CI: kokoro <[email protected]> Reviewed-by: Alan Donovan <[email protected]> Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent ec044b1 commit 39c2fd8

File tree

6 files changed

+22
-34
lines changed

6 files changed

+22
-34
lines changed

gopls/internal/lsp/cache/imports.go

+7-22
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import (
1313
"sync"
1414
"time"
1515

16+
"golang.org/x/tools/gopls/internal/lsp/source"
1617
"golang.org/x/tools/internal/event"
1718
"golang.org/x/tools/internal/event/keys"
1819
"golang.org/x/tools/internal/gocommand"
1920
"golang.org/x/tools/internal/imports"
20-
"golang.org/x/tools/gopls/internal/lsp/source"
2121
)
2222

2323
type importsState struct {
@@ -37,33 +37,18 @@ func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot
3737
s.mu.Lock()
3838
defer s.mu.Unlock()
3939

40-
// Find the hash of the active mod file, if any. Using the unsaved content
40+
// Find the hash of active mod files, if any. Using the unsaved content
4141
// is slightly wasteful, since we'll drop caches a little too often, but
4242
// the mod file shouldn't be changing while people are autocompleting.
43-
var modFileHash source.Hash
44-
// If we are using 'legacyWorkspace' mode, we can just read the modfile from
45-
// the snapshot. Otherwise, we need to get the synthetic workspace mod file.
4643
//
47-
// TODO(rfindley): we should be able to just always use the synthetic
48-
// workspace module, or alternatively use the go.work file.
49-
if snapshot.workspace.moduleSource == legacyWorkspace {
50-
for m := range snapshot.workspace.getActiveModFiles() { // range to access the only element
51-
modFH, err := snapshot.GetFile(ctx, m)
52-
if err != nil {
53-
return err
54-
}
55-
modFileHash = modFH.FileIdentity().Hash
56-
}
57-
} else {
58-
modFile, err := snapshot.workspace.modFile(ctx, snapshot)
59-
if err != nil {
60-
return err
61-
}
62-
modBytes, err := modFile.Format()
44+
// TODO(rfindley): consider instead hashing on-disk modfiles here.
45+
var modFileHash source.Hash
46+
for m := range snapshot.workspace.ActiveModFiles() {
47+
fh, err := snapshot.GetFile(ctx, m)
6348
if err != nil {
6449
return err
6550
}
66-
modFileHash = source.HashOf(modBytes)
51+
modFileHash.XORWith(fh.FileIdentity().Hash)
6752
}
6853

6954
// view.goEnv is immutable -- changes make a new view. Options can change.

gopls/internal/lsp/cache/load.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,10 @@ https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.`
352352
// If the user has one active go.mod file, they may still be editing files
353353
// in nested modules. Check the module of each open file and add warnings
354354
// that the nested module must be opened as a workspace folder.
355-
if len(s.workspace.getActiveModFiles()) == 1 {
355+
if len(s.workspace.ActiveModFiles()) == 1 {
356356
// Get the active root go.mod file to compare against.
357357
var rootModURI span.URI
358-
for uri := range s.workspace.getActiveModFiles() {
358+
for uri := range s.workspace.ActiveModFiles() {
359359
rootModURI = uri
360360
}
361361
nestedModules := map[string][]source.VersionedFileHandle{}

gopls/internal/lsp/cache/snapshot.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ func (s *snapshot) FileSet() *token.FileSet {
250250

251251
func (s *snapshot) ModFiles() []span.URI {
252252
var uris []span.URI
253-
for modURI := range s.workspace.getActiveModFiles() {
253+
for modURI := range s.workspace.ActiveModFiles() {
254254
uris = append(uris, modURI)
255255
}
256256
return uris
@@ -281,7 +281,7 @@ func (s *snapshot) ValidBuildConfiguration() bool {
281281
}
282282
// Check if the user is working within a module or if we have found
283283
// multiple modules in the workspace.
284-
if len(s.workspace.getActiveModFiles()) > 0 {
284+
if len(s.workspace.ActiveModFiles()) > 0 {
285285
return true
286286
}
287287
// The user may have a multiple directories in their GOPATH.
@@ -308,7 +308,7 @@ func (s *snapshot) workspaceMode() workspaceMode {
308308
// If the view is not in a module and contains no modules, but still has a
309309
// valid workspace configuration, do not create the workspace module.
310310
// It could be using GOPATH or a different build system entirely.
311-
if len(s.workspace.getActiveModFiles()) == 0 && validBuildConfiguration {
311+
if len(s.workspace.ActiveModFiles()) == 0 && validBuildConfiguration {
312312
return mode
313313
}
314314
mode |= moduleMode
@@ -480,7 +480,7 @@ func (s *snapshot) goCommandInvocation(ctx context.Context, flags source.Invocat
480480
if mode == source.LoadWorkspace {
481481
switch s.workspace.moduleSource {
482482
case legacyWorkspace:
483-
for m := range s.workspace.getActiveModFiles() { // range to access the only element
483+
for m := range s.workspace.ActiveModFiles() { // range to access the only element
484484
modURI = m
485485
}
486486
case goWorkWorkspace:

gopls/internal/lsp/cache/view.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -581,13 +581,13 @@ func (v *View) Session() *Session {
581581
func (s *snapshot) IgnoredFile(uri span.URI) bool {
582582
filename := uri.Filename()
583583
var prefixes []string
584-
if len(s.workspace.getActiveModFiles()) == 0 {
584+
if len(s.workspace.ActiveModFiles()) == 0 {
585585
for _, entry := range filepath.SplitList(s.view.gopath) {
586586
prefixes = append(prefixes, filepath.Join(entry, "src"))
587587
}
588588
} else {
589589
prefixes = append(prefixes, s.view.gomodcache)
590-
for m := range s.workspace.getActiveModFiles() {
590+
for m := range s.workspace.ActiveModFiles() {
591591
prefixes = append(prefixes, dirURI(m).Filename())
592592
}
593593
}
@@ -679,8 +679,8 @@ func (s *snapshot) loadWorkspace(ctx context.Context, firstAttempt bool) {
679679
})
680680
}
681681

682-
if len(s.workspace.getActiveModFiles()) > 0 {
683-
for modURI := range s.workspace.getActiveModFiles() {
682+
if len(s.workspace.ActiveModFiles()) > 0 {
683+
for modURI := range s.workspace.ActiveModFiles() {
684684
// Be careful not to add context cancellation errors as critical module
685685
// errors.
686686
fh, err := s.GetFile(ctx, modURI)

gopls/internal/lsp/cache/workspace.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type workspaceCommon struct {
7373
type workspace struct {
7474
workspaceCommon
7575

76+
// The source of modules in this workspace.
7677
moduleSource workspaceSource
7778

7879
// activeModFiles holds the active go.mod files.
@@ -192,11 +193,13 @@ func (ws *workspace) loadExplicitWorkspaceFile(ctx context.Context, fs source.Fi
192193

193194
var noHardcodedWorkspace = errors.New("no hardcoded workspace")
194195

196+
// TODO(rfindley): eliminate getKnownModFiles.
195197
func (w *workspace) getKnownModFiles() map[span.URI]struct{} {
196198
return w.knownModFiles
197199
}
198200

199-
func (w *workspace) getActiveModFiles() map[span.URI]struct{} {
201+
// ActiveModFiles returns the set of active mod files for the current workspace.
202+
func (w *workspace) ActiveModFiles() map[span.URI]struct{} {
200203
return w.activeModFiles
201204
}
202205

gopls/internal/lsp/cache/workspace_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ func checkState(ctx context.Context, t *testing.T, fs source.FileSource, rel fak
386386
t.Errorf("module source = %v, want %v", got.moduleSource, want.source)
387387
}
388388
modules := make(map[span.URI]struct{})
389-
for k := range got.getActiveModFiles() {
389+
for k := range got.ActiveModFiles() {
390390
modules[k] = struct{}{}
391391
}
392392
for _, modPath := range want.modules {

0 commit comments

Comments
 (0)