@@ -10,14 +10,16 @@ import (
10
10
"go/ast"
11
11
"go/types"
12
12
"reflect"
13
+ "runtime/debug"
13
14
"sync"
14
15
15
16
"golang.org/x/sync/errgroup"
16
17
"golang.org/x/tools/go/analysis"
18
+ "golang.org/x/tools/gopls/internal/lsp/source"
17
19
"golang.org/x/tools/internal/analysisinternal"
20
+ "golang.org/x/tools/internal/bug"
18
21
"golang.org/x/tools/internal/event"
19
22
"golang.org/x/tools/internal/event/tag"
20
- "golang.org/x/tools/gopls/internal/lsp/source"
21
23
"golang.org/x/tools/internal/memoize"
22
24
"golang.org/x/tools/internal/span"
23
25
)
@@ -60,7 +62,7 @@ func (s *snapshot) Analyze(ctx context.Context, id string, analyzers []*source.A
60
62
}
61
63
62
64
type actionKey struct {
63
- pkg packageKey
65
+ pkgid PackageID
64
66
analyzer * analysis.Analyzer
65
67
}
66
68
@@ -102,11 +104,7 @@ type packageFactKey struct {
102
104
}
103
105
104
106
func (s * snapshot ) actionHandle (ctx context.Context , id PackageID , a * analysis.Analyzer ) (* actionHandle , error ) {
105
- const mode = source .ParseFull
106
- key := actionKey {
107
- pkg : packageKey {id : id , mode : mode },
108
- analyzer : a ,
109
- }
107
+ key := actionKey {id , a }
110
108
111
109
s .mu .Lock ()
112
110
entry , hit := s .actions .Get (key )
@@ -126,7 +124,7 @@ func (s *snapshot) actionHandle(ctx context.Context, id PackageID, a *analysis.A
126
124
// use of concurrency would lead to an exponential amount of duplicated
127
125
// work. We should instead use an atomically updated future cache
128
126
// and a parallel graph traversal.
129
- ph , err := s .buildPackageHandle (ctx , id , mode )
127
+ ph , err := s .buildPackageHandle (ctx , id , source . ParseFull )
130
128
if err != nil {
131
129
return nil , err
132
130
}
@@ -138,6 +136,8 @@ func (s *snapshot) actionHandle(ctx context.Context, id PackageID, a *analysis.A
138
136
// Add a dependency on each required analyzer.
139
137
var deps []* actionHandle
140
138
for _ , req := range a .Requires {
139
+ // TODO(adonovan): opt: there's no need to repeat the package-handle
140
+ // portion of the recursion here, since we have the pkg already.
141
141
reqActionHandle , err := s .actionHandle (ctx , id , req )
142
142
if err != nil {
143
143
return nil , err
@@ -227,7 +227,8 @@ func actionImpl(ctx context.Context, snapshot *snapshot, deps []*actionHandle, a
227
227
// in-memory outputs of prerequisite analyzers
228
228
// become inputs to this analysis pass.
229
229
inputs [dep .analyzer ] = data .result
230
- } else if dep .analyzer == analyzer { // (always true)
230
+
231
+ } else if dep .analyzer == analyzer {
231
232
// Same analysis, different package (vertical edge):
232
233
// serialized facts produced by prerequisite analysis
233
234
// become available to this analysis pass.
@@ -246,12 +247,34 @@ func actionImpl(ctx context.Context, snapshot *snapshot, deps []*actionHandle, a
246
247
// to prevent side channels.
247
248
packageFacts [key ] = fact
248
249
}
250
+
251
+ } else {
252
+ // Edge is neither vertical nor horizontal.
253
+ // This should never happen, yet an assertion here was
254
+ // observed to fail due to an edge (bools, p) -> (inspector, p')
255
+ // where p and p' are distinct packages with the
256
+ // same ID ("command-line-arguments:file=.../main.go").
257
+ //
258
+ // It is not yet clear whether the command-line-arguments
259
+ // package is significant, but it is clear that package
260
+ // loading (the mapping from ID to *pkg) is inconsistent
261
+ // within a single graph.
262
+
263
+ // Use the bug package so that we detect whether our tests
264
+ // discover this problem in regular packages.
265
+ // For command-line-arguments we quietly abort the analysis
266
+ // for now since we already know there is a bug.
267
+ errorf := bug .Errorf // report this discovery
268
+ if source .IsCommandLineArguments (pkg .ID ()) {
269
+ errorf = fmt .Errorf // suppress reporting
270
+ }
271
+ return errorf ("internal error: unexpected analysis dependency %s@%s -> %s" , analyzer .Name , pkg .ID (), dep )
249
272
}
250
273
return nil
251
274
})
252
275
}
253
276
if err := g .Wait (); err != nil {
254
- return nil , err // e.g. cancelled
277
+ return nil , err // cancelled, or dependency failed
255
278
}
256
279
257
280
// Now run the (pkg, analyzer) analysis.
@@ -338,13 +361,19 @@ func actionImpl(ctx context.Context, snapshot *snapshot, deps []*actionHandle, a
338
361
var result interface {}
339
362
var err error
340
363
func () {
341
- defer func () {
342
- if r := recover (); r != nil {
343
- // TODO(adonovan): use bug.Errorf here so that we
344
- // detect crashes covered by our test suite.
345
- err = fmt .Errorf ("analysis %s for package %s panicked: %v" , analyzer .Name , pkg .PkgPath (), r )
346
- }
347
- }()
364
+ // Set this flag temporarily when debugging crashes.
365
+ // See https://github.com/golang/go/issues/54762.
366
+ const norecover = false
367
+ if norecover {
368
+ debug .SetTraceback ("all" ) // show all goroutines
369
+ } else {
370
+ defer func () {
371
+ if r := recover (); r != nil {
372
+ // Use bug.Errorf so that we detect panics during testing.
373
+ err = bug .Errorf ("analysis %s for package %s panicked: %v" , analyzer .Name , pkg .PkgPath (), r )
374
+ }
375
+ }()
376
+ }
348
377
result , err = pass .Analyzer .Run (pass )
349
378
}()
350
379
if err != nil {
@@ -414,13 +443,14 @@ func factType(fact analysis.Fact) reflect.Type {
414
443
415
444
func (s * snapshot ) DiagnosePackage (ctx context.Context , spkg source.Package ) (map [span.URI ][]* source.Diagnostic , error ) {
416
445
pkg := spkg .(* pkg )
417
- // Apply type error analyzers. They augment type error diagnostics with their own fixes.
418
- var analyzers []* source.Analyzer
419
- for _ , a := range s .View ().Options ().TypeErrorAnalyzers {
420
- analyzers = append (analyzers , a )
421
- }
422
446
var errorAnalyzerDiag []* source.Diagnostic
423
447
if pkg .HasTypeErrors () {
448
+ // Apply type error analyzers.
449
+ // They augment type error diagnostics with their own fixes.
450
+ var analyzers []* source.Analyzer
451
+ for _ , a := range s .View ().Options ().TypeErrorAnalyzers {
452
+ analyzers = append (analyzers , a )
453
+ }
424
454
var err error
425
455
errorAnalyzerDiag , err = s .Analyze (ctx , pkg .ID (), analyzers )
426
456
if err != nil {
0 commit comments