@@ -199,6 +199,76 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
199199 return None
200200 }
201201
202+ member _.TryGetExternalDeclarationAsync ( targetSymbolUse : FSharpSymbolUse , metadataReferences : seq < MetadataReference >) =
203+ let textOpt =
204+ match targetSymbolUse.Symbol with
205+ | :? FSharpEntity as symbol -> symbol.TryGetMetadataText() |> Option.map ( fun text -> text, symbol.DisplayName)
206+ | :? FSharpMemberOrFunctionOrValue as symbol ->
207+ symbol.ApparentEnclosingEntity.TryGetMetadataText()
208+ |> Option.map ( fun text -> text, symbol.ApparentEnclosingEntity.DisplayName)
209+ | :? FSharpField as symbol ->
210+ match symbol.DeclaringEntity with
211+ | Some entity ->
212+ let text = entity.TryGetMetadataText()
213+
214+ match text with
215+ | Some text -> Some( text, entity.DisplayName)
216+ | None -> None
217+ | None -> None
218+ | :? FSharpUnionCase as symbol ->
219+ symbol.DeclaringEntity.TryGetMetadataText()
220+ |> Option.map ( fun text -> text, symbol.DisplayName)
221+ | _ -> None
222+
223+ match textOpt with
224+ | None -> CancellableTask.singleton None
225+ | Some( text, fileName) ->
226+ foregroundCancellableTask {
227+ let! cancellationToken = CancellableTask.getCancellationToken ()
228+ do ! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync( cancellationToken)
229+
230+ let tmpProjInfo , tmpDocInfo =
231+ MetadataAsSource.generateTemporaryDocument (
232+ AssemblyIdentity( targetSymbolUse.Symbol.Assembly.QualifiedName),
233+ fileName,
234+ metadataReferences
235+ )
236+
237+ let tmpShownDocOpt =
238+ metadataAsSource.ShowDocument( tmpProjInfo, tmpDocInfo.FilePath, SourceText.From( text.ToString()))
239+
240+ match tmpShownDocOpt with
241+ | ValueNone -> return None
242+ | ValueSome tmpShownDoc ->
243+ let! _ , checkResults = tmpShownDoc.GetFSharpParseAndCheckResultsAsync( " NavigateToExternalDeclaration" )
244+
245+ let r =
246+ // This tries to find the best possible location of the target symbol's location in the metadata source.
247+ // We really should rely on symbol equality within FCS instead of doing it here,
248+ // but the generated metadata as source isn't perfect for symbol equality.
249+ let symbols = checkResults.GetAllUsesOfAllSymbolsInFile( cancellationToken)
250+
251+ symbols
252+ |> Seq.tryFindV ( tryFindExternalSymbolUse targetSymbolUse)
253+ |> ValueOption.map ( fun x -> x.Range)
254+
255+ let! span =
256+ cancellableTask {
257+ let! cancellationToken = CancellableTask.getCancellationToken ()
258+
259+ match r with
260+ | ValueNone -> return TextSpan.empty
261+ | ValueSome r ->
262+ let! text = tmpShownDoc.GetTextAsync( cancellationToken)
263+
264+ match RoslynHelpers.TryFSharpRangeToTextSpan( text, r) with
265+ | ValueSome span -> return span
266+ | _ -> return TextSpan.empty
267+ }
268+
269+ return Some( FSharpGoToDefinitionNavigableItem( tmpShownDoc, span) :> FSharpNavigableItem)
270+ }
271+
202272 /// Helper function that is used to determine the navigation strategy to apply, can be tuned towards signatures or implementation files.
203273 member private _.FindSymbolHelper ( originDocument : Document , originRange : range , sourceText : SourceText , preferSignature : bool ) =
204274 let originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan( sourceText, originRange)
@@ -566,75 +636,13 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
566636 }
567637
568638 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- let! cancellationToken = CancellableTask.getCancellationToken ()
594- do ! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync( cancellationToken)
595-
596- let tmpProjInfo , tmpDocInfo =
597- MetadataAsSource.generateTemporaryDocument (
598- AssemblyIdentity( targetSymbolUse.Symbol.Assembly.QualifiedName),
599- fileName,
600- metadataReferences
601- )
602-
603- let tmpShownDocOpt =
604- metadataAsSource.ShowDocument( tmpProjInfo, tmpDocInfo.FilePath, SourceText.From( text.ToString()))
605-
606- match tmpShownDocOpt with
607- | ValueNone -> return false
608- | ValueSome tmpShownDoc ->
609- let! _ , checkResults = tmpShownDoc.GetFSharpParseAndCheckResultsAsync( " NavigateToExternalDeclaration" )
610-
611- let r =
612- // This tries to find the best possible location of the target symbol's location in the metadata source.
613- // We really should rely on symbol equality within FCS instead of doing it here,
614- // but the generated metadata as source isn't perfect for symbol equality.
615- let symbols = checkResults.GetAllUsesOfAllSymbolsInFile( cancellationToken)
616-
617- symbols
618- |> Seq.tryFindV ( tryFindExternalSymbolUse targetSymbolUse)
619- |> ValueOption.map ( fun x -> x.Range)
620-
621- let! span =
622- cancellableTask {
623- let! cancellationToken = CancellableTask.getCancellationToken ()
624-
625- match r with
626- | ValueNone -> return TextSpan.empty
627- | ValueSome r ->
628- let! text = tmpShownDoc.GetTextAsync( cancellationToken)
629-
630- match RoslynHelpers.TryFSharpRangeToTextSpan( text, r) with
631- | ValueSome span -> return span
632- | _ -> return TextSpan.empty
633- }
639+ foregroundCancellableTask {
640+ let! cancellationToken = CancellableTask.getCancellationToken ()
634641
635- let navItem = FSharpGoToDefinitionNavigableItem( tmpShownDoc, span)
636- return this.NavigateToItem( navItem, cancellationToken)
637- }
642+ match ! this.TryGetExternalDeclarationAsync( targetSymbolUse, metadataReferences) with
643+ | Some navItem -> return this.NavigateToItem( navItem, cancellationToken)
644+ | None -> return false
645+ }
638646
639647 member this.NavigateToExternalDeclaration
640648 (
@@ -780,11 +788,9 @@ type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService,
780788 match result with
781789 | ValueSome( FSharpGoToDefinitionResult.NavigableItem( navItem), _) -> return ImmutableArray.create navItem
782790 | ValueSome( FSharpGoToDefinitionResult.ExternalAssembly( targetSymbolUse, metadataReferences), _) ->
783- do !
784- gtd.NavigateToExternalDeclarationAsync( targetSymbolUse, metadataReferences)
785- |> CancellableTask.ignore
786-
787- return ImmutableArray.empty
791+ match ! gtd.TryGetExternalDeclarationAsync( targetSymbolUse, metadataReferences) with
792+ | Some navItem -> return ImmutableArray.Create navItem
793+ | _ -> return ImmutableArray.empty
788794 | _ -> return ImmutableArray.empty
789795 }
790796
0 commit comments