diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index 474b952c478..5b81796d8d5 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -46,6 +46,7 @@
+
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs
index 56c074d78b2..f3212db489f 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs
@@ -26,6 +26,8 @@ type internal FSharpCheckerProvider
settings: EditorOptions
) =
+ let metadataAsSource = FSharpMetadataAsSourceService()
+
let tryGetMetadataSnapshot (path, timeStamp) =
try
let md = Microsoft.CodeAnalysis.ExternalAccess.FSharp.LanguageServices.FSharpVisualStudioWorkspaceExtensions.GetMetadata(workspace, path, timeStamp)
@@ -85,3 +87,5 @@ type internal FSharpCheckerProvider
member this.Checker = checker.Value
+ member _.MetadataAsSource = metadataAsSource
+
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs
index a35323f9de2..c077def059a 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs
@@ -433,3 +433,5 @@ type internal FSharpProjectOptionsManager
reactor.SetCpsCommandLineOptions(projectId, sourcePaths, options.ToArray())
member _.Checker = checkerProvider.Checker
+
+ member _.MetadataAsSource = checkerProvider.MetadataAsSource
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/MetadataAsSource.fs b/vsintegration/src/FSharp.Editor/LanguageService/MetadataAsSource.fs
new file mode 100644
index 00000000000..b1e0df38153
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/LanguageService/MetadataAsSource.fs
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System
+open System.Threading
+open System.Collections.Immutable
+open System.Diagnostics
+open System.IO
+open System.Linq
+open System.Text
+open System.Runtime.InteropServices
+open System.Reflection.PortableExecutable
+
+open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.FindSymbols
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.Navigation
+open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation
+open Microsoft.VisualStudio.ComponentModelHost
+
+open Microsoft.VisualStudio
+open Microsoft.VisualStudio.Editor
+open Microsoft.VisualStudio.Threading
+open Microsoft.VisualStudio.Shell
+open Microsoft.VisualStudio.Shell.Interop
+open Microsoft.VisualStudio.TextManager.Interop
+
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+module internal MetadataAsSource =
+
+ open Microsoft.CodeAnalysis.CSharp
+ open ICSharpCode.Decompiler
+ open ICSharpCode.Decompiler.CSharp
+ open ICSharpCode.Decompiler.Metadata
+ open ICSharpCode.Decompiler.CSharp.Transforms
+ open ICSharpCode.Decompiler.TypeSystem
+
+ let generateTemporaryCSharpDocument (asmIdentity: AssemblyIdentity, name: string, metadataReferences) =
+ let rootPath = Path.Combine(Path.GetTempPath(), "MetadataAsSource")
+ let extension = ".cs"
+ let directoryName = Guid.NewGuid().ToString("N")
+ let temporaryFilePath = Path.Combine(rootPath, directoryName, name + extension)
+
+ let projectId = ProjectId.CreateNewId()
+
+ let parseOptions = CSharpParseOptions.Default.WithLanguageVersion(Microsoft.CodeAnalysis.CSharp.LanguageVersion.Preview)
+ // Just say it's always a DLL since we probably won't have a Main method
+ let compilationOptions = Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
+
+ // We need to include the version information of the assembly so InternalsVisibleTo and stuff works
+ let assemblyInfoDocumentId = DocumentId.CreateNewId(projectId)
+ let assemblyInfoFileName = "AssemblyInfo" + extension
+ let assemblyInfoString = String.Format(@"[assembly: System.Reflection.AssemblyVersion(""{0}"")]", asmIdentity.Version)
+
+ let assemblyInfoSourceTextContainer = SourceText.From(assemblyInfoString, Encoding.UTF8).Container
+
+ let assemblyInfoDocument =
+ DocumentInfo.Create(
+ assemblyInfoDocumentId,
+ assemblyInfoFileName,
+ loader = TextLoader.From(assemblyInfoSourceTextContainer, VersionStamp.Default))
+
+ let generatedDocumentId = DocumentId.CreateNewId(projectId)
+ let documentInfo =
+ DocumentInfo.Create(
+ generatedDocumentId,
+ Path.GetFileName(temporaryFilePath),
+ filePath = temporaryFilePath,
+ loader = FileTextLoader(temporaryFilePath, Encoding.UTF8))
+
+ let projectInfo =
+ ProjectInfo.Create(
+ projectId,
+ VersionStamp.Default,
+ name = asmIdentity.Name,
+ assemblyName = asmIdentity.Name,
+ language = LanguageNames.CSharp,
+ compilationOptions = compilationOptions,
+ parseOptions = parseOptions,
+ documents = [|assemblyInfoDocument;documentInfo|],
+ metadataReferences = metadataReferences)
+
+ (projectInfo, documentInfo)
+
+ let decompileCSharp (symbolFullTypeName: string, assemblyLocation: string) =
+ let logger = new StringBuilder()
+
+ // Initialize a decompiler with default settings.
+ let decompiler = CSharpDecompiler(assemblyLocation, DecompilerSettings())
+ // Escape invalid identifiers to prevent Roslyn from failing to parse the generated code.
+ // (This happens for example, when there is compiler-generated code that is not yet recognized/transformed by the decompiler.)
+ decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers())
+
+ let fullTypeName = FullTypeName(symbolFullTypeName)
+
+ // Try to decompile; if an exception is thrown the caller will handle it
+ let text = decompiler.DecompileTypeAsString(fullTypeName)
+
+ let text = text + "#if false // " + Environment.NewLine
+ let text = text + logger.ToString()
+ let text = text + "#endif" + Environment.NewLine
+
+ SourceText.From(text)
+
+ let showDocument (filePath, name, serviceProvider: IServiceProvider) =
+ let vsRunningDocumentTable4 = serviceProvider.GetService()
+ let fileAlreadyOpen = vsRunningDocumentTable4.IsMonikerValid(filePath)
+
+ let openDocumentService = serviceProvider.GetService()
+
+ let (_, _, _, _, windowFrame) = openDocumentService.OpenDocumentViaProject(filePath, ref VSConstants.LOGVIEWID.TextView_guid)
+
+ let componentModel = serviceProvider.GetService()
+ let editorAdaptersFactory = componentModel.GetService();
+ let documentCookie = vsRunningDocumentTable4.GetDocumentCookie(filePath)
+ let vsTextBuffer = vsRunningDocumentTable4.GetDocumentData(documentCookie) :?> IVsTextBuffer
+ let textBuffer = editorAdaptersFactory.GetDataBuffer(vsTextBuffer)
+
+ if not fileAlreadyOpen then
+ ErrorHandler.ThrowOnFailure(windowFrame.SetProperty(int __VSFPROPID5.VSFPROPID_IsProvisional, true)) |> ignore
+ ErrorHandler.ThrowOnFailure(windowFrame.SetProperty(int __VSFPROPID5.VSFPROPID_OverrideCaption, name)) |> ignore
+ ErrorHandler.ThrowOnFailure(windowFrame.SetProperty(int __VSFPROPID5.VSFPROPID_OverrideToolTip, name)) |> ignore
+
+ windowFrame.Show() |> ignore
+
+ let textContainer = textBuffer.AsTextContainer()
+ let mutable workspace = Unchecked.defaultof<_>
+ if Workspace.TryGetWorkspace(textContainer, &workspace) then
+ let solution = workspace.CurrentSolution
+ let documentId = workspace.GetDocumentIdInCurrentContext(textContainer)
+ match box documentId with
+ | null -> None
+ | _ -> solution.GetDocument(documentId) |> Some
+ else
+ None
+
+[]
+type internal FSharpMetadataAsSourceService() =
+
+ member val CSharpFiles = System.Collections.Concurrent.ConcurrentDictionary(StringComparer.OrdinalIgnoreCase)
+
+ member this.ShowCSharpDocument(projInfo: ProjectInfo, docInfo: DocumentInfo, text: Text.SourceText) =
+ let _ =
+ let directoryName = Path.GetDirectoryName(docInfo.FilePath)
+ if Directory.Exists(directoryName) |> not then
+ Directory.CreateDirectory(directoryName) |> ignore
+ use fileStream = new FileStream(docInfo.FilePath, IO.FileMode.Create)
+ use writer = new StreamWriter(fileStream)
+ text.Write(writer)
+
+ this.CSharpFiles.[docInfo.FilePath] <- (projInfo, docInfo)
+
+ MetadataAsSource.showDocument(docInfo.FilePath, docInfo.Name, ServiceProvider.GlobalProvider)
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SingleFileWorkspaceMap.fs b/vsintegration/src/FSharp.Editor/LanguageService/SingleFileWorkspaceMap.fs
index 5947c59b8ae..0e565801fd3 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/SingleFileWorkspaceMap.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/SingleFileWorkspaceMap.fs
@@ -33,11 +33,33 @@ type internal SingleFileWorkspaceMap(workspace: VisualStudioWorkspace,
projectContext.AddSourceFile(filePath, sourceCodeKind = createSourceCodeKind filePath)
projectContext
+ let createCSharpMetadataProjectContext (projInfo: ProjectInfo) (docInfo: DocumentInfo) =
+ let projectContext = projectContextFactory.CreateProjectContext(LanguageNames.CSharp, projInfo.Id.ToString(), projInfo.FilePath, Guid.NewGuid(), null, null)
+ projectContext.DisplayName <- projInfo.Name
+ projectContext.AddSourceFile(docInfo.FilePath, sourceCodeKind = SourceCodeKind.Regular)
+
+ for metaRef in projInfo.MetadataReferences do
+ match metaRef with
+ | :? PortableExecutableReference as peRef ->
+ projectContext.AddMetadataReference(peRef.FilePath, MetadataReferenceProperties.Assembly)
+ | _ ->
+ ()
+
+ projectContext
+
do
miscFilesWorkspace.DocumentOpened.Add(fun args ->
let document = args.Document
+
if document.Project.Language = FSharpConstants.FSharpLanguageName && workspace.CurrentSolution.GetDocumentIdsWithFilePath(document.FilePath).Length = 0 then
files.[document.FilePath] <- createProjectContext document.FilePath
+
+ if optionsManager.MetadataAsSource.CSharpFiles.ContainsKey(document.FilePath) && workspace.CurrentSolution.GetDocumentIdsWithFilePath(document.FilePath).Length = 0 then
+ match optionsManager.MetadataAsSource.CSharpFiles.TryGetValue(document.FilePath) with
+ | true, (projInfo, docInfo) ->
+ files.[document.FilePath] <- createCSharpMetadataProjectContext projInfo docInfo
+ | _ ->
+ ()
)
workspace.DocumentOpened.Add(fun args ->
@@ -57,6 +79,8 @@ type internal SingleFileWorkspaceMap(workspace: VisualStudioWorkspace,
optionsManager.ClearSingleFileOptionsCache(document.Id)
projectContext.Dispose()
| _ -> ()
+
+ optionsManager.MetadataAsSource.CSharpFiles.TryRemove(document.FilePath) |> ignore
)
do
diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs
index 00b8152934f..d5166440213 100644
--- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs
+++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs
@@ -8,19 +8,28 @@ open System.Collections.Immutable
open System.Diagnostics
open System.IO
open System.Linq
+open System.Text
open System.Runtime.InteropServices
+open System.Reflection.PortableExecutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.FindSymbols
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.Navigation
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation
+open Microsoft.VisualStudio.ComponentModelHost
+open Microsoft.VisualStudio
+open Microsoft.VisualStudio.Editor
+open Microsoft.VisualStudio.Threading
+open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
+open Microsoft.VisualStudio.TextManager.Interop
open FSharp.Compiler.SourceCodeServices
open FSharp.Compiler.Text
+
module private Symbol =
let fullName (root: ISymbol) : string =
let rec inner parts (sym: ISymbol) =
@@ -145,6 +154,11 @@ type internal StatusBar(statusBar: IVsStatusbar) =
type internal FSharpGoToDefinitionNavigableItem(document, sourceSpan) =
inherit FSharpNavigableItem(Glyph.BasicFile, ImmutableArray.Empty, document, sourceSpan)
+[]
+type internal FSharpGoToDefinitionResult =
+ | NavigableItem of FSharpNavigableItem
+ | ExternalAssembly of ProjectInfo * DocumentInfo * FSharpSymbolUse * FSharpExternalSymbol
+
type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager) =
let userOpName = "GoToDefinition"
@@ -241,23 +255,28 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
match declarations with
| FSharpFindDeclResult.ExternalDecl (assembly, targetExternalSym) ->
- let! project = originDocument.Project.Solution.Projects |> Seq.tryFind (fun p -> p.AssemblyName.Equals(assembly, StringComparison.OrdinalIgnoreCase))
- let! symbols = SymbolFinder.FindSourceDeclarationsAsync(project, fun _ -> true)
-
- let roslynSymbols =
- symbols
- |> Seq.collect ExternalSymbol.ofRoslynSymbol
- |> Array.ofSeq
-
- let! symbol =
- roslynSymbols
- |> Seq.tryPick (fun (sym, externalSym) ->
- if externalSym = targetExternalSym then Some sym
- else None
- )
-
- let! location = symbol.Locations |> Seq.tryHead
- return (FSharpGoToDefinitionNavigableItem(project.GetDocument(location.SourceTree), location.SourceSpan), idRange)
+ let projectOpt = originDocument.Project.Solution.Projects |> Seq.tryFind (fun p -> p.AssemblyName.Equals(assembly, StringComparison.OrdinalIgnoreCase))
+ match projectOpt with
+ | Some project ->
+ let! symbols = SymbolFinder.FindSourceDeclarationsAsync(project, fun _ -> true)
+
+ let roslynSymbols =
+ symbols
+ |> Seq.collect ExternalSymbol.ofRoslynSymbol
+ |> Array.ofSeq
+
+ let! symbol =
+ roslynSymbols
+ |> Seq.tryPick (fun (sym, externalSym) ->
+ if externalSym = targetExternalSym then Some sym
+ else None
+ )
+
+ let! location = symbol.Locations |> Seq.tryHead
+ return (FSharpGoToDefinitionResult.NavigableItem(FSharpGoToDefinitionNavigableItem(project.GetDocument(location.SourceTree), location.SourceSpan)), idRange)
+ | _ ->
+ let tmpProjInfo, tmpDocId = MetadataAsSource.generateTemporaryCSharpDocument(AssemblyIdentity(targetSymbolUse.Symbol.Assembly.QualifiedName), targetSymbolUse.Symbol.DisplayName, originDocument.Project.MetadataReferences)
+ return (FSharpGoToDefinitionResult.ExternalAssembly(tmpProjInfo, tmpDocId, targetSymbolUse, targetExternalSym), idRange)
| FSharpFindDeclResult.DeclFound targetRange ->
// if goto definition is called at we are alread at the declaration location of a symbol in
@@ -275,7 +294,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange)
let navItem = FSharpGoToDefinitionNavigableItem (implDocument, implTextSpan)
- return (navItem, idRange)
+ return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange)
else // jump from implementation to the corresponding signature
let declarations = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLineString, lexerSymbol.FullIsland, true)
match declarations with
@@ -284,7 +303,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
let! sigSourceText = sigDocument.GetTextAsync () |> liftTaskAsync
let! sigTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sigSourceText, targetRange)
let navItem = FSharpGoToDefinitionNavigableItem (sigDocument, sigTextSpan)
- return (navItem, idRange)
+ return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange)
| _ ->
return! None
// when the target range is different follow the navigation convention of
@@ -297,7 +316,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
// if the gotodef call originated from a signature and the returned target is a signature, navigate there
if isSignatureFile targetRange.FileName && preferSignature then
let navItem = FSharpGoToDefinitionNavigableItem (sigDocument, sigTextSpan)
- return (navItem, idRange)
+ return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange)
else // we need to get an FSharpSymbol from the targetRange found in the signature
// that symbol will be used to find the destination in the corresponding implementation file
let implFilePath =
@@ -314,7 +333,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange)
let navItem = FSharpGoToDefinitionNavigableItem (implDocument, implTextSpan)
- return (navItem, idRange)
+ return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange)
| _ ->
return! None
}
@@ -330,8 +349,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
member this.FindDefinitionsForPeekTask(originDocument: Document, position: int, cancellationToken: CancellationToken) =
this.FindDefinitionAtPosition(originDocument, position)
|> Async.map (
- Option.map (fun (navItem, _) -> navItem :> FSharpNavigableItem)
- >> Option.toArray
+ Option.toArray
>> Array.toSeq)
|> RoslynHelpers.StartAsyncAsTask cancellationToken
@@ -343,7 +361,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP
/// Navigate to the positon of the textSpan in the provided document
/// used by quickinfo link navigation when the tooltip contains the correct destination range.
- member _.TryNavigateToTextSpan(document: Document, textSpan: TextSpan, statusBar: StatusBar) =
+ member _.TryNavigateToTextSpan(document: Document, textSpan: Microsoft.CodeAnalysis.Text.TextSpan, statusBar: StatusBar) =
let navigableItem = FSharpGoToDefinitionNavigableItem(document, textSpan)
let workspace = document.Project.Solution.Workspace
let navigationService = workspace.Services.GetService()
diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs
index e8bb0d1fdc9..ba377a3929a 100644
--- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs
+++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs
@@ -2,18 +2,24 @@
namespace Microsoft.VisualStudio.FSharp.Editor
+open System
open System.Composition
+open System.IO
open System.Threading
open System.Threading.Tasks
open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.Editor
open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor
+open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation
open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
-open System
+open Microsoft.VisualStudio.LanguageServices
+
+open FSharp.Compiler.SourceCodeServices
[)>]
[)>]
@@ -25,12 +31,22 @@ type internal FSharpGoToDefinitionService
) =
let gtd = GoToDefinition(checkerProvider.Checker, projectInfoManager)
- let statusBar = StatusBar(ServiceProvider.GlobalProvider.GetService())
+ let statusBar = StatusBar(ServiceProvider.GlobalProvider.GetService())
+ let metadataAsSourceService = checkerProvider.MetadataAsSource
interface IFSharpGoToDefinitionService with
/// Invoked with Peek Definition.
member _.FindDefinitionsAsync (document: Document, position: int, cancellationToken: CancellationToken) =
- gtd.FindDefinitionsForPeekTask(document, position, cancellationToken)
+ let task = gtd.FindDefinitionsForPeekTask(document, position, cancellationToken)
+ task.Wait(cancellationToken)
+ let results = task.Result
+ results
+ |> Seq.choose(fun (result, _) ->
+ match result with
+ | FSharpGoToDefinitionResult.NavigableItem(navItem) -> Some navItem
+ | _ -> None
+ )
+ |> Task.FromResult
/// Invoked with Go to Definition.
/// Try to navigate to the definiton of the symbol at the symbolRange in the originDocument
@@ -44,13 +60,44 @@ type internal FSharpGoToDefinitionService
// Task.Wait throws an exception if the task is cancelled, so be sure to catch it.
try
// This call to Wait() is fine because we want to be able to provide the error message in the status bar.
- gtdTask.Wait()
+ gtdTask.Wait(cancellationToken)
if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then
- let item, _ = gtdTask.Result.Value
- gtd.NavigateToItem(item, statusBar)
+ let result, _ = gtdTask.Result.Value
+ match result with
+ | FSharpGoToDefinitionResult.NavigableItem(navItem) ->
+ gtd.NavigateToItem(navItem, statusBar)
+ // 'true' means do it, like Sheev Palpatine would want us to.
+ true
+ | FSharpGoToDefinitionResult.ExternalAssembly(tmpProjInfo, tmpDocInfo, targetSymbolUse, targetExternalSymbol) ->
+ match targetSymbolUse.Symbol.Assembly.FileName with
+ | Some targetSymbolAssemblyFileName ->
+ try
+ let symbolFullTypeName =
+ match targetExternalSymbol with
+ | FSharpExternalSymbol.Constructor(tyName, _)
+ | FSharpExternalSymbol.Event(tyName, _)
+ | FSharpExternalSymbol.Field(tyName, _)
+ | FSharpExternalSymbol.Method(tyName, _, _, _)
+ | FSharpExternalSymbol.Property(tyName, _)
+ | FSharpExternalSymbol.Type(tyName) -> tyName
- // 'true' means do it, like Sheev Palpatine would want us to.
- true
+ let text = MetadataAsSource.decompileCSharp(symbolFullTypeName, targetSymbolAssemblyFileName)
+ let tmpShownDocOpt = metadataAsSourceService.ShowCSharpDocument(tmpProjInfo, tmpDocInfo, text)
+ match tmpShownDocOpt with
+ | Some tmpShownDoc ->
+ let navItem = FSharpGoToDefinitionNavigableItem(tmpShownDoc, TextSpan())
+ gtd.NavigateToItem(navItem, statusBar)
+ true
+ | _ ->
+ statusBar.TempMessage (SR.CannotDetermineSymbol())
+ false
+ with
+ | _ ->
+ statusBar.TempMessage (SR.CannotDetermineSymbol())
+ false
+ | _ ->
+ statusBar.TempMessage (SR.CannotDetermineSymbol())
+ false
else
statusBar.TempMessage (SR.CannotDetermineSymbol())
false
diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs
index 2c7b1b7a894..941a9c30e6e 100644
--- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs
+++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs
@@ -58,13 +58,17 @@ type internal FSharpNavigableSymbolSource(checkerProvider: FSharpCheckerProvider
statusBar.Clear()
if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then
- let navigableItem, range = gtdTask.Result.Value
+ let result, range = gtdTask.Result.Value
let declarationTextSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)
let declarationSpan = Span(declarationTextSpan.Start, declarationTextSpan.Length)
let symbolSpan = SnapshotSpan(snapshot, declarationSpan)
- return FSharpNavigableSymbol(navigableItem, symbolSpan, gtd, statusBar) :> INavigableSymbol
+ match result with
+ | FSharpGoToDefinitionResult.NavigableItem(navItem) ->
+ return FSharpNavigableSymbol(navItem, symbolSpan, gtd, statusBar) :> INavigableSymbol
+ | _ ->
+ return null
else
statusBar.TempMessage(SR.CannotDetermineSymbol())