@@ -19,6 +19,7 @@ import (
19
19
"go/token"
20
20
"go/types"
21
21
"log"
22
+ "maps"
22
23
urlpkg "net/url"
23
24
"path/filepath"
24
25
"reflect"
@@ -45,6 +46,7 @@ import (
45
46
"golang.org/x/tools/gopls/internal/util/bug"
46
47
"golang.org/x/tools/gopls/internal/util/frob"
47
48
"golang.org/x/tools/gopls/internal/util/moremaps"
49
+ "golang.org/x/tools/gopls/internal/util/persistent"
48
50
"golang.org/x/tools/internal/analysisinternal"
49
51
"golang.org/x/tools/internal/event"
50
52
"golang.org/x/tools/internal/facts"
@@ -175,7 +177,7 @@ const AnalysisProgressTitle = "Analyzing Dependencies"
175
177
// The analyzers list must be duplicate free; order does not matter.
176
178
//
177
179
// Notifications of progress may be sent to the optional reporter.
178
- func (s * Snapshot ) Analyze (ctx context.Context , pkgs map [PackageID ]* metadata.Package , analyzers [] * settings. Analyzer , reporter * progress.Tracker ) ([]* Diagnostic , error ) {
180
+ func (s * Snapshot ) Analyze (ctx context.Context , pkgs map [PackageID ]* metadata.Package , reporter * progress.Tracker ) ([]* Diagnostic , error ) {
179
181
start := time .Now () // for progress reporting
180
182
181
183
var tagStr string // sorted comma-separated list of PackageIDs
@@ -192,6 +194,7 @@ func (s *Snapshot) Analyze(ctx context.Context, pkgs map[PackageID]*metadata.Pac
192
194
193
195
// Filter and sort enabled root analyzers.
194
196
// A disabled analyzer may still be run if required by another.
197
+ analyzers := analyzers (s .Options ().Staticcheck )
195
198
toSrc := make (map [* analysis.Analyzer ]* settings.Analyzer )
196
199
var enabledAnalyzers []* analysis.Analyzer // enabled subset + transitive requirements
197
200
for _ , a := range analyzers {
@@ -322,20 +325,14 @@ func (s *Snapshot) Analyze(ctx context.Context, pkgs map[PackageID]*metadata.Pac
322
325
roots = append (roots , root )
323
326
}
324
327
325
- // Now that we have read all files,
326
- // we no longer need the snapshot.
327
- // (but options are needed for progress reporting)
328
- options := s .Options ()
329
- s = nil
330
-
331
328
// Progress reporting. If supported, gopls reports progress on analysis
332
329
// passes that are taking a long time.
333
330
maybeReport := func (completed int64 ) {}
334
331
335
332
// Enable progress reporting if enabled by the user
336
333
// and we have a capable reporter.
337
- if reporter != nil && reporter .SupportsWorkDoneProgress () && options .AnalysisProgressReporting {
338
- var reportAfter = options .ReportAnalysisProgressAfter // tests may set this to 0
334
+ if reporter != nil && reporter .SupportsWorkDoneProgress () && s . Options () .AnalysisProgressReporting {
335
+ var reportAfter = s . Options () .ReportAnalysisProgressAfter // tests may set this to 0
339
336
const reportEvery = 1 * time .Second
340
337
341
338
ctx , cancel := context .WithCancel (ctx )
@@ -396,10 +393,34 @@ func (s *Snapshot) Analyze(ctx context.Context, pkgs map[PackageID]*metadata.Pac
396
393
limiter <- unit {}
397
394
defer func () { <- limiter }()
398
395
399
- summary , err := an .runCached (ctx )
396
+ // Check to see if we already have a valid cache key. If not, compute it.
397
+ //
398
+ // The snapshot field that memoizes keys depends on whether this key is
399
+ // for the analysis result including all enabled analyzer, or just facty analyzers.
400
+ var keys * persistent.Map [PackageID , file.Hash ]
401
+ if _ , root := pkgs [an .mp .ID ]; root {
402
+ keys = s .fullAnalysisKeys
403
+ } else {
404
+ keys = s .factyAnalysisKeys
405
+ }
406
+
407
+ // As keys is referenced by a snapshot field, it's guarded by s.mu.
408
+ s .mu .Lock ()
409
+ key , keyFound := keys .Get (an .mp .ID )
410
+ s .mu .Unlock ()
411
+
412
+ if ! keyFound {
413
+ key = an .cacheKey ()
414
+ s .mu .Lock ()
415
+ keys .Set (an .mp .ID , key , nil )
416
+ s .mu .Unlock ()
417
+ }
418
+
419
+ summary , err := an .runCached (ctx , key )
400
420
if err != nil {
401
421
return err // cancelled, or failed to produce a package
402
422
}
423
+
403
424
maybeReport (completed .Add (1 ))
404
425
an .summary = summary
405
426
@@ -488,6 +509,14 @@ func (s *Snapshot) Analyze(ctx context.Context, pkgs map[PackageID]*metadata.Pac
488
509
return results , nil
489
510
}
490
511
512
+ func analyzers (staticcheck bool ) []* settings.Analyzer {
513
+ analyzers := slices .Collect (maps .Values (settings .DefaultAnalyzers ))
514
+ if staticcheck {
515
+ analyzers = slices .AppendSeq (analyzers , maps .Values (settings .StaticcheckAnalyzers ))
516
+ }
517
+ return analyzers
518
+ }
519
+
491
520
func (an * analysisNode ) decrefPreds () {
492
521
if an .unfinishedPreds .Add (- 1 ) == 0 {
493
522
an .summary .Actions = nil
@@ -711,21 +740,14 @@ var (
711
740
// actions failed. It usually fails only if the package was unknown,
712
741
// a file was missing, or the operation was cancelled.
713
742
//
714
- // Postcondition: runCached must not continue to use the snapshot
715
- // (in background goroutines) after it has returned; see memoize.RefCounted.
716
- func (an * analysisNode ) runCached (ctx context.Context ) (* analyzeSummary , error ) {
717
- // At this point we have the action results (serialized
718
- // packages and facts) of our immediate dependencies,
719
- // and the metadata and content of this package.
720
- //
721
- // We now compute a hash for all our inputs, and consult a
722
- // global cache of promised results. If nothing material
723
- // has changed, we'll make a hit in the shared cache.
743
+ // The provided key is the cache key for this package.
744
+ func (an * analysisNode ) runCached (ctx context.Context , key file.Hash ) (* analyzeSummary , error ) {
745
+ // At this point we have the action results (serialized packages and facts)
746
+ // of our immediate dependencies, and the metadata and content of this
747
+ // package.
724
748
//
725
- // The hash of our inputs is based on the serialized export
726
- // data and facts so that immaterial changes can be pruned
727
- // without decoding.
728
- key := an .cacheKey ()
749
+ // We now consult a global cache of promised results. If nothing material has
750
+ // changed, we'll make a hit in the shared cache.
729
751
730
752
// Access the cache.
731
753
var summary * analyzeSummary
0 commit comments