Skip to content

Commit 3c293ad

Browse files
committed
internal/cache: invalidate broken imports when package files change
When a file->package association changes, it may fix broken imports. Fix this invalidation in Snapshot.clone. Fixes golang/go#66384 Change-Id: If0f491548043a30bb6302bf207733f6f458f2574 Reviewed-on: https://go-review.googlesource.com/c/tools/+/588764 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 5eff1ee commit 3c293ad

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

gopls/internal/cache/snapshot.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -1775,16 +1775,18 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
17751775
// Compute invalidations based on file changes.
17761776
anyImportDeleted := false // import deletions can resolve cycles
17771777
anyFileOpenedOrClosed := false // opened files affect workspace packages
1778-
anyFileAdded := false // adding a file can resolve missing dependencies
1778+
anyPkgFileChanged := false // adding a file to a package can resolve missing dependencies
17791779

17801780
for uri, newFH := range changedFiles {
17811781
// The original FileHandle for this URI is cached on the snapshot.
17821782
oldFH := oldFiles[uri] // may be nil
17831783
_, oldOpen := oldFH.(*overlay)
17841784
_, newOpen := newFH.(*overlay)
17851785

1786+
// TODO(rfindley): consolidate with 'metadataChanges' logic below, which
1787+
// also considers existential changes.
17861788
anyFileOpenedOrClosed = anyFileOpenedOrClosed || (oldOpen != newOpen)
1787-
anyFileAdded = anyFileAdded || (oldFH == nil || !fileExists(oldFH)) && fileExists(newFH)
1789+
anyPkgFileChanged = anyPkgFileChanged || (oldFH == nil || !fileExists(oldFH)) && fileExists(newFH)
17881790

17891791
// If uri is a Go file, check if it has changed in a way that would
17901792
// invalidate metadata. Note that we can't use s.view.FileKind here,
@@ -1802,6 +1804,7 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
18021804

18031805
invalidateMetadata = invalidateMetadata || reinit
18041806
anyImportDeleted = anyImportDeleted || importDeleted
1807+
anyPkgFileChanged = anyPkgFileChanged || pkgFileChanged
18051808

18061809
// Mark all of the package IDs containing the given file.
18071810
filePackageIDs := invalidatedPackageIDs(uri, s.meta.IDs, pkgFileChanged)
@@ -1878,7 +1881,7 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
18781881
// We could be smart here and try to guess which packages may have been
18791882
// fixed, but until that proves necessary, just invalidate metadata for any
18801883
// package with missing dependencies.
1881-
if anyFileAdded {
1884+
if anyPkgFileChanged {
18821885
for id, mp := range s.meta.Packages {
18831886
for _, impID := range mp.DepsByImpPath {
18841887
if impID == "" { // missing import

gopls/internal/test/integration/diagnostics/invalidation_test.go

+37-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func _() {
2727
x := 2
2828
}
2929
`
30-
Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file.
30+
Run(t, files, func(t *testing.T, env *Env) { // Create a new workspace-level directory and empty file.
3131
env.OpenFile("main.go")
3232
var afterOpen protocol.PublishDiagnosticsParams
3333
env.AfterChange(
@@ -70,7 +70,7 @@ func _() {
7070
// Irrelevant comment #0
7171
`
7272

73-
Run(t, files, func(_ *testing.T, env *Env) { // Create a new workspace-level directory and empty file.
73+
Run(t, files, func(t *testing.T, env *Env) { // Create a new workspace-level directory and empty file.
7474
env.OpenFile("main.go")
7575
var d protocol.PublishDiagnosticsParams
7676
env.AfterChange(
@@ -104,3 +104,38 @@ func _() {
104104
}
105105
})
106106
}
107+
108+
func TestCreatingPackageInvalidatesDiagnostics_Issue66384(t *testing.T) {
109+
const files = `
110+
-- go.mod --
111+
module example.com
112+
113+
go 1.15
114+
-- main.go --
115+
package main
116+
117+
import "example.com/pkg"
118+
119+
func main() {
120+
var _ pkg.Thing
121+
}
122+
`
123+
Run(t, files, func(t *testing.T, env *Env) {
124+
env.OnceMet(
125+
InitialWorkspaceLoad,
126+
Diagnostics(env.AtRegexp("main.go", `"example.com/pkg"`)),
127+
)
128+
// In order for this test to reproduce golang/go#66384, we have to create
129+
// the buffer, wait for loads, and *then* "type out" the contents. Doing so
130+
// reproduces the conditions of the bug report, that typing the package
131+
// name itself doesn't invalidate the broken import.
132+
env.CreateBuffer("pkg/pkg.go", "")
133+
env.AfterChange()
134+
env.EditBuffer("pkg/pkg.go", protocol.TextEdit{NewText: "package pkg\ntype Thing struct{}\n"})
135+
env.AfterChange()
136+
env.SaveBuffer("pkg/pkg.go")
137+
env.AfterChange(NoDiagnostics())
138+
env.SetBufferContent("pkg/pkg.go", "package pkg")
139+
env.AfterChange(Diagnostics(env.AtRegexp("main.go", "Thing")))
140+
})
141+
}

0 commit comments

Comments
 (0)