Skip to content

Commit ae42f3c

Browse files
committed
internal/lsp: recover from a view initialization failure
If an orphaned file is used to recover a workspace package, we should remove the initialization error and treat the view as correctly initialized. Also, stop caching metadata for packages with no files. We have no way to invalidate it, and it's useless, so just re-load those files as needed. Fixes golang/go#36795. Fixes golang/go#36671. Fixes golang/go#36772. Change-Id: I0aee5a43401517b6073d27136cca533160effef2 Reviewed-on: https://go-review.googlesource.com/c/tools/+/216637 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
1 parent 345141a commit ae42f3c

File tree

5 files changed

+22
-35
lines changed

5 files changed

+22
-35
lines changed

internal/lsp/cache/load.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,15 @@ func (s *snapshot) updateMetadata(ctx context.Context, scopes []interface{}, pkg
149149
}
150150
}
151151
if !containsDir || s.view.Options().VerboseOutput {
152-
log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
152+
log.Print(ctx, "go/packages.Load", tag.Of("snapshot", s.ID()), tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
153153
}
154-
// golang/go#36292: Ignore packages with no sources and no errors.
155-
if len(pkg.GoFiles) == 0 && len(pkg.CompiledGoFiles) == 0 && len(pkg.Errors) == 0 {
154+
// Ignore packages with no sources, since we will never be able to
155+
// correctly invalidate that metadata.
156+
if len(pkg.GoFiles) == 0 && len(pkg.CompiledGoFiles) == 0 {
156157
continue
157158
}
158159
// Skip test main packages.
159-
if s.view.isTestMain(ctx, pkg) {
160+
if isTestMain(ctx, pkg, s.view.gocache) {
160161
continue
161162
}
162163
// Set the metadata for this package.
@@ -234,7 +235,7 @@ func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *
234235
return nil
235236
}
236237

237-
func (v *view) isTestMain(ctx context.Context, pkg *packages.Package) bool {
238+
func isTestMain(ctx context.Context, pkg *packages.Package, gocache string) bool {
238239
// Test mains must have an import path that ends with ".test".
239240
if !strings.HasSuffix(pkg.PkgPath, ".test") {
240241
return false
@@ -247,7 +248,7 @@ func (v *view) isTestMain(ctx context.Context, pkg *packages.Package) bool {
247248
if len(pkg.GoFiles) > 1 {
248249
return false
249250
}
250-
if !strings.HasPrefix(pkg.GoFiles[0], v.gocache) {
251+
if !strings.HasPrefix(pkg.GoFiles[0], gocache) {
251252
return false
252253
}
253254
return true

internal/lsp/cache/snapshot.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,7 @@ func (s *snapshot) KnownPackages(ctx context.Context) ([]source.PackageHandle, e
359359
func (s *snapshot) CachedImportPaths(ctx context.Context) (map[string]source.Package, error) {
360360
// Don't reload workspace package metadata.
361361
// This function is meant to only return currently cached information.
362-
if err := s.view.awaitInitialized(ctx); err != nil {
363-
return nil, err
364-
}
362+
s.view.awaitInitialized(ctx)
365363

366364
s.mu.Lock()
367365
defer s.mu.Unlock()
@@ -537,9 +535,8 @@ func (s *snapshot) findFileHandle(f *fileBase) source.FileHandle {
537535

538536
func (s *snapshot) awaitLoaded(ctx context.Context) error {
539537
// Do not return results until the snapshot's view has been initialized.
540-
if err := s.view.awaitInitialized(ctx); err != nil {
541-
return err
542-
}
538+
s.view.awaitInitialized(ctx)
539+
543540
m, err := s.reloadWorkspace(ctx)
544541
if err != nil {
545542
return err

internal/lsp/cache/view.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ type view struct {
9090
// On initialization, the view's workspace packages are loaded.
9191
// All of the fields below are set as part of initialization.
9292
// If we failed to load, we don't re-try to avoid too many go/packages calls.
93-
initializeOnce sync.Once
94-
initialized chan struct{}
95-
initializationError error
93+
initializeOnce sync.Once
94+
initialized chan struct{}
9695

9796
// builtin pins the AST and package for builtin.go in memory.
9897
builtin *builtinPackageHandle
@@ -205,9 +204,8 @@ func (v *view) Rebuild(ctx context.Context) (source.Snapshot, error) {
205204
}
206205

207206
func (v *view) LookupBuiltin(ctx context.Context, name string) (*ast.Object, error) {
208-
if err := v.awaitInitialized(ctx); err != nil {
209-
return nil, err
210-
}
207+
v.awaitInitialized(ctx)
208+
211209
data := v.builtin.handle.Get(ctx)
212210
if ctx.Err() != nil {
213211
return nil, ctx.Err()
@@ -553,7 +551,7 @@ func (v *view) initialize(ctx context.Context, s *snapshot) {
553551
v.initializeOnce.Do(func() {
554552
defer close(v.initialized)
555553

556-
v.initializationError = func() error {
554+
err := func() error {
557555
// Do not cancel the call to go/packages.Load for the entire workspace.
558556
meta, err := s.load(ctx, viewLoadScope("LOAD_VIEW"), packagePath("builtin"))
559557
if err != nil {
@@ -576,21 +574,17 @@ func (v *view) initialize(ctx context.Context, s *snapshot) {
576574
}
577575
return nil
578576
}()
577+
if err != nil {
578+
log.Error(ctx, "initial workspace load failed", err)
579+
}
579580
})
580581
}
581582

582-
func (v *view) Initialized(ctx context.Context) bool {
583-
err := v.awaitInitialized(ctx)
584-
return err == nil
585-
}
586-
587-
func (v *view) awaitInitialized(ctx context.Context) error {
583+
func (v *view) awaitInitialized(ctx context.Context) {
588584
select {
589585
case <-ctx.Done():
590-
return ctx.Err()
591586
case <-v.initialized:
592587
}
593-
return v.initializationError
594588
}
595589

596590
// invalidateContent invalidates the content of a Go file,
@@ -605,7 +599,7 @@ func (v *view) invalidateContent(ctx context.Context, uris []span.URI) source.Sn
605599
v.cancelBackground()
606600

607601
// Do not clone a snapshot until its view has finished initializing.
608-
_ = v.awaitInitialized(ctx)
602+
v.awaitInitialized(ctx)
609603

610604
// This should be the only time we hold the view's snapshot lock for any period of time.
611605
v.snapshotMu.Lock()

internal/lsp/diagnostics.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,14 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot) {
3636
ctx, done := trace.StartSpan(ctx, "lsp:background-worker")
3737
defer done()
3838

39-
ctx = telemetry.Snapshot.With(ctx, snapshot.ID())
40-
4139
// Diagnose all of the packages in the workspace.
4240
go func() {
4341
wsPackages, err := snapshot.WorkspacePackages(ctx)
4442
if ctx.Err() != nil {
4543
return
4644
}
4745
if err != nil {
48-
log.Error(ctx, "diagnose: no workspace packages", err, telemetry.Directory.Of(snapshot.View().Folder))
46+
log.Error(ctx, "diagnose: no workspace packages", err, telemetry.Snapshot.Of(snapshot.ID()), telemetry.Directory.Of(snapshot.View().Folder))
4947
return
5048
}
5149
for _, ph := range wsPackages {
@@ -70,7 +68,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot) {
7068
return
7169
}
7270
if err != nil {
73-
log.Error(ctx, "diagnose: could not generate diagnostics for package", err, telemetry.Package.Of(ph.ID()))
71+
log.Error(ctx, "diagnose: could not generate diagnostics for package", err, telemetry.Snapshot.Of(snapshot.ID()), telemetry.Package.Of(ph.ID()))
7472
return
7573
}
7674
s.publishReports(ctx, snapshot, reports, withAnalyses)

internal/lsp/source/view.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,6 @@ type View interface {
128128
// Snapshot returns the current snapshot for the view.
129129
Snapshot() Snapshot
130130

131-
// Initialized returns true if the view has been initialized without errors.
132-
Initialized(ctx context.Context) bool
133-
134131
// Rebuild rebuilds the current view, replacing the original view in its session.
135132
Rebuild(ctx context.Context) (Snapshot, error)
136133

0 commit comments

Comments
 (0)