From 150625c179c9546f4785e6af780a4417677bcfac 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..afadee502 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 + findLineStart text range.Start.Line 1 0 + |> Option.bind (fun startLineOffset -> + findLineStart text range.End.Line range.Start.Line startLineOffset + |> Option.map (fun endLineOffset -> + let startIndex = startLineOffset + range.Start.Column + let endIndex = endLineOffset + range.End.Column + text.Substring(startIndex, endIndex - startIndex) + ) + ) let getLeadingSpaces (range:Range) (text:string) = let range = Range.mkRange String.Empty (Position.mkPos range.StartLine 0) range.End