Skip to content

Commit 3034d9c

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/lsp/cmd: append, don't overwrite, in PublishDiagnostics
This change causes the CLI tool's PublishDiagnostics operation to accumulate, rather than overwrite, the slice of file diagnostics, under the hypothesis that it is receiving multiple events and the later ones are clobbering the earlier ones, causing golang/go#59475. We perform a crude de-duplication in case this should result in duplicate diagnostics. A more robust approach using textDocument/diagnostic will be added in a follow-up. Also, clarify the mutex's responsibility, copy (don't alias) the diagnostics slice in the critical section, and tidy up the surrounding code. Updates golang/go#59475 Change-Id: Ifbb4974ef00ab7bd6547de28f052cec86462230b Reviewed-on: https://go-review.googlesource.com/c/tools/+/494275 Run-TryBot: Alan Donovan <[email protected]> Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 4318d63 commit 3034d9c

File tree

2 files changed

+38
-16
lines changed

2 files changed

+38
-16
lines changed

gopls/internal/lsp/cmd/cmd.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ type cmdClient struct {
406406
diagnosticsMu sync.Mutex
407407
diagnosticsDone chan struct{}
408408

409-
filesMu sync.Mutex
409+
filesMu sync.Mutex // guards files map and each cmdFile.diagnostics
410410
files map[span.URI]*cmdFile
411411
}
412412

@@ -518,6 +518,11 @@ func (c *cmdClient) ApplyEdit(ctx context.Context, p *protocol.ApplyWorkspaceEdi
518518
}
519519

520520
func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishDiagnosticsParams) error {
521+
var debug = os.Getenv(DebugSuggestedFixEnvVar) == "true"
522+
if debug {
523+
log.Printf("PublishDiagnostics URI=%v Diagnostics=%v", p.URI, p.Diagnostics)
524+
}
525+
521526
if p.URI == "gopls://diagnostics-done" {
522527
close(c.diagnosticsDone)
523528
}
@@ -530,7 +535,24 @@ func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishD
530535
defer c.filesMu.Unlock()
531536

532537
file := c.getFile(ctx, fileURI(p.URI))
533-
file.diagnostics = p.Diagnostics
538+
file.diagnostics = append(file.diagnostics, p.Diagnostics...)
539+
540+
// Perform a crude in-place deduplication.
541+
// TODO(golang/go#60122): replace the ad-hoc gopls/diagnoseFiles
542+
// non-standard request with support for textDocument/diagnostic,
543+
// so that we don't need to do this de-duplication.
544+
type key [5]interface{}
545+
seen := make(map[key]bool)
546+
out := file.diagnostics[:0]
547+
for _, d := range file.diagnostics {
548+
k := key{d.Range, d.Severity, d.Code, d.Source, d.Message}
549+
if !seen[k] {
550+
seen[k] = true
551+
out = append(out, d)
552+
}
553+
}
554+
file.diagnostics = out
555+
534556
return nil
535557
}
536558

gopls/internal/lsp/cmd/suggested_fix.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,39 +67,38 @@ func (s *suggestedFix) Run(ctx context.Context, args ...string) error {
6767
if err != nil {
6868
return err
6969
}
70+
rng, err := file.mapper.SpanRange(from)
71+
if err != nil {
72+
return err
73+
}
7074

75+
// Get diagnostics.
7176
if err := conn.diagnoseFiles(ctx, []span.URI{uri}); err != nil {
7277
return err
7378
}
79+
diagnostics := []protocol.Diagnostic{} // LSP wants non-nil slice
7480
conn.Client.filesMu.Lock()
75-
defer conn.Client.filesMu.Unlock()
81+
diagnostics = append(diagnostics, file.diagnostics...)
82+
conn.Client.filesMu.Unlock()
83+
if debug {
84+
log.Printf("file diagnostics: %#v", diagnostics)
85+
}
7686

87+
// Request code actions
7788
codeActionKinds := []protocol.CodeActionKind{protocol.QuickFix}
7889
if len(args) > 1 {
7990
codeActionKinds = []protocol.CodeActionKind{}
8091
for _, k := range args[1:] {
8192
codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k))
8293
}
8394
}
84-
85-
rng, err := file.mapper.SpanRange(from)
86-
if err != nil {
87-
return err
88-
}
89-
if file.diagnostics == nil {
90-
// LSP requires a slice, not a nil.
91-
file.diagnostics = []protocol.Diagnostic{}
92-
}
93-
if debug {
94-
log.Printf("file diagnostics: %#v", file.diagnostics)
95-
}
9695
p := protocol.CodeActionParams{
9796
TextDocument: protocol.TextDocumentIdentifier{
9897
URI: protocol.URIFromSpanURI(uri),
9998
},
10099
Context: protocol.CodeActionContext{
101100
Only: codeActionKinds,
102-
Diagnostics: file.diagnostics,
101+
Diagnostics: diagnostics,
103102
},
104103
Range: rng,
105104
}
@@ -111,6 +110,7 @@ func (s *suggestedFix) Run(ctx context.Context, args ...string) error {
111110
log.Printf("code actions: %#v", actions)
112111
}
113112

113+
// Gather edits from matching code actions.
114114
var edits []protocol.TextEdit
115115
for _, a := range actions {
116116
if a.Command != nil {

0 commit comments

Comments
 (0)