P1: `DocumentDiagnosticAnalyzer` repeats typecheck/diagnostics work on every crawler pass (no version-stamp cache)
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 131
Description
## Problem
`FSharpDocumentDiagnosticAnalyzer.GetDiagnostics` (in `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs`) recomputes syntax/semantic diagnostics (parse, typecheck, `UnusedParentheses`) on every invocation from the Roslyn solution crawler, even when the underlying document text and project state have not changed since the last computation.
This causes redundant CPU work (parsing, typechecking, and diagnostic conversion) to repeat unnecessarily during idle background analysis passes, contributing to overall background CPU churn in the F# editor experience.
## Impact
Identified as part of a broader background-activity minimization effort (see prior P1 fix for `Compilation.Emit` metadata-only re-emission in `FSharpProjectOptionsManager.fs`). CPU profiling of `devenv.exe` shows a significant share of samples spent in typecheck (`FSharp.Compiler.CheckDeclarations`) and `UnusedOpens` computation paths reachable from this analyzer, some of which are redundant re-computations for documents whose content/version has not changed between crawler passes.
## Proposed Fix
Add a version-stamp-aware cache keyed by `(DocumentId, DiagnosticsType)`, storing the last computed `(textVersion, projectVersion, diagnostics)` tuple. On each call, compare current `document.GetTextVersionAsync()` (and, for semantic diagnostics, `document.Project.GetDependentVersionAsync()`) against the cached versions; if unchanged, return the cached `ImmutableArray` instead of recomputing.
This mirrors the versioned-cache pattern already used for referenced-project compilation emission in `FSharpProjectOptionsManager.fs` (`emitCache: ConcurrentDictionary>`).
## Repro / Validation
1. Open a large F# solution in Visual Studio.
2. Collect a CPU trace (Instrumentation/Sampling) of `devenv.exe` while idle with a document open.
3. Observe repeated `FSharp.Compiler.CheckDeclarations` / `FSharp.Compiler.EditorServices.UnusedOpens` invocations from `FSharpDocumentDiagnosticAnalyzer.GetDiagnostics` for a document whose version has not changed between crawler passes.
Contributor guide
Research direction
Start with GetDiagnostics in vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs, then compare the versioned cache pattern in FSharpProjectOptionsManager.fs. Trace document and dependent-project version retrieval, and validate with an idle devenv.exe CPU trace. Done means unchanged versions reuse diagnostics while changed document or project versions recompute them.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fsharp
- Domain
- developer-experience, devtools, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100