Skip to content

Commit 0ca9d30

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/lsp/cache: fix nil panic in analysis toSourceDiagnostic
The set of enabled analyzers is expanded to include requirements, but we should not use the expanded set in the final loop when we map back to source.Analyzers. Nonetheless, it is surprising that any analyzer only in the expandes set should report a diagnostics, so I've added an assertion. Fixes golang/go#60909 Change-Id: I3b6e21194f7d717628822b933e6f4a387f719a1c Reviewed-on: https://go-review.googlesource.com/c/tools/+/504818 Run-TryBot: Alan Donovan <[email protected]> gopls-CI: kokoro <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 85554d6 commit 0ca9d30

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

gopls/internal/lsp/cache/analysis.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
176176
// Filter and sort enabled root analyzers.
177177
// A disabled analyzer may still be run if required by another.
178178
toSrc := make(map[*analysis.Analyzer]*source.Analyzer)
179-
var enabled []*analysis.Analyzer
179+
var enabled []*analysis.Analyzer // enabled subset + transitive requirements
180180
for _, a := range analyzers {
181181
if a.IsEnabled(snapshot.view.Options()) {
182182
toSrc[a.Analyzer] = a
@@ -190,16 +190,16 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
190190

191191
// Register fact types of required analyzers.
192192
enabled = requiredAnalyzers(enabled)
193-
var useFacts []*analysis.Analyzer
193+
var facty []*analysis.Analyzer // facty subset of enabled + transitive requirements
194194
for _, a := range enabled {
195195
if len(a.FactTypes) > 0 {
196-
useFacts = append(useFacts, a)
196+
facty = append(facty, a)
197197
for _, f := range a.FactTypes {
198198
gob.Register(f) // <2us
199199
}
200200
}
201201
}
202-
useFacts = requiredAnalyzers(useFacts)
202+
facty = requiredAnalyzers(facty)
203203

204204
// File set for this batch (entire graph) of analysis.
205205
fset := token.NewFileSet()
@@ -208,7 +208,9 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
208208
// build the DAG of packages we're going to analyze.
209209
//
210210
// Root nodes will run the enabled set of analyzers,
211-
// whereas dependencies will run only the useFacts set.
211+
// whereas dependencies will run only the facty set.
212+
// Because (by construction) enabled is a superset of facty,
213+
// we can analyze each node with exactly one set of analyzers.
212214
nodes := make(map[PackageID]*analysisNode)
213215
var leaves []*analysisNode // nodes with no unfinished successors
214216
var makeNode func(from *analysisNode, id PackageID) (*analysisNode, error)
@@ -225,7 +227,7 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
225227
an = &analysisNode{
226228
fset: fset,
227229
m: m,
228-
analyzers: useFacts, // all nodes run at least the facty analyzers
230+
analyzers: facty, // all nodes run at least the facty analyzers
229231
allDeps: make(map[PackagePath]*analysisNode),
230232
exportDeps: make(map[PackagePath]*analysisNode),
231233
}
@@ -338,6 +340,23 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
338340
var results []*source.Diagnostic
339341
for _, root := range roots {
340342
for _, a := range enabled {
343+
// Skip analyzers that were added only to
344+
// fulfil requirements of the original set.
345+
srcAnalyzer, ok := toSrc[a]
346+
if !ok {
347+
// Although this 'skip' operation is logically sound,
348+
// it is nonetheless surprising that its absence should
349+
// cause #60909 since none of the analyzers added for
350+
// requirements (e.g. ctrlflow, inspect, buildssa)
351+
// is capable of reporting diagnostics.
352+
if summary := root.summary.Actions[a.Name]; summary != nil {
353+
if n := len(summary.Diagnostics); n > 0 {
354+
bug.Reportf("Internal error: got %d unexpected diagnostics from analyzer %s. This analyzer was added only to fulfil the requirements of the requested set of analyzers, and it is not expected that such analyzers report diagnostics. Please report this in issue #60909.", n, a)
355+
}
356+
}
357+
continue
358+
}
359+
341360
// Inv: root.summary is the successful result of run (via runCached).
342361
summary, ok := root.summary.Actions[a.Name]
343362
if summary == nil {
@@ -348,7 +367,7 @@ func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit,
348367
continue // action failed
349368
}
350369
for _, gobDiag := range summary.Diagnostics {
351-
results = append(results, toSourceDiagnostic(toSrc[a], &gobDiag))
370+
results = append(results, toSourceDiagnostic(srcAnalyzer, &gobDiag))
352371
}
353372
}
354373
}

0 commit comments

Comments
 (0)