Skip to content

Commit ae085a8

Browse files
committed
Fully async version + ignore cancellation on external navigation
1 parent 9264c4a commit ae085a8

File tree

2 files changed

+75
-20
lines changed

2 files changed

+75
-20
lines changed

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

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -565,17 +565,77 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
565565
return this.NavigateToItem(item, cancellationToken)
566566
}
567567

568-
member this.NavigateToExternalDeclarationAsync
569-
(
570-
targetSymbolUse: FSharpSymbolUse,
571-
metadataReferences: seq<MetadataReference>
572-
) =
573-
foregroundCancellableTask
574-
{
575-
let! cancellationToken = CancellableTask.getCancellationToken()
576-
do! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken)
577-
return this.NavigateToExternalDeclaration(targetSymbolUse, metadataReferences, cancellationToken)
578-
}
568+
member this.NavigateToExternalDeclarationAsync (targetSymbolUse: FSharpSymbolUse, metadataReferences: seq<MetadataReference>) =
569+
let textOpt =
570+
match targetSymbolUse.Symbol with
571+
| :? FSharpEntity as symbol -> symbol.TryGetMetadataText() |> Option.map (fun text -> text, symbol.DisplayName)
572+
| :? FSharpMemberOrFunctionOrValue as symbol ->
573+
symbol.ApparentEnclosingEntity.TryGetMetadataText()
574+
|> Option.map (fun text -> text, symbol.ApparentEnclosingEntity.DisplayName)
575+
| :? FSharpField as symbol ->
576+
match symbol.DeclaringEntity with
577+
| Some entity ->
578+
let text = entity.TryGetMetadataText()
579+
580+
match text with
581+
| Some text -> Some(text, entity.DisplayName)
582+
| None -> None
583+
| None -> None
584+
| :? FSharpUnionCase as symbol ->
585+
symbol.DeclaringEntity.TryGetMetadataText()
586+
|> Option.map (fun text -> text, symbol.DisplayName)
587+
| _ -> None
588+
589+
match textOpt with
590+
| None -> CancellableTask.singleton false
591+
| Some (text, fileName) ->
592+
foregroundCancellableTask
593+
{
594+
let! cancellationToken = CancellableTask.getCancellationToken()
595+
do! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken)
596+
597+
let tmpProjInfo, tmpDocInfo =
598+
MetadataAsSource.generateTemporaryDocument (
599+
AssemblyIdentity(targetSymbolUse.Symbol.Assembly.QualifiedName),
600+
fileName,
601+
metadataReferences
602+
)
603+
let tmpShownDocOpt =
604+
metadataAsSource.ShowDocument(tmpProjInfo, tmpDocInfo.FilePath, SourceText.From(text.ToString()))
605+
606+
match tmpShownDocOpt with
607+
| ValueNone ->
608+
return false
609+
| ValueSome tmpShownDoc ->
610+
let! _, checkResults = tmpShownDoc.GetFSharpParseAndCheckResultsAsync("NavigateToExternalDeclaration")
611+
612+
let r =
613+
// This tries to find the best possible location of the target symbol's location in the metadata source.
614+
// We really should rely on symbol equality within FCS instead of doing it here,
615+
// but the generated metadata as source isn't perfect for symbol equality.
616+
let symbols = checkResults.GetAllUsesOfAllSymbolsInFile(cancellationToken)
617+
618+
symbols
619+
|> Seq.tryFindV (tryFindExternalSymbolUse targetSymbolUse)
620+
|> ValueOption.map (fun x -> x.Range)
621+
622+
let! span =
623+
cancellableTask {
624+
let! cancellationToken = CancellableTask.getCancellationToken()
625+
626+
match r with
627+
| ValueNone -> return TextSpan.empty
628+
| ValueSome r ->
629+
let! text = tmpShownDoc.GetTextAsync(cancellationToken)
630+
631+
match RoslynHelpers.TryFSharpRangeToTextSpan(text, r) with
632+
| ValueSome span -> return span
633+
| _ -> return TextSpan.empty
634+
}
635+
636+
let navItem = FSharpGoToDefinitionNavigableItem(tmpShownDoc, span)
637+
return this.NavigateToItem(navItem, cancellationToken)
638+
}
579639

580640
member this.NavigateToExternalDeclaration
581641
(
@@ -718,17 +778,12 @@ type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService,
718778
let gtd = GoToDefinition(metadataAsSource)
719779
let! result = gtd.FindDefinitionAtPosition(initialDoc, position)
720780

721-
722781
match result with
723782
| ValueSome(FSharpGoToDefinitionResult.NavigableItem(navItem), _) ->
724783
return ImmutableArray.create navItem
725784
| ValueSome(FSharpGoToDefinitionResult.ExternalAssembly(targetSymbolUse, metadataReferences), _) ->
726-
let! res = gtd.NavigateToExternalDeclarationAsync(targetSymbolUse, metadataReferences)
727-
if not res then
728-
return ImmutableArray.empty
729-
else
730-
// TODO: return something? Maybe cancelled task?
731-
return ImmutableArray.empty
785+
do! gtd.NavigateToExternalDeclarationAsync(targetSymbolUse, metadataReferences) |> CancellableTask.ignore
786+
return ImmutableArray.empty
732787
| _ ->
733788
return ImmutableArray.empty
734789
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ type internal FSharpGoToDefinitionService [<ImportingConstructor>] (metadataAsSo
1818

1919
interface IFSharpGoToDefinitionService with
2020
/// Invoked with Peek Definition.
21-
member _.FindDefinitionsAsync(document: Document, position: int, cancellationToken: CancellationToken) =
21+
member _.FindDefinitionsAsync(document: Document, position: int, _cancellationToken: CancellationToken) =
2222
cancellableTask {
2323
let navigation = FSharpNavigation(metadataAsSource, document, rangeStartup)
2424
let! res = navigation.FindDefinitionsAsync(position)
2525
return (res :> IEnumerable<_>)
2626
}
27-
|> CancellableTask.start cancellationToken
27+
|> CancellableTask.startWithoutCancellation
2828

2929
/// Invoked with Go to Definition.
3030
/// Try to navigate to the definiton of the symbol at the symbolRange in the originDocument

0 commit comments

Comments
 (0)