From c00c2ff6166ec40f11b925bf5101169c2de494db Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Tue, 11 Aug 2026 09:05:22 +0100 Subject: [PATCH] perf(Core): tweak tryFindTextOfRange tryFindTextOfRange appears to be a hotspot for performance in the current version (the calls to IndexOf show up at the top of profiles of the benchmark app) So, some tweaks to the implementation: 1) Only look for the end position if we found the start If requires both start and end to function, so looking for the end when it couldn't find the start is spurious 2) Start looking for the end line starting at the offset of the start line, to reduce duplicate work (findLineStart should also then exit immediately if the start and end are on the same line) Benchmark result before: | Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | |--------------- |---------:|---------:|---------:|-----------:|----------:|----------:|----------:| | LintParsedFile | 807.4 ms | 16.09 ms | 22.03 ms | 14000.0000 | 5000.0000 | 1000.0000 | 229.87 MB | After: | Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | |--------------- |---------:|--------:|--------:|-----------:|----------:|----------:|----------:| | LintParsedFile | 476.1 ms | 6.95 ms | 5.81 ms | 14000.0000 | 5000.0000 | 1000.0000 | 229.87 MB | --- src/FSharpLint.Core/Framework/Utilities.fs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/FSharpLint.Core/Framework/Utilities.fs b/src/FSharpLint.Core/Framework/Utilities.fs index 36d46a6c4..a6c8c8c14 100644 --- a/src/FSharpLint.Core/Framework/Utilities.fs +++ b/src/FSharpLint.Core/Framework/Utilities.fs @@ -104,13 +104,15 @@ module ExpressionUtilities = /// Tries to find the source code within a given range. let tryFindTextOfRange (range:Range) (text:string) = - let maybeStartIndex = findPos range.Start text - let maybeEndIndex = findPos range.End text - - match (maybeStartIndex, maybeEndIndex) with - | Some(startIndex), Some(endIndex) -> - text.Substring(startIndex, endIndex - startIndex) |> Some - | _ -> None + match findLineStart text range.Start.Line 1 0 with + | Some startLineOffset -> + match findLineStart text range.End.Line range.Start.Line startLineOffset with + | Some endLineOffset -> + let startIndex = startLineOffset + range.Start.Column + let endIndex = endLineOffset + range.End.Column + text.Substring(startIndex, endIndex - startIndex) |> Some + | None -> None + | None -> None let getLeadingSpaces (range:Range) (text:string) = let range = Range.mkRange String.Empty (Position.mkPos range.StartLine 0) range.End