Skip to content

Commit 8b05170

Browse files
authored
LSP fix file imports becoming unresolvable (#4097)
1 parent f4e6125 commit 8b05170

File tree

5 files changed

+265
-71
lines changed

5 files changed

+265
-71
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Fix LSP published diagnostics to filter to the opened file.
66
- Add `textDocument/documentSymbol` support for `buf lsp serve`.
7+
- Fix LSP navigation for cached modules which could cause import paths to become unresolvable.
78

89
## [v1.59.0] - 2025-10-20
910

private/buf/buflsp/buflsp.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func Serve(
6262
queryExecutor: queryExecutor,
6363
}
6464
lsp.fileManager = newFileManager(lsp)
65+
lsp.workspaceManager = newWorkspaceManager(lsp)
6566
off := protocol.TraceOff
6667
lsp.traceValue.Store(&off)
6768

@@ -83,13 +84,14 @@ type lsp struct {
8384
client protocol.Client
8485
container appext.Container
8586

86-
logger *slog.Logger
87-
controller bufctl.Controller
88-
wasmRuntime wasm.Runtime
89-
fileManager *fileManager
90-
queryExecutor *incremental.Executor
91-
wktBucket storage.ReadBucket
92-
shutdown bool
87+
logger *slog.Logger
88+
controller bufctl.Controller
89+
wasmRuntime wasm.Runtime
90+
fileManager *fileManager
91+
workspaceManager *workspaceManager
92+
queryExecutor *incremental.Executor
93+
wktBucket storage.ReadBucket
94+
shutdown bool
9395

9496
lock sync.Mutex
9597

private/buf/buflsp/file.go

Lines changed: 55 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@ import (
3333
"buf.build/go/standard/xio"
3434
"buf.build/go/standard/xlog/xslog"
3535
"buf.build/go/standard/xslices"
36-
"github.com/bufbuild/buf/private/buf/bufworkspace"
3736
"github.com/bufbuild/buf/private/bufpkg/bufanalysis"
3837
"github.com/bufbuild/buf/private/bufpkg/bufcheck"
3938
"github.com/bufbuild/buf/private/bufpkg/bufimage"
40-
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
4139
"github.com/bufbuild/buf/private/pkg/git"
4240
"github.com/bufbuild/buf/private/pkg/normalpath"
4341
"github.com/bufbuild/buf/private/pkg/storage"
@@ -72,9 +70,7 @@ type file struct {
7270
version int32
7371
hasText bool // Whether this file has ever had text read into it.
7472

75-
workspace bufworkspace.Workspace
76-
module bufmodule.Module
77-
checkClient bufcheck.Client
73+
workspace *workspace
7874

7975
againstStrategy againstStrategy
8076
againstGitRef string
@@ -135,6 +131,10 @@ func (f *file) Close(ctx context.Context) {
135131
close(f.checkWork)
136132
f.checkWork = nil
137133
}
134+
if f.workspace != nil {
135+
f.workspace.Release()
136+
f.workspace = nil
137+
}
138138
}
139139

140140
// IsOpenInEditor returns whether this file was opened in the LSP client's
@@ -314,44 +314,30 @@ func (f *file) Refresh(ctx context.Context) {
314314
// The Buf workspace provides the sources for the compiler to work with.
315315
func (f *file) RefreshWorkspace(ctx context.Context) {
316316
f.lsp.logger.Debug(
317-
"getting workspace",
317+
"refresh workspace",
318318
slog.String("file", f.uri.Filename()),
319319
slog.Int("version", int(f.version)),
320320
)
321-
workspace, err := f.lsp.controller.GetWorkspace(ctx, f.uri.Filename())
322-
if err != nil {
323-
f.lsp.logger.Error(
324-
"could not load workspace",
325-
slog.String("uri", string(f.uri)),
326-
xslog.ErrorAttr(err),
327-
)
328-
return
329-
}
330-
f.workspace = workspace
331-
332-
var module bufmodule.Module
333-
for _, mod := range workspace.Modules() {
334-
// We do not care about this error, so we discard it.
335-
_ = mod.WalkFileInfos(ctx, func(fileInfo bufmodule.FileInfo) error {
336-
if fileInfo.LocalPath() == f.uri.Filename() {
337-
module = mod
338-
}
339-
return nil
340-
})
341-
if module != nil {
342-
break
321+
if f.workspace != nil {
322+
if err := f.workspace.Refresh(ctx); err != nil {
323+
f.lsp.logger.Error(
324+
"could not refresh workspace",
325+
slog.String("uri", string(f.uri)),
326+
xslog.ErrorAttr(err),
327+
)
343328
}
329+
} else {
330+
workspace, err := f.lsp.workspaceManager.LeaseWorkspace(ctx, f.uri)
331+
if err != nil {
332+
f.lsp.logger.Error(
333+
"could not lease workspace",
334+
slog.String("uri", string(f.uri)),
335+
xslog.ErrorAttr(err),
336+
)
337+
return
338+
}
339+
f.workspace = workspace
344340
}
345-
if module == nil {
346-
f.lsp.logger.Warn("could not find module", slog.String("file", f.uri.Filename()))
347-
}
348-
f.module = module
349-
350-
checkClient, err := f.lsp.controller.GetCheckClientForWorkspace(ctx, workspace, f.lsp.wasmRuntime)
351-
if err != nil {
352-
f.lsp.logger.Warn("could not get check client", xslog.ErrorAttr(err))
353-
}
354-
f.checkClient = checkClient
355341
}
356342

357343
// IndexImports keeps track of importable files.
@@ -407,17 +393,9 @@ func (f *file) IndexImports(ctx context.Context) {
407393
func (f *file) getWorkspaceFileInfos(ctx context.Context) ([]storage.ObjectInfo, error) {
408394
seen := make(map[string]struct{})
409395
var fileInfos []storage.ObjectInfo
410-
for _, module := range f.workspace.Modules() {
411-
if err := module.WalkFileInfos(ctx, func(fileInfo bufmodule.FileInfo) error {
412-
if fileInfo.FileType() != bufmodule.FileTypeProto {
413-
return nil
414-
}
415-
fileInfos = append(fileInfos, fileInfo)
416-
seen[fileInfo.Path()] = struct{}{}
417-
return nil
418-
}); err != nil {
419-
return nil, err
420-
}
396+
for _, fileInfo := range f.workspace.fileNameToFileInfo {
397+
fileInfos = append(fileInfos, fileInfo)
398+
seen[fileInfo.Path()] = struct{}{}
421399
}
422400
// Add all wellknown types if not provided within the workspace.
423401
if err := f.lsp.wktBucket.Walk(ctx, "", func(objectInfo storage.ObjectInfo) error {
@@ -1046,22 +1024,29 @@ func (f *file) RunLints(ctx context.Context) bool {
10461024
return false
10471025
}
10481026

1049-
if f.module == nil || f.image == nil {
1027+
workspace := f.workspace.Workspace()
1028+
module := f.workspace.GetModule(f.uri)
1029+
checkClient := f.workspace.CheckClient()
1030+
if workspace == nil {
1031+
f.lsp.logger.Warn(fmt.Sprintf("could not find workspace for %q", f.uri))
1032+
return false
1033+
}
1034+
if module == nil || f.image == nil {
10501035
f.lsp.logger.Warn(fmt.Sprintf("could not find image for %q", f.uri))
10511036
return false
10521037
}
1053-
if f.checkClient == nil {
1038+
if checkClient == nil {
10541039
f.lsp.logger.Warn(fmt.Sprintf("could not find check client for %q", f.uri))
10551040
return false
10561041
}
10571042

1058-
f.lsp.logger.Debug(fmt.Sprintf("running lint for %q in %v", f.uri, f.module.FullName()))
1059-
return f.appendLintErrors("buf lint", f.checkClient.Lint(
1043+
f.lsp.logger.Debug(fmt.Sprintf("running lint for %q in %v", f.uri, module.FullName()))
1044+
return f.appendLintErrors("buf lint", checkClient.Lint(
10601045
ctx,
1061-
f.workspace.GetLintConfigForOpaqueID(f.module.OpaqueID()),
1046+
workspace.GetLintConfigForOpaqueID(module.OpaqueID()),
10621047
f.image,
1063-
bufcheck.WithPluginConfigs(f.workspace.PluginConfigs()...),
1064-
bufcheck.WithPolicyConfigs(f.workspace.PolicyConfigs()...),
1048+
bufcheck.WithPluginConfigs(workspace.PluginConfigs()...),
1049+
bufcheck.WithPolicyConfigs(workspace.PolicyConfigs()...),
10651050
))
10661051
}
10671052

@@ -1074,23 +1059,30 @@ func (f *file) RunBreaking(ctx context.Context) bool {
10741059
return false
10751060
}
10761061

1077-
if f.module == nil || f.image == nil || f.againstImage == nil {
1062+
workspace := f.workspace.Workspace()
1063+
module := f.workspace.GetModule(f.uri)
1064+
checkClient := f.workspace.CheckClient()
1065+
if workspace == nil {
1066+
f.lsp.logger.Warn(fmt.Sprintf("could not find workspace for %q", f.uri))
1067+
return false
1068+
}
1069+
if module == nil || f.image == nil || f.againstImage == nil {
10781070
f.lsp.logger.Warn(fmt.Sprintf("could not find --against image for %q", f.uri))
10791071
return false
10801072
}
1081-
if f.checkClient == nil {
1073+
if checkClient == nil {
10821074
f.lsp.logger.Warn(fmt.Sprintf("could not find check client for %q", f.uri))
10831075
return false
10841076
}
10851077

1086-
f.lsp.logger.Debug(fmt.Sprintf("running breaking for %q in %v", f.uri, f.module.FullName()))
1087-
return f.appendLintErrors("buf breaking", f.checkClient.Breaking(
1078+
f.lsp.logger.Debug(fmt.Sprintf("running breaking for %q in %v", f.uri, module.FullName()))
1079+
return f.appendLintErrors("buf breaking", checkClient.Breaking(
10881080
ctx,
1089-
f.workspace.GetBreakingConfigForOpaqueID(f.module.OpaqueID()),
1081+
workspace.GetBreakingConfigForOpaqueID(module.OpaqueID()),
10901082
f.image,
10911083
f.againstImage,
1092-
bufcheck.WithPluginConfigs(f.workspace.PluginConfigs()...),
1093-
bufcheck.WithPolicyConfigs(f.workspace.PolicyConfigs()...),
1084+
bufcheck.WithPluginConfigs(workspace.PluginConfigs()...),
1085+
bufcheck.WithPolicyConfigs(workspace.PolicyConfigs()...),
10941086
))
10951087
}
10961088

private/buf/buflsp/file_manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type fileManager struct {
3030
uriToFile refcount.Map[protocol.URI, file]
3131
}
3232

33-
// newFiles creates a new file manager.
33+
// newFileManager creates a new file manager.
3434
func newFileManager(lsp *lsp) *fileManager {
3535
return &fileManager{lsp: lsp}
3636
}

0 commit comments

Comments
 (0)