@@ -26,8 +26,8 @@ import (
26
26
// idWithAnalysis is used to track if the diagnostics for a given file were
27
27
// computed with analyses.
28
28
type idWithAnalysis struct {
29
- id source.VersionedFileIdentity
30
- withAnalysis bool
29
+ id source.VersionedFileIdentity
30
+ includeAnalysis bool
31
31
}
32
32
33
33
// A reportSet collects diagnostics for publication, sorting them by file and
@@ -38,15 +38,15 @@ type reportSet struct {
38
38
reports map [idWithAnalysis ]map [string ]* source.Diagnostic
39
39
}
40
40
41
- func (s * reportSet ) add (id source.VersionedFileIdentity , withAnalysis bool , diags ... * source.Diagnostic ) {
41
+ func (s * reportSet ) add (id source.VersionedFileIdentity , includeAnalysis bool , diags ... * source.Diagnostic ) {
42
42
s .mu .Lock ()
43
43
defer s .mu .Unlock ()
44
44
if s .reports == nil {
45
45
s .reports = make (map [idWithAnalysis ]map [string ]* source.Diagnostic )
46
46
}
47
47
key := idWithAnalysis {
48
- id : id ,
49
- withAnalysis : withAnalysis ,
48
+ id : id ,
49
+ includeAnalysis : includeAnalysis ,
50
50
}
51
51
if _ , ok := s .reports [key ]; ! ok {
52
52
s .reports [key ] = map [string ]* source.Diagnostic {}
@@ -79,7 +79,7 @@ func (s *Server) diagnoseDetached(snapshot source.Snapshot) {
79
79
// If a view has been created or the configuration changed, warn the user.
80
80
s .client .ShowMessage (ctx , shows )
81
81
}
82
- s .publishReports (ctx , snapshot , reports )
82
+ s .publishReports (ctx , snapshot , reports , false )
83
83
}
84
84
85
85
func (s * Server ) diagnoseSnapshot (snapshot source.Snapshot , changedURIs []span.URI ) {
@@ -99,17 +99,17 @@ func (s *Server) diagnoseSnapshot(snapshot source.Snapshot, changedURIs []span.U
99
99
event .Error (ctx , "diagnosing changed files" , err )
100
100
}
101
101
}
102
- s .publishReports (ctx , snapshot , reports )
102
+ s .publishReports (ctx , snapshot , reports , true )
103
103
s .debouncer .debounce (snapshot .View ().Name (), snapshot .ID (), delay , func () {
104
104
reports , _ := s .diagnose (ctx , snapshot , false )
105
- s .publishReports (ctx , snapshot , reports )
105
+ s .publishReports (ctx , snapshot , reports , false )
106
106
})
107
107
return
108
108
}
109
109
110
110
// Ignore possible workspace configuration warnings in the normal flow.
111
111
reports , _ := s .diagnose (ctx , snapshot , false )
112
- s .publishReports (ctx , snapshot , reports )
112
+ s .publishReports (ctx , snapshot , reports , false )
113
113
}
114
114
115
115
func (s * Server ) diagnoseChangedFiles (ctx context.Context , snapshot source.Snapshot , uris []span.URI ) (* reportSet , error ) {
@@ -215,11 +215,11 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
215
215
go func (pkg source.Package ) {
216
216
defer wg .Done ()
217
217
218
- withAnalysis := alwaysAnalyze // only run analyses for packages with open files
219
- var gcDetailsDir span.URI // find the package's optimization details, if available
218
+ includeAnalysis := alwaysAnalyze // only run analyses for packages with open files
219
+ var gcDetailsDir span.URI // find the package's optimization details, if available
220
220
for _ , pgf := range pkg .CompiledGoFiles () {
221
221
if snapshot .IsOpen (pgf .URI ) {
222
- withAnalysis = true
222
+ includeAnalysis = true
223
223
}
224
224
if gcDetailsDir == "" {
225
225
dirURI := span .URIFromPath (filepath .Dir (pgf .URI .Filename ()))
@@ -232,7 +232,7 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
232
232
}
233
233
}
234
234
235
- pkgReports , warn , err := source .Diagnostics (ctx , snapshot , pkg , withAnalysis )
235
+ pkgReports , warn , err := source .Diagnostics (ctx , snapshot , pkg , includeAnalysis )
236
236
237
237
// Check if might want to warn the user about their build configuration.
238
238
// Our caller decides whether to send the message.
@@ -251,7 +251,7 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
251
251
252
252
// Add all reports to the global map, checking for duplicates.
253
253
for id , diags := range pkgReports {
254
- reports .add (id , withAnalysis , diags ... )
254
+ reports .add (id , includeAnalysis , diags ... )
255
255
}
256
256
// If gc optimization details are available, add them to the
257
257
// diagnostic reports.
@@ -261,7 +261,7 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
261
261
event .Error (ctx , "warning: gc details" , err , tag .Snapshot .Of (snapshot .ID ()))
262
262
}
263
263
for id , diags := range gcReports {
264
- reports .add (id , withAnalysis , diags ... )
264
+ reports .add (id , includeAnalysis , diags ... )
265
265
}
266
266
}
267
267
}(pkg )
@@ -274,10 +274,10 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
274
274
// Check if we already have diagnostic reports for the given file,
275
275
// meaning that we have already seen its package.
276
276
var seen bool
277
- for _ , withAnalysis := range []bool {true , false } {
277
+ for _ , includeAnalysis := range []bool {true , false } {
278
278
_ , ok := reports .reports [idWithAnalysis {
279
- id : o .VersionedFileIdentity (),
280
- withAnalysis : withAnalysis ,
279
+ id : o .VersionedFileIdentity (),
280
+ includeAnalysis : includeAnalysis ,
281
281
}]
282
282
seen = seen || ok
283
283
}
@@ -349,7 +349,7 @@ func errorsToDiagnostic(ctx context.Context, snapshot source.Snapshot, errors []
349
349
return nil
350
350
}
351
351
352
- func (s * Server ) publishReports (ctx context.Context , snapshot source.Snapshot , reports * reportSet ) {
352
+ func (s * Server ) publishReports (ctx context.Context , snapshot source.Snapshot , reports * reportSet , isFirstPass bool ) {
353
353
// Check for context cancellation before publishing diagnostics.
354
354
if ctx .Err () != nil || reports == nil {
355
355
return
@@ -370,10 +370,10 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
370
370
}
371
371
source .SortDiagnostics (diagnostics )
372
372
toSend := sentDiagnostics {
373
- id : key .id ,
374
- sorted : diagnostics ,
375
- withAnalysis : key .withAnalysis ,
376
- snapshotID : snapshot .ID (),
373
+ id : key .id ,
374
+ sorted : diagnostics ,
375
+ includeAnalysis : key .includeAnalysis ,
376
+ snapshotID : snapshot .ID (),
377
377
}
378
378
379
379
// We use the zero values if this is an unknown file.
@@ -382,10 +382,11 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
382
382
// Snapshot IDs are always increasing, so we use them instead of file
383
383
// versions to create the correct order for diagnostics.
384
384
385
- // If we've already delivered diagnostics for a future snapshot for this file,
386
- // do not deliver them.
385
+ // If we've already delivered diagnostics for a future snapshot for
386
+ // this file, do not deliver them.
387
387
if delivered .snapshotID > toSend .snapshotID {
388
- // Do not update the delivered map since it already contains newer diagnostics.
388
+ // Do not update the delivered map since it already contains newer
389
+ // diagnostics.
389
390
continue
390
391
}
391
392
@@ -399,10 +400,18 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
399
400
// If we've already delivered diagnostics for this file, at this
400
401
// snapshot, with analyses, do not send diagnostics without analyses.
401
402
if delivered .snapshotID == toSend .snapshotID && delivered .id == toSend .id &&
402
- delivered .withAnalysis && ! toSend .withAnalysis {
403
+ delivered .includeAnalysis && ! toSend .includeAnalysis {
403
404
// Do not update the delivered map since it already contains better diagnostics.
404
405
continue
405
406
}
407
+
408
+ // If we've previously delivered non-empty diagnostics and this is a
409
+ // first diagnostic pass, wait for a subsequent pass to complete before
410
+ // sending empty diagnostics to avoid flickering diagnostics.
411
+ if isFirstPass && delivered .includeAnalysis && ! toSend .includeAnalysis && len (toSend .sorted ) == 0 {
412
+ continue
413
+ }
414
+
406
415
if err := s .client .PublishDiagnostics (ctx , & protocol.PublishDiagnosticsParams {
407
416
Diagnostics : toProtocolDiagnostics (diagnostics ),
408
417
URI : protocol .URIFromSpanURI (key .id .URI ),
0 commit comments