Skip to content

Commit f53864d

Browse files
committed
internal/lsp: remove command-line-arguments as a workspace package
If a package starts out as command-line-arguments, and then becomes "valid" (i.e., gets a package declaration), we shouldn't continue to try to diagnose "command-line-arguments". We should remove "command-line-arguments" from workspace packages any time its metadata is invalidated (assuming it may get added back if a file= query produces it again). Include the relevant regression test. Fixes golang/go#37978 Change-Id: I7fc51edeb58007b4b4a163336cbeb752a53da322 Reviewed-on: https://go-review.googlesource.com/c/tools/+/225317 Run-TryBot: Rebecca Stambler <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 4c1ea05 commit f53864d

File tree

4 files changed

+49
-12
lines changed

4 files changed

+49
-12
lines changed

internal/lsp/cache/snapshot.go

+15-5
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ func (s *snapshot) addID(uri span.URI, id packageID) {
478478
// had a command-line-arguments ID, we should just replace it.
479479
if existingID == "command-line-arguments" {
480480
s.ids[uri][i] = id
481+
// Delete command-line-arguments if it was a workspace package.
482+
delete(s.workspacePackages, existingID)
481483
return
482484
}
483485
}
@@ -585,6 +587,7 @@ func (s *snapshot) reloadOrphanedFiles(ctx context.Context) error {
585587
// Check for context cancellation so that we don't incorrectly mark files
586588
// as unloadable, but don't return before setting all workspace packages.
587589
if ctx.Err() == nil && err != nil {
590+
event.Error(ctx, "reloadOrphanedFiles: failed to load", err, tag.Query.Of(scopes))
588591
s.mu.Lock()
589592
for _, scope := range scopes {
590593
uri := span.URI(scope.(fileURI))
@@ -693,7 +696,6 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Fi
693696
if invalidateMetadata || fileWasSaved(originalFH, currentFH) {
694697
result.modTidyHandle = nil
695698
}
696-
697699
if currentFH.Identity().Kind == source.Mod {
698700
// If the view's go.mod file's contents have changed, invalidate the metadata
699701
// for all of the packages in the workspace.
@@ -749,10 +751,6 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Fi
749751
// Make sure to remove the changed file from the unloadable set.
750752
delete(result.unloadableFiles, withoutURI)
751753
}
752-
// Copy the set of initally loaded packages.
753-
for k, v := range s.workspacePackages {
754-
result.workspacePackages[k] = v
755-
}
756754
// Copy the package type information.
757755
for k, v := range s.packages {
758756
if _, ok := transitiveIDs[k.id]; ok {
@@ -786,6 +784,18 @@ outer:
786784
}
787785
result.ids[k] = ids
788786
}
787+
// Copy the set of initally loaded packages.
788+
for id, pkgPath := range s.workspacePackages {
789+
// TODO(rstambler): For now, we only invalidate "command-line-arguments"
790+
// from workspace packages, but in general, we need to handle deletion
791+
// of a package.
792+
if id == "command-line-arguments" {
793+
if invalidateMetadata, ok := transitiveIDs[id]; invalidateMetadata && ok {
794+
continue
795+
}
796+
}
797+
result.workspacePackages[id] = pkgPath
798+
}
789799
// Don't bother copying the importedBy graph,
790800
// as it changes each time we update metadata.
791801
return result

internal/lsp/diagnostics.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysA
6161
return nil
6262
}
6363
if err != nil {
64-
event.Error(ctx, "diagnose: could not generate diagnostics for go.mod file", err, tag.Directory.Of(snapshot.View().Folder))
64+
event.Error(ctx, "warning: diagnose go.mod", err, tag.Directory.Of(snapshot.View().Folder))
6565
}
6666
// Ensure that the reports returned from mod.Diagnostics are only related to the
6767
// go.mod file for the module.
@@ -85,7 +85,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysA
8585
return nil
8686
}
8787
if err != nil {
88-
event.Error(ctx, "diagnose: no workspace packages", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder))
88+
event.Error(ctx, "failed to load workspace packages, skipping diagnostics", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder))
8989
return nil
9090
}
9191
for _, ph := range wsPackages {
@@ -111,7 +111,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysA
111111
return
112112
}
113113
if err != nil {
114-
event.Error(ctx, "diagnose: could not generate diagnostics for package", err, tag.Snapshot.Of(snapshot.ID()), tag.Package.Of(ph.ID()))
114+
event.Error(ctx, "warning: diagnose package", err, tag.Snapshot.Of(snapshot.ID()), tag.Package.Of(ph.ID()))
115115
return
116116
}
117117
reportsMu.Lock()

internal/lsp/regtest/diagnostics_test.go

+30-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ package regtest
66

77
import (
88
"testing"
9+
10+
"golang.org/x/tools/internal/lsp/fake"
911
)
1012

13+
// Use mod.com for all go.mod files due to golang/go#35230.
1114
const exampleProgram = `
1215
-- go.mod --
13-
module mod
16+
module mod.com
1417
1518
go 1.12
1619
-- main.go --
@@ -34,7 +37,7 @@ func TestDiagnosticErrorInEditedFile(t *testing.T) {
3437

3538
const onlyMod = `
3639
-- go.mod --
37-
module mod
40+
module mod.com
3841
3942
go 1.12
4043
`
@@ -65,7 +68,7 @@ func TestDiagnosticErrorInNewFile(t *testing.T) {
6568
// badPackage contains a duplicate definition of the 'a' const.
6669
const badPackage = `
6770
-- go.mod --
68-
module mod
71+
module mod.com
6972
7073
go 1.12
7174
-- a.go --
@@ -115,3 +118,27 @@ const a = 3`)
115118
EmptyDiagnostics("c.go"))
116119
})
117120
}
121+
122+
func TestIssue37978(t *testing.T) {
123+
runner.Run(t, exampleProgram, func(env *Env) {
124+
// Create a new workspace-level directory and empty file.
125+
env.CreateBuffer("c/c.go", "")
126+
127+
// Write the file contents with a missing import.
128+
env.EditBuffer("c/c.go", fake.Edit{
129+
Text: `package c
130+
131+
const a = http.MethodGet
132+
`,
133+
})
134+
env.Await(
135+
env.DiagnosticAtRegexp("c/c.go", "http.MethodGet"),
136+
)
137+
// Save file, which will organize imports, adding the expected import.
138+
// Expect the diagnostics to clear.
139+
env.SaveBuffer("c/c.go")
140+
env.Await(
141+
EmptyDiagnostics("c/c.go"),
142+
)
143+
})
144+
}

internal/lsp/regtest/wrappers.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (e *Env) RegexpSearch(name, re string) fake.Pos {
7171
pos, err = e.W.RegexpSearch(name, re)
7272
}
7373
if err != nil {
74-
e.T.Fatalf("RegexpSearch: %v", err)
74+
e.T.Fatalf("RegexpSearch: %v, %v", name, err)
7575
}
7676
return pos
7777
}

0 commit comments

Comments
 (0)