From 74828992487753adb89f743b9abc56f684c411c4 Mon Sep 17 00:00:00 2001 From: Howard van Rooijen Date: Fri, 23 Jan 2026 17:26:43 +0000 Subject: [PATCH] Summary of Changes 1. Removed unsafe .Value call (line 455) - The original code accessed wf.Value before the match to check if wf was Some. This caused crashes when the workspace folder wasn't found. 2. Moved wfPathToUri into the Some wf, Some doc branch (line 510) - The calculation now only happens when we're certain wf is Some. 3. Added .cshtml extension check (line 460) - The Some wf, None branch now only processes files as Razor/cshtml if they actually have a .cshtml extension, instead of treating ALL unfound documents as cshtml files. 4. Safe handling of wf.Solution (lines 461-466) - Instead of the unsafe wf.Solution.Value, the code now pattern matches on wf.Solution to safely handle the case where the solution hasn't loaded yet. 5. Added retry logic for unfound documents (lines 464-465, 504-505) - When a document isn't found (due to timing or solution not being fully loaded), the code now posts PushDiagnosticsDocumentBacklogUpdate and PushDiagnosticsProcessPendingDocuments to rebuild the backlog and retry later. 6. Added continuation for unfound .cshtml documents (line 495) - When a .cshtml document isn't found as a Razor document, processing continues with the next document. All 67 tests pass, including the two previously failing tests: - testPushDiagnosticsWork - testDiagnoseCommandWorks --- src/CSharpLanguageServer/State/ServerState.fs | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/src/CSharpLanguageServer/State/ServerState.fs b/src/CSharpLanguageServer/State/ServerState.fs index b5835cb2..1bd35566 100644 --- a/src/CSharpLanguageServer/State/ServerState.fs +++ b/src/CSharpLanguageServer/State/ServerState.fs @@ -452,46 +452,63 @@ let processServerEvent (logger: ILogger) state postSelf msg : Async PushDiagnosticsDocumentBacklog = newBacklog } let wf, docForUri = docUri |> workspaceDocument state.Workspace AnyDocument - let wfPathToUri = workspaceFolderPathToUri wf.Value match wf, docForUri with | Some wf, None -> - let cshtmlPath = workspaceFolderUriToPath wf docUri |> _.Value - - match! solutionGetRazorDocumentForPath wf.Solution.Value cshtmlPath with - | Some(_, compilation, cshtmlTree) -> - let semanticModelMaybe = compilation.GetSemanticModel cshtmlTree |> Option.ofObj - - match semanticModelMaybe with + // Only try to process as a .cshtml file if it actually is one + match workspaceFolderUriToPath wf docUri with + | Some cshtmlPath when cshtmlPath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase) -> + match wf.Solution with | None -> - Error(Exception "could not GetSemanticModelAsync") - |> PushDiagnosticsDocumentDiagnosticsResolution - |> postSelf - - | Some semanticModel -> - let diagnostics = - semanticModel.GetDiagnostics() - |> Seq.map (Diagnostic.fromRoslynDiagnostic (workspaceFolderPathToUri wf)) - |> Seq.filter (fun (_, uri) -> uri = docUri) - |> Seq.map fst - |> Array.ofSeq - - Ok(docUri, None, diagnostics) - |> PushDiagnosticsDocumentDiagnosticsResolution - |> postSelf - - | None -> - // could not find document for this enqueued uri + // Solution not loaded yet, rebuild backlog and try again later + postSelf PushDiagnosticsDocumentBacklogUpdate + postSelf PushDiagnosticsProcessPendingDocuments + | Some solution -> + match! solutionGetRazorDocumentForPath solution cshtmlPath with + | Some(_, compilation, cshtmlTree) -> + let semanticModelMaybe = compilation.GetSemanticModel cshtmlTree |> Option.ofObj + + match semanticModelMaybe with + | None -> + Error(Exception "could not GetSemanticModelAsync") + |> PushDiagnosticsDocumentDiagnosticsResolution + |> postSelf + + | Some semanticModel -> + let diagnostics = + semanticModel.GetDiagnostics() + |> Seq.map (Diagnostic.fromRoslynDiagnostic (workspaceFolderPathToUri wf)) + |> Seq.filter (fun (_, uri) -> uri = docUri) + |> Seq.map fst + |> Array.ofSeq + + Ok(docUri, None, diagnostics) + |> PushDiagnosticsDocumentDiagnosticsResolution + |> postSelf + + | None -> + logger.LogDebug( + "PushDiagnosticsProcessPendingDocuments: could not find razor document for \"{cshtmlPath}\"", + cshtmlPath + ) + // Continue with next document + postSelf PushDiagnosticsProcessPendingDocuments + + | _ -> + // Not a .cshtml file or couldn't convert URI + // This can happen if solution hasn't loaded yet - rebuild backlog for retry logger.LogDebug( - "PushDiagnosticsProcessPendingDocuments: could not find document w/ uri \"{docUri}\"", + "PushDiagnosticsProcessPendingDocuments: could not find document w/ uri \"{docUri}\", will retry", string docUri ) - - () + postSelf PushDiagnosticsDocumentBacklogUpdate + postSelf PushDiagnosticsProcessPendingDocuments return newState | Some wf, Some doc -> + let wfPathToUri = workspaceFolderPathToUri wf + let resolveDocumentDiagnostics () : Task = task { let! semanticModelMaybe = doc.GetSemanticModelAsync()