From 96841e549263a6e80c8161009cb61bbebec761d8 Mon Sep 17 00:00:00 2001 From: Adam Tao Date: Sat, 15 Apr 2023 17:14:21 +0800 Subject: [PATCH] fix: Fix crash if there is no newline at the end of the last line The `Range` may extend the actual range of the text according to the doc of LSP: > ... the end position is exclusive. If you want to specify a range > that contains a line including the line ending character(s) then use > an end position denoting the start of the next line. If there is no newline at the end of the last line (which is common for files created by Vistual Studio) and client set the end of Range to the start of the next line of the last line, then csharp-ls will crash because argument is out of the range. On the other hand, we SHOULDN'T trust the value client sent to us. Signed-off-by: Adam Tao --- src/CSharpLanguageServer/RoslynHelpers.fs | 17 +++++++++++------ src/CSharpLanguageServer/Server.fs | 12 ++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/CSharpLanguageServer/RoslynHelpers.fs b/src/CSharpLanguageServer/RoslynHelpers.fs index 57b6bea4..c25a3bc8 100644 --- a/src/CSharpLanguageServer/RoslynHelpers.fs +++ b/src/CSharpLanguageServer/RoslynHelpers.fs @@ -49,13 +49,18 @@ let roslynTagToLspCompletion tag = let lspPositionForRoslynLinePosition (pos: LinePosition): Types.Position = { Line = pos.Line ; Character = pos.Character } -let roslynLinePositionForLspPosition (pos: Types.Position) = - LinePosition(pos.Line, pos.Character) +let roslynLinePositionForLspPosition (lines: TextLineCollection) (pos: Types.Position) = + if pos.Line < 0 then + LinePosition(0, 0) + else if pos.Line >= lines.Count then + LinePosition(lines.Count - 1, lines[lines.Count - 1].EndIncludingLineBreak - lines[lines.Count - 1].Start) + else + LinePosition(pos.Line, pos.Character) -let roslynLinePositionSpanForLspRange (range: Types.Range) = +let roslynLinePositionSpanForLspRange (lines: TextLineCollection) (range: Types.Range) = LinePositionSpan( - roslynLinePositionForLspPosition range.Start, - roslynLinePositionForLspPosition range.End) + roslynLinePositionForLspPosition lines range.Start, + roslynLinePositionForLspPosition lines range.End) let lspRangeForRoslynLinePosSpan (pos: LinePositionSpan): Types.Range = { Start = lspPositionForRoslynLinePosition pos.Start @@ -82,7 +87,7 @@ let applyLspContentChangesOnRoslynSourceText match change.Range with | Some changeRange -> let changeTextSpan = - changeRange |> roslynLinePositionSpanForLspRange + changeRange |> roslynLinePositionSpanForLspRange sourceText.Lines |> sourceText.Lines.GetTextSpan TextChange(changeTextSpan, change.Text) |> sourceText.WithChanges diff --git a/src/CSharpLanguageServer/Server.fs b/src/CSharpLanguageServer/Server.fs index 1f466b1d..bd30b7bc 100644 --- a/src/CSharpLanguageServer/Server.fs +++ b/src/CSharpLanguageServer/Server.fs @@ -476,7 +476,7 @@ let setupServerHandlers settings (lspClient: LspClient) = let textSpan = actionParams.Range - |> roslynLinePositionSpanForLspRange + |> roslynLinePositionSpanForLspRange docText.Lines |> docText.Lines.GetTextSpan let! roslynCodeActions = @@ -548,7 +548,7 @@ let setupServerHandlers settings (lspClient: LspClient) = let textSpan = resolutionData.Value.Range - |> roslynLinePositionSpanForLspRange + |> roslynLinePositionSpanForLspRange docText.Lines |> docText.Lines.GetTextSpan let! roslynCodeActions = @@ -871,8 +871,8 @@ let setupServerHandlers settings (lspClient: LspClient) = |> Option.defaultValue false let linePositionSpan = LinePositionSpan( - roslynLinePositionForLspPosition prepareRename.Position, - roslynLinePositionForLspPosition prepareRename.Position) + roslynLinePositionForLspPosition docText.Lines prepareRename.Position, + roslynLinePositionForLspPosition docText.Lines prepareRename.Position) let textSpan = docText.Lines.GetTextSpan(linePositionSpan) @@ -1120,7 +1120,7 @@ let setupServerHandlers settings (lspClient: LspClient) = match range with | Some r -> r - |> roslynLinePositionSpanForLspRange + |> roslynLinePositionSpanForLspRange sourceText.Lines |> sourceText.Lines.GetTextSpan | None -> TextSpan(0, sourceText.Length) @@ -1269,7 +1269,7 @@ let setupServerHandlers settings (lspClient: LspClient) = let! sourceText = doc.GetTextAsync() |> Async.AwaitTask let textSpan = inlayHintParams.Range - |> roslynLinePositionSpanForLspRange + |> roslynLinePositionSpanForLspRange sourceText.Lines |> sourceText.Lines.GetTextSpan let inlayHints =