Skip to content

Commit c4a8ff2

Browse files
dsymeKevinRansom
authored andcommitted
fix span bug (#3181)
1 parent 684e628 commit c4a8ff2

File tree

10 files changed

+61
-41
lines changed

10 files changed

+61
-41
lines changed

vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ type internal FSharpColorizationService
4545
let colorizationData = checkResults.GetSemanticClassification (Some targetRange) |> Array.distinctBy fst
4646

4747
for (range, classificationType) in colorizationData do
48-
let span = Tokenizer.fixupSpan(sourceText, RoslynHelpers.FSharpRangeToTextSpan(sourceText, range))
49-
result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType)))
48+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with
49+
| None -> ()
50+
| Some span ->
51+
let span = Tokenizer.fixupSpan(sourceText, span)
52+
result.Add(ClassifiedSpan(span, FSharpClassificationTypes.getClassificationTypeName(classificationType)))
5053
}
5154
|> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
5255

vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ module internal RoslynHelpers =
2121

2222
let FSharpRangeToTextSpan(sourceText: SourceText, range: range) =
2323
// Roslyn TextLineCollection is zero-based, F# range lines are one-based
24-
let startPosition = sourceText.Lines.[range.StartLine - 1].Start + range.StartColumn
25-
let endPosition = sourceText.Lines.[range.EndLine - 1].Start + range.EndColumn
24+
let startPosition = sourceText.Lines.[max 0 (range.StartLine - 1)].Start + range.StartColumn
25+
let endPosition = sourceText.Lines.[min (range.EndLine - 1) (sourceText.Lines.Count - 1)].Start + range.EndColumn
2626
TextSpan(startPosition, endPosition - startPosition)
2727

2828
let TryFSharpRangeToTextSpan(sourceText: SourceText, range: range) : TextSpan option =

vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ type internal FSharpBreakpointResolutionService
5252
let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document)
5353
let! sourceText = document.GetTextAsync(cancellationToken)
5454
let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, options)
55-
return BreakpointResolutionResult.CreateSpanResult(document, RoslynHelpers.FSharpRangeToTextSpan(sourceText, range))
55+
let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range)
56+
return BreakpointResolutionResult.CreateSpanResult(document, span)
5657
}
5758
|> Async.map Option.toObj
5859
|> RoslynHelpers.StartAsyncAsTask cancellationToken

vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ type internal FSharpDocumentHighlightsService [<ImportingConstructor>] (checkerP
6464
let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync
6565
return
6666
[| for symbolUse in symbolUses do
67-
yield { IsDefinition = symbolUse.IsFromDefinition
68-
TextSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) } |]
67+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) with
68+
| None -> ()
69+
| Some span ->
70+
yield { IsDefinition = symbolUse.IsFromDefinition
71+
TextSpan = span } |]
6972
|> fixInvalidSymbolSpans sourceText symbol.Ident.idText
7073
}
7174

vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ type internal FSharpBraceMatchingService
1919
static member GetBraceMatchingResult(checker: FSharpChecker, sourceText, fileName, options, position: int) =
2020
async {
2121
let! matchedBraces = checker.MatchBraces(fileName, sourceText.ToString(), options, userOpName = userOpName)
22-
let isPositionInRange range = RoslynHelpers.FSharpRangeToTextSpan(sourceText, range).Contains(position)
22+
let isPositionInRange range =
23+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with
24+
| None -> false
25+
| Some range -> range.Contains(position)
2326
return matchedBraces |> Array.tryFind(fun (left, right) -> isPositionInRange left || isPositionInRange right)
2427
}
2528

@@ -29,10 +32,9 @@ type internal FSharpBraceMatchingService
2932
let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document)
3033
let! sourceText = document.GetTextAsync(cancellationToken)
3134
let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, options, position)
32-
return
33-
BraceMatchingResult(
34-
RoslynHelpers.FSharpRangeToTextSpan(sourceText, left),
35-
RoslynHelpers.FSharpRangeToTextSpan(sourceText, right))
35+
let! leftSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, left)
36+
let! rightSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, right)
37+
return BraceMatchingResult(leftSpan, rightSpan)
3638
}
3739
|> Async.map Option.toNullable
3840
|> RoslynHelpers.StartAsyncAsTask cancellationToken

vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ type internal InlineRenameInfo
7575
checker: FSharpChecker,
7676
projectInfoManager: ProjectInfoManager,
7777
document: Document,
78-
sourceText: SourceText,
78+
triggerSpan: TextSpan,
7979
lexerSymbol: LexerSymbol,
8080
symbolUse: FSharpSymbolUse,
8181
declLoc: SymbolDeclarationLocation,
@@ -89,10 +89,6 @@ type internal InlineRenameInfo
8989
| true, text -> text
9090
| _ -> document.GetTextAsync(cancellationToken).Result
9191

92-
let triggerSpan =
93-
let span = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate)
94-
Tokenizer.fixupSpan(sourceText, span)
95-
9692
let symbolUses =
9793
SymbolHelpers.getSymbolUsesInSolution(symbolUse.Symbol, declLoc, checkFileResults, projectInfoManager, checker, document.Project.Solution, userOpName)
9894
|> Async.cache
@@ -126,9 +122,12 @@ type internal InlineRenameInfo
126122
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
127123
let locations =
128124
symbolUses
129-
|> Array.map (fun symbolUse ->
130-
let textSpan = Tokenizer.fixupSpan(sourceText, RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate))
131-
InlineRenameLocation(document, textSpan))
125+
|> Array.choose (fun symbolUse ->
126+
RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate)
127+
|> Option.map (fun span ->
128+
let textSpan = Tokenizer.fixupSpan(sourceText, span)
129+
InlineRenameLocation(document, textSpan)))
130+
132131
return { Document = document; Locations = locations }
133132
})
134133
|> Async.Parallel
@@ -158,7 +157,11 @@ type internal InlineRenameService
158157
let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, allowStaleResults = true, userOpName = userOpName)
159158
let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.Text.ToString(), symbol.FullIsland, userOpName=userOpName)
160159
let! declLoc = symbolUse.GetDeclarationLocation(document)
161-
return InlineRenameInfo(checker, projectInfoManager, document, sourceText, symbol, symbolUse, declLoc, checkFileResults) :> IInlineRenameInfo
160+
161+
let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate)
162+
let triggerSpan = Tokenizer.fixupSpan(sourceText, span)
163+
164+
return InlineRenameInfo(checker, projectInfoManager, document, triggerSpan, symbol, symbolUse, declLoc, checkFileResults) :> IInlineRenameInfo
162165
}
163166

164167
interface IEditorInlineRenameService with

vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,12 @@ module internal SymbolHelpers =
9595
let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask
9696
let mutable sourceText = sourceText
9797
for symbolUse in symbolUses do
98-
let textSpan = Tokenizer.fixupSpan(sourceText, RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate))
99-
sourceText <- sourceText.Replace(textSpan, newText)
100-
solution <- solution.WithDocumentText(documentId, sourceText)
98+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) with
99+
| None -> ()
100+
| Some span ->
101+
let textSpan = Tokenizer.fixupSpan(sourceText, span)
102+
sourceText <- sourceText.Replace(textSpan, newText)
103+
solution <- solution.WithDocumentText(documentId, sourceText)
101104
return solution
102105
} |> RoslynHelpers.StartAsyncAsTask cancellationToken),
103106
originalText

vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: Project
4949
let refDocument = document.Project.Solution.GetDocument refDocumentId
5050
let! cancellationToken = Async.CancellationToken
5151
let! refSourceText = refDocument.GetTextAsync(cancellationToken) |> Async.AwaitTask
52-
let refTextSpan = RoslynHelpers.FSharpRangeToTextSpan (refSourceText, range)
53-
return Some (FSharpNavigableItem (refDocument, refTextSpan))
52+
match RoslynHelpers.TryFSharpRangeToTextSpan (refSourceText, range) with
53+
| None -> return None
54+
| Some refTextSpan -> return Some (FSharpNavigableItem (refDocument, refTextSpan))
5455
else return None
5556
}
5657

@@ -59,7 +60,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: Project
5960
asyncMaybe {
6061
let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject originDocument
6162
let defines = CompilerEnvironment.GetCompilationDefinesForEditing (originDocument.FilePath, projectOptions.OtherOptions |> Seq.toList)
62-
let originTextSpan = RoslynHelpers.FSharpRangeToTextSpan (sourceText, originRange)
63+
let! originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, originRange)
6364
let position = originTextSpan.Start
6465
let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position, originDocument.FilePath, defines, SymbolLookupKind.Greedy, false)
6566

@@ -83,7 +84,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: Project
8384
let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, allowStaleResults=true, sourceText=implSourceText, userOpName = userOpName)
8485
let! symbolUses = checkFileResults.GetUsesOfSymbolInFile symbol |> liftAsync
8586
let! implSymbol = symbolUses |> Array.tryHead
86-
let implTextSpan = RoslynHelpers.FSharpRangeToTextSpan (implSourceText, implSymbol.RangeAlternate)
87+
let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, implSymbol.RangeAlternate)
8788
return FSharpNavigableItem (implDoc, implTextSpan)
8889
else
8990
let! targetDocument = originDocument.Project.Solution.TryGetDocumentFromFSharpRange fsSymbolUse.RangeAlternate
@@ -241,7 +242,7 @@ type internal FSharpGoToDefinitionService
241242
let! targetRange =
242243
gotoDefinition.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText.ToString(), projectOptions, implVersion.GetHashCode())
243244

244-
let implTextSpan = RoslynHelpers.FSharpRangeToTextSpan (implSourceText, targetRange)
245+
let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange)
245246
let navItem = FSharpNavigableItem (implDocument, implTextSpan)
246247
return navItem
247248
else // jump from implementation to the corresponding signature
@@ -250,7 +251,7 @@ type internal FSharpGoToDefinitionService
250251
| FSharpFindDeclResult.DeclFound targetRange ->
251252
let! sigDocument = originDocument.Project.Solution.TryGetDocumentFromPath targetRange.FileName
252253
let! sigSourceText = sigDocument.GetTextAsync () |> liftTaskAsync
253-
let sigTextSpan = RoslynHelpers.FSharpRangeToTextSpan (sigSourceText, targetRange)
254+
let! sigTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sigSourceText, targetRange)
254255
let navItem = FSharpNavigableItem (sigDocument, sigTextSpan)
255256
return navItem
256257
| _ -> return! None
@@ -260,7 +261,7 @@ type internal FSharpGoToDefinitionService
260261
else
261262
let! sigDocument = originDocument.Project.Solution.TryGetDocumentFromPath targetRange.FileName
262263
let! sigSourceText = sigDocument.GetTextAsync () |> liftTaskAsync
263-
let sigTextSpan = RoslynHelpers.FSharpRangeToTextSpan (sigSourceText, targetRange)
264+
let! sigTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sigSourceText, targetRange)
264265
// if the gotodef call originated from a signature and the returned target is a signature, navigate there
265266
if isSignatureFile targetRange.FileName && preferSignature then
266267
let navItem = FSharpNavigableItem (sigDocument, sigTextSpan)
@@ -280,7 +281,7 @@ type internal FSharpGoToDefinitionService
280281
let! targetRange =
281282
gotoDefinition.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText.ToString(), projectOptions, implVersion.GetHashCode())
282283

283-
let implTextSpan = RoslynHelpers.FSharpRangeToTextSpan (implSourceText, targetRange)
284+
let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange)
284285
let navItem = FSharpNavigableItem (implDocument, implTextSpan)
285286
return navItem
286287
| _ -> return! None

vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ type internal FSharpNavigateToSearchService
196196
match parseResults.ParseTree |> Option.map NavigateTo.getNavigableItems with
197197
| Some items ->
198198
[| for item in items do
199-
let sourceSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, item.Range)
200-
let glyph = Utils.navigateToItemKindToGlyph item.Kind
201-
let kind = Utils.navigateToItemKindToRoslynKind item.Kind
202-
let additionalInfo = Utils.containerToString item.Container document.Project
203-
yield NavigableItem(document, sourceSpan, glyph, item.Name, kind, additionalInfo) |]
199+
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, item.Range) with
200+
| None -> ()
201+
| Some sourceSpan ->
202+
let glyph = Utils.navigateToItemKindToGlyph item.Kind
203+
let kind = Utils.navigateToItemKindToRoslynKind item.Kind
204+
let additionalInfo = Utils.containerToString item.Container document.Project
205+
yield NavigableItem(document, sourceSpan, glyph, item.Name, kind, additionalInfo) |]
204206
| None -> [||]
205207
}
206208

vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module private FSharpQuickInfo =
5050
let! extDocId = solution.GetDocumentIdsWithFilePath declRange.FileName |> Seq.tryHead
5151
let extDocument = solution.GetProject(extDocId.ProjectId).GetDocument extDocId
5252
let! extSourceText = extDocument.GetTextAsync cancellationToken
53-
let extSpan = RoslynHelpers.FSharpRangeToTextSpan (extSourceText, declRange)
53+
let! extSpan = RoslynHelpers.TryFSharpRangeToTextSpan (extSourceText, declRange)
5454
let extLineText = (extSourceText.Lines.GetLineFromPosition extSpan.Start).ToString()
5555

5656
// project options need to be retrieved because the signature file could be in another project
@@ -69,9 +69,10 @@ module private FSharpQuickInfo =
6969
| extTooltipText ->
7070
let! extSymbolUse =
7171
extCheckFileResults.GetSymbolUseAtLocation(declRange.StartLine, extLexerSymbol.Ident.idRange.EndColumn, extLineText, extLexerSymbol.FullIsland, userOpName=userOpName)
72+
let! span = RoslynHelpers.TryFSharpRangeToTextSpan (extSourceText, extLexerSymbol.Range)
7273

7374
return { StructuredText = extTooltipText
74-
Span = RoslynHelpers.FSharpRangeToTextSpan (extSourceText, extLexerSymbol.Range)
75+
Span = span
7576
Symbol = extSymbolUse.Symbol
7677
SymbolKind = extLexerSymbol.Kind }
7778
}
@@ -110,7 +111,7 @@ module private FSharpQuickInfo =
110111
| FSharpToolTipText []
111112
| FSharpToolTipText [FSharpStructuredToolTipElement.None] -> return! None
112113
| _ ->
113-
let targetTextSpan = RoslynHelpers.FSharpRangeToTextSpan (sourceText, lexerSymbol.Range)
114+
let! targetTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, lexerSymbol.Range)
114115
return { StructuredText = targetTooltip
115116
Span = targetTextSpan
116117
Symbol = symbolUse.Symbol
@@ -180,7 +181,8 @@ type internal FSharpQuickInfoProvider
180181
| FSharpToolTipText [FSharpStructuredToolTipElement.None] -> return! None
181182
| _ ->
182183
let! symbolUse = checkFileResults.GetSymbolUseAtLocation (textLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, userOpName=FSharpQuickInfo.userOpName)
183-
return res, RoslynHelpers.FSharpRangeToTextSpan (sourceText, symbol.Range), symbolUse.Symbol, symbol.Kind
184+
let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, symbol.Range)
185+
return res, symbolSpan, symbolUse.Symbol, symbol.Kind
184186
}
185187

186188
interface IQuickInfoProvider with

0 commit comments

Comments
 (0)