From 024a45e386d57822aa8ce39f81229d8334048541 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Thu, 31 Aug 2017 15:44:50 -0700 Subject: [PATCH 01/13] Saved --- .../Classification/ColorizationService.fs | 2 +- .../CodeFix/AddOpenCodeFixProvider.fs | 2 +- .../ImplementInterfaceCodeFixProvider.fs | 2 +- .../CodeFix/ProposeUppercaseLabel.fs | 2 +- .../CodeFix/RemoveUnusedOpens.fs | 2 +- .../CodeFix/RenameUnusedValue.fs | 2 +- .../Commands/HelpContextService.fs | 2 +- .../Commands/XmlDocCommandService.fs | 4 +- .../Completion/CompletionProvider.fs | 2 +- .../Completion/CompletionService.fs | 4 +- .../Completion/FileSystemCompletion.fs | 2 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 2 +- .../Debugging/BreakpointResolutionService.fs | 2 +- .../Debugging/LanguageDebugInfoService.fs | 2 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 2 +- .../SimplifyNameDiagnosticAnalyzer.fs | 2 +- .../Diagnostics/UnusedDeclarationsAnalyzer.fs | 2 +- .../UnusedOpensDiagnosticAnalyzer.fs | 2 +- .../DocumentHighlightsService.fs | 2 +- .../Formatting/BraceMatchingService.fs | 2 +- .../Formatting/IndentationService.fs | 2 +- .../InlineRename/InlineRenameService.fs | 6 +- .../LanguageService/LanguageService.fs | 180 ++++++++++++++---- .../LanguageService/SymbolHelpers.fs | 4 +- .../Navigation/FindUsagesService.fs | 2 +- .../Navigation/GoToDefinitionService.fs | 4 +- .../Navigation/NavigateToSearchService.fs | 2 +- .../Navigation/NavigationBarItemService.fs | 2 +- .../QuickInfo/QuickInfoProvider.fs | 6 +- .../Structure/BlockStructureService.fs | 4 +- .../ProjectSitesAndFiles.fs | 16 +- 31 files changed, 187 insertions(+), 85 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs b/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs index b40aaa4d0a2..b35c49b8582 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs @@ -21,7 +21,7 @@ type internal FSharpColorizationService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "SemanticColorization" diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs index 5ad0a1a9b63..e1a3c3740a9 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs @@ -22,7 +22,7 @@ type internal FSharpAddOpenCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, assemblyContentProvider: AssemblyContentProvider ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs index d4dd1bf4134..a6f69be90f1 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -29,7 +29,7 @@ type internal FSharpImplementInterfaceCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = ["FS0366"] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs index c1c370f021f..6a97df5a863 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs @@ -12,7 +12,7 @@ type internal FSharpProposeUpperCaseLabelCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = ["FS0053"] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index 8147cc99be9..a6994ec55ee 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -19,7 +19,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = [IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs index e25095da3f0..8430786e79e 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs @@ -20,7 +20,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs index 1c51bc4235e..fbaeea13e96 100644 --- a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs @@ -19,7 +19,7 @@ type internal FSharpHelpContextService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "ImplementInterfaceCodeFix" diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index f93604034b5..e6c84584b36 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -21,7 +21,7 @@ type internal XmlDocCommandFilter wpfTextView: IWpfTextView, filePath: string, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, workspace: VisualStudioWorkspaceImpl ) = @@ -117,7 +117,7 @@ type internal XmlDocCommandFilter type internal XmlDocCommandFilterProvider [] (checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, workspace: VisualStudioWorkspaceImpl, textDocumentFactoryService: ITextDocumentFactoryService, editorFactory: IVsEditorAdaptersFactoryService) = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index f77988f2702..e8a217a30ad 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -27,7 +27,7 @@ type internal FSharpCompletionProvider workspace: Workspace, serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, assemblyContentProvider: AssemblyContentProvider ) = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index ab9585c5184..98b6d87c35e 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -17,7 +17,7 @@ type internal FSharpCompletionService workspace: Workspace, serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, assemblyContentProvider: AssemblyContentProvider ) = inherit CompletionServiceWithProviders(workspace) @@ -47,7 +47,7 @@ type internal FSharpCompletionServiceFactory ( serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, assemblyContentProvider: AssemblyContentProvider ) = interface ILanguageServiceFactory with diff --git a/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs b/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs index f8a66615f20..42694f084b2 100644 --- a/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs +++ b/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs @@ -22,7 +22,7 @@ type internal Completion = AllowableExtensions = allowableExtensions UseIncludeDirectives = useIncludeDirectives } -type internal HashDirectiveCompletionProvider(workspace: Workspace, projectInfoManager: FSharpProjectOptionsManager, completions: Completion list) = +type internal HashDirectiveCompletionProvider(workspace: Workspace, projectInfoManager: ProjectInfoManager, completions: Completion list) = inherit CommonCompletionProvider() let [] NetworkPath = "\\\\" diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 22310a9bf43..53592a42803 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -25,7 +25,7 @@ type internal FSharpSignatureHelpProvider ( serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "SignatureHelpProvider" diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs index 864a77e44aa..802ad32bf82 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs @@ -23,7 +23,7 @@ type internal FSharpBreakpointResolutionService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "BreakpointResolution" diff --git a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs index 02ccfc1e6e8..b9fbe70ff35 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs @@ -18,7 +18,7 @@ open Microsoft.VisualStudio.FSharp.LanguageService [] [, FSharpConstants.FSharpLanguageName)>] -type internal FSharpLanguageDebugInfoService [](projectInfoManager: FSharpProjectOptionsManager) = +type internal FSharpLanguageDebugInfoService [](projectInfoManager: ProjectInfoManager) = static member GetDataTipInformation(sourceText: SourceText, position: int, tokens: List): TextSpan option = let tokenIndex = tokens |> Seq.tryFindIndex(fun t -> t.TextSpan.Contains(position)) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 412496efa35..f31f18e1102 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -30,7 +30,7 @@ type internal FSharpDocumentDiagnosticAnalyzer() = document.Project.Solution.Workspace.Services.GetService().Checker let getProjectInfoManager(document: Document) = - document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager + document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager static let errorInfoEqualityComparer = { new IEqualityComparer with diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index 0686c7ddd86..50f561b818a 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -24,7 +24,7 @@ type internal SimplifyNameDiagnosticAnalyzer() = inherit DocumentDiagnosticAnalyzer() static let userOpName = "SimplifyNameDiagnosticAnalyzer" - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker let getPlidLength (plid: string list) = (plid |> List.sumBy String.length) + plid.Length static let cache = ConditionalWeakTable>() diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs index b1868f9f5f1..9047f62c13f 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -17,7 +17,7 @@ type internal UnusedDeclarationsAnalyzer() = inherit DocumentDiagnosticAnalyzer() static let userOpName = "UnusedDeclarationsAnalyzer" - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker let [] DescriptorId = "FS1182" diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 53c5d51b3d3..354264d5c0f 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -143,7 +143,7 @@ module private UnusedOpens = type internal UnusedOpensDiagnosticAnalyzer() = inherit DocumentDiagnosticAnalyzer() - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker static let userOpName = "UnusedOpensAnalyzer" diff --git a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs index e4829fd4764..d43dc7dc23c 100644 --- a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs +++ b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs @@ -23,7 +23,7 @@ type internal FSharpHighlightSpan = [] [, FSharpConstants.FSharpLanguageName)>] -type internal FSharpDocumentHighlightsService [] (checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager) = +type internal FSharpDocumentHighlightsService [] (checkerProvider: FSharpCheckerProvider, projectInfoManager: ProjectInfoManager) = static let userOpName = "DocumentHighlights" diff --git a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs index 9c5a160ad05..e4b0f83a2e4 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs @@ -12,7 +12,7 @@ type internal FSharpBraceMatchingService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "BraceMatching" diff --git a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs index ed7d2a7b827..9162f31e48b 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs @@ -18,7 +18,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices [, FSharpConstants.FSharpLanguageName)>] type internal FSharpIndentationService [] - (projectInfoManager: FSharpProjectOptionsManager) = + (projectInfoManager: ProjectInfoManager) = static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, optionsOpt: FSharpProjectOptions option): Option = // Match indentation with previous line diff --git a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs index d2f804ebe55..15fa5df1328 100644 --- a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs +++ b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs @@ -73,7 +73,7 @@ type internal InlineRenameLocationSet(locationsByDocument: DocumentLocations [], type internal InlineRenameInfo ( checker: FSharpChecker, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, document: Document, triggerSpan: TextSpan, lexerSymbol: LexerSymbol, @@ -141,13 +141,13 @@ type internal InlineRenameInfo type internal InlineRenameService [] ( - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, checkerProvider: FSharpCheckerProvider, [] _refactorNotifyServices: seq ) = static let userOpName = "InlineRename" - static member GetInlineRenameInfo(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager, document: Document, sourceText: SourceText, position: int, + static member GetInlineRenameInfo(checker: FSharpChecker, projectInfoManager: ProjectInfoManager, document: Document, sourceText: SourceText, position: int, defines: string list, options: FSharpProjectOptions) : Async = asyncMaybe { let textLine = sourceText.Lines.GetLineFromPosition(position) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index cd4281e4ab6..55c7119cfee 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -7,11 +7,13 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System open System.Collections.Concurrent open System.Collections.Generic +open System.Collections.Immutable open System.ComponentModel.Composition +open System.Diagnostics +open System.IO +open System.Linq open System.Runtime.CompilerServices open System.Runtime.InteropServices -open System.IO -open System.Diagnostics open Microsoft.FSharp.Compiler.CompileOps open Microsoft.FSharp.Compiler.SourceCodeServices @@ -23,6 +25,7 @@ open Microsoft.CodeAnalysis.Options open Microsoft.VisualStudio open Microsoft.VisualStudio.Editor open Microsoft.VisualStudio.TextManager.Interop +open Microsoft.VisualStudio.LanguageServices open Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList @@ -32,6 +35,11 @@ open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.LanguageService open Microsoft.VisualStudio.ComponentModelHost +module LogFile = + let log (text:string) = + use logfile = File.AppendText(@"c:\temp\mylogfile.log") + logfile.WriteLine(text) + // Exposes FSharpChecker as MEF export [); Composition.Shared>] type internal FSharpCheckerProvider @@ -78,7 +86,6 @@ type internal FSharpCheckerProvider member this.Checker = checker.Value - /// A value and a function to recompute/refresh the value. The function is passed a flag indicating if a refresh is happening. type Refreshable<'T> = 'T * (bool -> 'T) @@ -89,24 +96,28 @@ type Refreshable<'T> = 'T * (bool -> 'T) // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject. -[); Composition.Shared>] -type internal FSharpProjectOptionsManager +[); Composition.Shared>] +type internal ProjectInfoManager [] ( checkerProvider: FSharpCheckerProvider, [)>] serviceProvider: System.IServiceProvider ) = - // A table of information about projects, excluding single-file projects. + // A table of information about projects, excluding single-file projects. let projectTable = ConcurrentDictionary>() // A table of information about single-file projects. Currently we only need the load time of each such file, plus // the original options for editing let singleFileProjectTable = ConcurrentDictionary() + // Accumulate sorces and references for each project file + let projectInfo = new ConcurrentDictionary() + /// Clear a project from the project table member this.ClearInfoForProject(projectId: ProjectId) = projectTable.TryRemove(projectId) |> ignore this.RefreshInfoForProjectsThatReferenceThisProject(projectId) + //@@@@@@@ sourceFiles / referenceFiles / commandlineOptions member this.ClearInfoForSingleFileProject(projectId) = singleFileProjectTable.TryRemove(projectId) |> ignore @@ -204,20 +215,34 @@ type internal FSharpProjectOptionsManager | true, (_loadTime, originalOptions) -> Some originalOptions | _ -> this.TryGetOptionsForProject(projectId) + [] + member this.HandleCommandLineChanges(path:string, sources:ImmutableArray, references:ImmutableArray, options:ImmutableArray) = + let fullPath p = + if Path.IsPathRooted(p) then p + else Path.Combine(Path.GetDirectoryName(path), p) + let sourcePaths = sources |> Seq.map(fun s -> fullPath s.Path) |> Seq.toArray + let referencePaths = references |> Seq.map(fun r -> fullPath r.Reference) |> Seq.toArray + projectInfo.[path] <- (sourcePaths,referencePaths,options.ToArray()) + () + + member __.GetProjectInfo(path:string) = + match projectInfo.TryGetValue path with + | true, value -> value + | _ -> Array.empty, Array.empty, Array.empty + // Used to expose FSharpChecker/ProjectInfo manager to diagnostic providers // Diagnostic providers can be executed in environment that does not use MEF so they can rely only // on services exposed by the workspace type internal FSharpCheckerWorkspaceService = inherit Microsoft.CodeAnalysis.Host.IWorkspaceService abstract Checker: FSharpChecker - abstract FSharpProjectOptionsManager: FSharpProjectOptionsManager + abstract ProjectInfoManager: ProjectInfoManager type internal RoamingProfileStorageLocation(keyName: string) = inherit OptionStorageLocation() member __.GetKeyNameForLanguage(languageName: string) = let unsubstitutedKeyName = keyName - match languageName with | null -> unsubstitutedKeyName | _ -> @@ -230,13 +255,13 @@ type internal FSharpCheckerWorkspaceServiceFactory [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = interface Microsoft.CodeAnalysis.Host.Mef.IWorkspaceServiceFactory with member this.CreateService(_workspaceServices) = upcast { new FSharpCheckerWorkspaceService with member this.Checker = checkerProvider.Checker - member this.FSharpProjectOptionsManager = projectInfoManager } + member this.ProjectInfoManager = projectInfoManager } type [] @@ -266,21 +291,15 @@ type override this.Initialize() = base.Initialize() - //initialize settings this.ComponentModel.GetService() |> ignore override this.RoslynLanguageName = FSharpConstants.FSharpLanguageName - override this.CreateWorkspace() = this.ComponentModel.GetService() - - override this.CreateLanguageService() = - FSharpLanguageService(this) - + override this.CreateLanguageService() = FSharpLanguageService(this) override this.CreateEditorFactories() = Seq.empty - override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = () - -and + +and [] [, ".fs")>] [, ".fsi")>] @@ -297,7 +316,7 @@ and internal FSharpLanguageService(package : FSharpPackage) = inherit AbstractLanguageService(package) - let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value + let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value let projectDisplayNameOf projectFileName = if String.IsNullOrWhiteSpace projectFileName then projectFileName @@ -321,15 +340,93 @@ and let optionsAssociation = ConditionalWeakTable() + member private this.ProvideProjectSiteProvider(workspace:Workspace, project:Project) = + let visualStudioWorkspace = workspace :?> VisualStudioWorkspace + let hier = visualStudioWorkspace.GetHierarchy(project.Id) + + {new IProvideProjectSite with + member iProvideProjectSite.GetProjectSite() = + let sources () = + let items,_,_ = projectInfoManager.GetProjectInfo(project.FilePath) + items + let references () = + let _,items,_ = projectInfoManager.GetProjectInfo(project.FilePath) + items + let options () = + let _,_,items = projectInfoManager.GetProjectInfo(project.FilePath) + items + let caption () = project.Name + let projFileName () = project.FilePath + let targetFrameworkMoniker = "" + let projectGuid () = project.Id.Id.ToString() + let creationTime = System.DateTime.Now + let mutable errorReporter = + let reporter = ProjectExternalErrorReporter(project.Id, "FS", this.SystemServiceProvider) + Some(reporter:> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) + + {new Microsoft.VisualStudio.FSharp.LanguageService.IProjectSite with + member __.SourceFilesOnDisk() = sources () + member __.DescriptionOfProject() = caption () + member __.CompilerFlags() = options () + member __.ProjectFileName() = projFileName () + member __.AdviseProjectSiteChanges(_,_) = () + member __.AdviseProjectSiteCleaned(_,_) = () + member __.AdviseProjectSiteClosed(_,_) = () + member __.IsIncompleteTypeCheckEnvironment = false + member __.TargetFrameworkMoniker = targetFrameworkMoniker + member __.ProjectGuid = projectGuid () + member __.LoadTime = creationTime + member __.ProjectProvider = Some iProvideProjectSite + member __.AssemblyReferences() = references () + member __.BuildErrorReporter with get () = errorReporter and + set (v) = errorReporter <- v + } + + interface IVsHierarchy with + member __.SetSite(psp) = hier.SetSite(psp) + member __.GetSite(psp) = hier.GetSite(ref psp) + member __.QueryClose(pfCanClose) = hier.QueryClose(ref pfCanClose) + member __.Close() = hier.Close() + member __.GetGuidProperty(itemid, propid, pguid) = hier.GetGuidProperty(itemid, propid, ref pguid) + member __.SetGuidProperty(itemid, propid, rguid) = hier.SetGuidProperty(itemid, propid, ref rguid) + member __.GetProperty(itemid, propid, pvar) = hier.GetProperty(itemid, propid, ref pvar) + member __.SetProperty(itemid, propid, var) = hier.SetProperty(itemid, propid, var) + member __.GetNestedHierarchy(itemid, iidHierarchyNested, ppHierarchyNested, pitemidNested) = hier.GetNestedHierarchy(itemid, ref iidHierarchyNested, ref ppHierarchyNested, ref pitemidNested) + member __.GetCanonicalName(itemid, pbstrName) = hier.GetCanonicalName(itemid, ref pbstrName) + member __.ParseCanonicalName(pszName, pitemid) = hier.ParseCanonicalName(pszName, ref pitemid) + member __.Unused0() = hier.Unused0() + member __.AdviseHierarchyEvents(pEventSink, pdwCookie) = hier.AdviseHierarchyEvents(pEventSink, ref pdwCookie) + member __.UnadviseHierarchyEvents(dwCookie) = hier.UnadviseHierarchyEvents(dwCookie) + member __.Unused1() = hier.Unused1() + member __.Unused2() = hier.Unused2() + member __.Unused3() = hier.Unused3() + member __.Unused4() = hier.Unused4() + } + + //member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = + // let project = this.Workspace.CurrentSolution.GetProject(projectId) + // let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) + // this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + + //member private this.OnProjectAdded(projectId:ProjectId, newSolution:Solution) = this.OnProjectChanged(projectId, newSolution) + + //member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () + override this.Initialize() = base.Initialize() + //let workspaceChanged (args:WorkspaceChangeEventArgs) = + // match args.Kind with + // | WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution) + // | WorkspaceChangeKind.ProjectChanged -> this.OnProjectChanged(args.ProjectId, args.NewSolution) + // | WorkspaceChangeKind.ProjectRemoved -> this.OnProjectRemoved(args.ProjectId, args.NewSolution) + // | _ -> () + this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false) + //this.Workspace.WorkspaceChanged.Add(workspaceChanged) + this.Workspace.DocumentClosed.Add <| fun args -> tryRemoveSingleFileProject args.Document.Project.Id - this.Workspace.DocumentClosed.Add <| fun args -> - tryRemoveSingleFileProject args.Document.Project.Id - Events.SolutionEvents.OnAfterCloseSolution.Add <| fun _ -> //checkerProvider.Checker.StopBackgroundCompile() @@ -342,7 +439,7 @@ and singleFileProjects.Keys |> Seq.iter tryRemoveSingleFileProject let ctx = System.Threading.SynchronizationContext.Current - + let rec setupProjectsAfterSolutionOpen() = async { use openedProjects = MailboxProcessor.Start <| fun inbox -> @@ -368,27 +465,27 @@ and let theme = package.ComponentModel.DefaultExportProvider.GetExport().Value theme.SetColors() - + /// Sync the information for the project - member this.SyncProject(project: AbstractProject, projectContext: IWorkspaceProjectContext, site: IProjectSite, workspace, forceUpdate, userOpName) = + member __.SyncProject(project: AbstractProject, projectContext: IWorkspaceProjectContext, site: IProjectSite, workspace, forceUpdate, userOpName) = let wellFormedFilePathSetIgnoreCase (paths: seq) = HashSet(paths |> Seq.filter isPathWellFormed |> Seq.map (fun s -> try System.IO.Path.GetFullPath(s) with _ -> s), StringComparer.OrdinalIgnoreCase) let updatedFiles = site.SourceFilesOnDisk() |> wellFormedFilePathSetIgnoreCase let originalFiles = project.GetCurrentDocuments() |> Seq.map (fun file -> file.FilePath) |> wellFormedFilePathSetIgnoreCase - + let mutable updated = forceUpdate for file in updatedFiles do if not(originalFiles.Contains(file)) then projectContext.AddSourceFile(file) updated <- true - + for file in originalFiles do if not(updatedFiles.Contains(file)) then projectContext.RemoveSourceFile(file) updated <- true - + let updatedRefs = site.AssemblyReferences() |> wellFormedFilePathSetIgnoreCase let originalRefs = project.GetCurrentMetadataReferences() |> Seq.map (fun ref -> ref.FilePath) |> wellFormedFilePathSetIgnoreCase @@ -431,11 +528,10 @@ and let projectGuid = Guid(site.ProjectGuid) let projectFileName = site.ProjectFileName() let projectDisplayName = projectDisplayNameOf projectFileName - let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) if isNull (workspace.ProjectTracker.GetProject projectId) then - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) let projectContextFactory = package.ComponentModel.GetService(); let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) @@ -454,11 +550,8 @@ and FSharpConstants.FSharpLanguageName, projectDisplayName, projectFileName, projectGuid, hierarchy, null, errorReporter) let project = projectContext :?> AbstractProject - this.SyncProject(project, projectContext, site, workspace, forceUpdate=false, userOpName=userOpName) - - site.BuildErrorReporter <- Some (errorReporter :> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) - + site.BuildErrorReporter <- Some(errorReporter :> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) site.AdviseProjectSiteChanges(FSharpConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site, workspace, forceUpdate=true, userOpName="AdviseProjectSiteChanges."+userOpName))) site.AdviseProjectSiteClosed(FSharpConstants.FSharpLanguageServiceCallbackName, @@ -466,6 +559,7 @@ and projectInfoManager.ClearInfoForProject(project.Id) optionsAssociation.Remove(projectContext) |> ignore project.Disconnect())) + for referencedSite in ProjectSitesAndFiles.GetReferencedProjectSites (site, this.SystemServiceProvider) do let referencedProjectId = setup referencedSite project.AddProjectReference(ProjectReference referencedProjectId) @@ -513,12 +607,20 @@ and match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with | Some (hier, _) -> match hier with - | :? IProvideProjectSite as siteProvider when not (IsScript(filename)) -> + | :? IProvideProjectSite as siteProvider when not (IsScript(filename)) -> this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") - | _ -> + | _ when not (IsScript(filename)) -> + let docId = this.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(filename).FirstOrDefault() + match docId with + | null -> + let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) + this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) + | id -> + let project = this.Workspace.CurrentSolution.GetProject(id.ProjectId) + let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) + this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) | _ -> () | _ -> () - - diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 5af7e9038a0..93052bddff3 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -16,7 +16,7 @@ open Microsoft.VisualStudio.FSharp.Editor.Symbols module internal SymbolHelpers = let getSymbolUsesInSolution (symbol: FSharpSymbol, declLoc: SymbolDeclarationLocation, checkFileResults: FSharpCheckFileResults, - projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, solution: Solution, userOpName) = + projectInfoManager: ProjectInfoManager, checker: FSharpChecker, solution: Solution, userOpName) = async { let! symbolUses = match declLoc with @@ -63,7 +63,7 @@ module internal SymbolHelpers = type OriginalText = string - let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, userOpName) + let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: ProjectInfoManager, checker: FSharpChecker, userOpName) : Async<(Func> * OriginalText) option> = asyncMaybe { do! Option.guard (symbolSpan.Length > 0) diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index b964f1d2eff..46e6bf5946f 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -20,7 +20,7 @@ type internal FSharpFindUsagesService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "FindUsages" diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 9b7b12aecd6..7d296edef06 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -33,7 +33,7 @@ type internal FSharpNavigableItem(document: Document, textSpan: TextSpan) = member this.DisplayTaggedParts = ImmutableArray.Empty member this.ChildItems = ImmutableArray.Empty -type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager) = +type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: ProjectInfoManager) = static let userOpName = "GoToDefinition" @@ -239,7 +239,7 @@ type internal FSharpGoToDefinitionService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "GoToDefinition" diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index d84202eac73..d29c85e724b 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -182,7 +182,7 @@ type internal FSharpNavigateToSearchService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = let itemsByDocumentId = ConditionalWeakTable() diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs index 7e0fdac0def..bd8f3cc64bd 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs @@ -23,7 +23,7 @@ type internal FSharpNavigationBarItemService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static let userOpName = "NavigationBarItem" diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 1324602ffb2..97b40efac68 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -38,7 +38,7 @@ module private FSharpQuickInfo = let getTooltipFromRange ( checker: FSharpChecker, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, document: Document, declRange: range, cancellationToken: CancellationToken @@ -82,7 +82,7 @@ module private FSharpQuickInfo = let getTooltipInfo ( checker: FSharpChecker, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, document: Document, position: int, cancellationToken: CancellationToken @@ -162,7 +162,7 @@ type internal FSharpQuickInfoProvider ( [)>] serviceProvider: IServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager, + projectInfoManager: ProjectInfoManager, gotoDefinitionService: FSharpGoToDefinitionService, viewProvider: QuickInfoViewProvider ) = diff --git a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs index 68a41f19e6d..30eced943b2 100644 --- a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs +++ b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs @@ -139,7 +139,7 @@ module internal BlockStructure = open BlockStructure -type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager) = +type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoManager: ProjectInfoManager) = inherit BlockStructureService() static let userOpName = "BlockStructure" @@ -158,7 +158,7 @@ type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoMan |> RoslynHelpers.StartAsyncAsTask(cancellationToken) [, FSharpConstants.FSharpLanguageName); Shared>] -type internal FSharpBlockStructureServiceFactory [](checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager) = +type internal FSharpBlockStructureServiceFactory [](checkerProvider: FSharpCheckerProvider, projectInfoManager: ProjectInfoManager) = interface ILanguageServiceFactory with member __.CreateLanguageService(_languageServices) = upcast FSharpBlockStructureService(checkerProvider.Checker, projectInfoManager) \ No newline at end of file diff --git a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs index 7d91599a789..b6ee14a600f 100644 --- a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs +++ b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs @@ -14,7 +14,7 @@ // through the nodes of the hierarchy for the F# project. There seems to be an essentially duplicated // version of this code in this file. // -// In our LanguageService.fs, FSharpProjectOptionsManager uses this IProjectSite information to incrementally maintain +// In our LanguageService.fs, ProjectInfoManager uses this IProjectSite information to incrementally maintain // a corresponding F# CompilerService FSharpProjectOptions value. // // In our LanguageService.fs, we also use this IProjectSite information to maintain a @@ -27,7 +27,7 @@ // project.AddProjectReference // // The new F# project system supplies the project information using a Roslyn project in the workspace. -// This means a lot of the stuff above is irrelevant in that case, apart from where FSharpProjectOptionsManager +// This means a lot of the stuff above is irrelevant in that case, apart from where ProjectInfoManager // incrementally maintains a corresponding F# CompilerService FSharpProjectOptions value. namespace Microsoft.VisualStudio.FSharp.LanguageService @@ -39,6 +39,7 @@ open System.Runtime.InteropServices open Microsoft.VisualStudio open Microsoft.VisualStudio.TextManager.Interop open Microsoft.VisualStudio.Shell.Interop +open Microsoft.FSharp.Compiler.Range open Microsoft.FSharp.Compiler.SourceCodeServices /// An additional interface that an IProjectSite object can implement to indicate it has an FSharpProjectOptions @@ -46,7 +47,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices type private IHaveCheckOptions = abstract OriginalCheckOptions : unit -> string[] * FSharpProjectOptions -/// Convert from FSharpProjectOptions into IProjectSite. +/// Convert from FSharpProjectOptions into IProjectSite. type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames, checkOptions : FSharpProjectOptions) = interface IProjectSite with override this.SourceFilesOnDisk() = checkOptions.SourceFiles @@ -62,7 +63,8 @@ type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames override this.ProjectGuid = "" override this.LoadTime = checkOptions.LoadTime override this.ProjectProvider = None - override this.AssemblyReferences() = [||] + override this.AssemblyReferences() = checkOptions.OriginalLoadReferences |> List.map(fun (_,p) -> p) |> List.toArray + interface IHaveCheckOptions with override this.OriginalCheckOptions() = (referencedProjectFileNames, checkOptions) @@ -182,7 +184,7 @@ type internal ProjectSitesAndFiles() = UseScriptResolutionRules = SourceFile.MustBeSingleFileProject fileName LoadTime = projectSite.LoadTime UnresolvedReferences = None - OriginalLoadReferences = [] + OriginalLoadReferences = (projectSite.AssemblyReferences() |> Array.map(fun s -> rangeCmdArgs, s) |> Array.toList) ExtraProjectInfo=extraProjectInfo Stamp = (if useUniqueStamp then (stamp <- stamp + 1L; Some stamp) else None) } referencedProjectFileNames, options @@ -192,10 +194,8 @@ type internal ProjectSitesAndFiles() = if SourceFile.MustBeSingleFileProject(filename) then Debug.Assert(false, ".fsx or .fsscript should have been treated as implicit project") failwith ".fsx or .fsscript should have been treated as implicit project" - new ProjectSiteOfSingleFile(filename) :> IProjectSite - - + static member GetReferencedProjectSites(projectSite:IProjectSite, serviceProvider:System.IServiceProvider) = referencedProvideProjectSites (projectSite, serviceProvider) |> Seq.map (fun (_, ps) -> ps.GetProjectSite()) From ad481939dcb56b02e135cebc2502987550bdd563 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Sat, 9 Sep 2017 00:34:38 -0700 Subject: [PATCH 02/13] SDK editor support --- src/fsharp/fsi/fsi.fs | 1 - src/fsharp/vs/IncrementalBuild.fs | 34 +++++-- src/fsharp/vs/service.fs | 4 +- .../LanguageService/LanguageService.fs | 94 +++++++++---------- 4 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index dd2714b6b7a..b9331351ffe 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -2468,7 +2468,6 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do tcConfigB.resolutionEnvironment <- ResolutionEnvironment.EditingOrCompilation false do tcConfigB.useSimpleResolution <- true do SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen - //do SetTargetProfile tcConfigB "privatecorelib" // always assume System.Private.CoreLib codegen #endif // Preset: --optimize+ -g --tailcalls+ (see 4505) diff --git a/src/fsharp/vs/IncrementalBuild.fs b/src/fsharp/vs/IncrementalBuild.fs index 8764878737f..312b5dc3649 100755 --- a/src/fsharp/vs/IncrementalBuild.fs +++ b/src/fsharp/vs/IncrementalBuild.fs @@ -1681,8 +1681,11 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. static member TryCreateBackgroundBuilderForProjectOptions (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, frameworkTcImportsCache: FrameworkImportsCache, loadClosureOpt:LoadClosure option, sourceFiles:string list, commandLineArgs:string list, projectReferences, projectDirectory, useScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds) = + let targetProfileSwitch = "--targetprofile:" + let useSimpleResolutionSwitch = "--simpleresolution" + cancellable { - + // Trap and report warnings and errors from creation. use errorScope = new ErrorScope() let! builderOpt = @@ -1695,23 +1698,38 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs /// Create a type-check configuration let tcConfigB, sourceFilesNew = - + + let getSwitchValue switchstring = + match commandLineArgs |> Seq.tryFindIndex(fun s -> s.StartsWith(switchstring)) with + | Some idx -> Some(commandLineArgs.[idx].Substring(switchstring.Length)) + | _ -> None + // see also fsc.fs:runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB let tcConfigB = TcConfigBuilder.CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, implicitIncludeDir=projectDirectory, optimizeForMemory=true, isInteractive=false, isInvalidationSupported=true, defaultCopyFSharpCore=false) + // The following uses more memory but means we don't take read-exclusions on the DLLs we reference // Could detect well-known assemblies--ie System.dll--and open them with read-locks tcConfigB.openBinariesInMemory <- true tcConfigB.resolutionEnvironment <- (ReferenceResolver.ResolutionEnvironment.EditingOrCompilation true) - + tcConfigB.conditionalCompilationDefines <- let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED" define::tcConfigB.conditionalCompilationDefines tcConfigB.projectReferences <- projectReferences + #if COMPILER_SERVICE_ASSUMES_DOTNETCORE_COMPILATION tcConfigB.useSimpleResolution <- true // turn off msbuild resolution +#else + tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome #endif + match (getSwitchValue targetProfileSwitch) with + | Some v -> + let _s = v + CompileOptions.SetTargetProfile tcConfigB v + | None -> () + // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = try @@ -1725,12 +1743,16 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs // Never open PDB files for the language service, even if --standalone is specified tcConfigB.openDebugInformationForLaterStaticLinking <- false - + match commandLineArgs |> Seq.tryFindIndex(fun s -> s.StartsWith(targetProfileSwitch)) with + | Some idx -> + let profile = commandLineArgs.[idx].Substring(targetProfileSwitch.Length) + CompileOptions.SetTargetProfile tcConfigB profile + | _ -> () tcConfigB, sourceFilesNew match loadClosureOpt with - | Some loadClosure -> - let dllReferences = + | Some loadClosure -> + let dllReferences = [for reference in tcConfigB.referencedDLLs do // If there's (one or more) resolutions of closure references then yield them all match loadClosure.References |> List.tryFind (fun (resolved,_)->resolved=reference.Text) with diff --git a/src/fsharp/vs/service.fs b/src/fsharp/vs/service.fs index ea92c92f9ae..f8e1dac2df8 100644 --- a/src/fsharp/vs/service.fs +++ b/src/fsharp/vs/service.fs @@ -3139,7 +3139,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio let loadClosure = LoadClosure.ComputeClosureOfSourceText(ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, source, CodeContext.Editing, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework) let! tcErrors, tcFileResult = Parser.CheckOneFile(parseResults, source, filename, "project", tcConfig, tcGlobals, tcImports, tcState, Some loadClosure, backgroundDiagnostics, reactorOps, (fun () -> true), None, userOpName) - + return match tcFileResult with | Parser.TypeCheckAborted.No scope -> @@ -3150,7 +3150,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio | _ -> failwith "unexpected aborted" } - + //---------------------------------------------------------------------------- // CompilerEnvironment, DebuggerEnvironment // diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 55c7119cfee..52ff554f9f6 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -64,23 +64,22 @@ type internal FSharpCheckerProvider // When the F# background builder refreshes the background semantic build context for a file, // we request Roslyn to reanalyze that individual file. checker.BeforeBackgroundFileCheck.Add(fun (fileName, extraProjectInfo) -> - async { - try - match extraProjectInfo with - | Some (:? Workspace as workspace) -> - let solution = workspace.CurrentSolution - let documentIds = solution.GetDocumentIdsWithFilePath(fileName) - if not documentIds.IsEmpty then - let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray - for documentId in docuentIdsFiltered do - Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) - if docuentIdsFiltered.Length > 0 then - analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) - | _ -> () - with ex -> - Assert.Exception(ex) - } |> Async.StartImmediate - ) + async { + try + match extraProjectInfo with + | Some (:? Workspace as workspace) -> + let solution = workspace.CurrentSolution + let documentIds = solution.GetDocumentIdsWithFilePath(fileName) + if not documentIds.IsEmpty then + let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray + for documentId in docuentIdsFiltered do + Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) + if docuentIdsFiltered.Length > 0 then + analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) + | _ -> () + with ex -> + Assert.Exception(ex) + } |> Async.StartImmediate ) checker member this.Checker = checker.Value @@ -350,11 +349,11 @@ and let items,_,_ = projectInfoManager.GetProjectInfo(project.FilePath) items let references () = - let _,items,_ = projectInfoManager.GetProjectInfo(project.FilePath) - items + let _,references,_ = projectInfoManager.GetProjectInfo(project.FilePath) + references let options () = - let _,_,items = projectInfoManager.GetProjectInfo(project.FilePath) - items + let _,references,options = projectInfoManager.GetProjectInfo(project.FilePath) + Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] let caption () = project.Name let projFileName () = project.FilePath let targetFrameworkMoniker = "" @@ -403,28 +402,26 @@ and member __.Unused4() = hier.Unused4() } - //member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = - // let project = this.Workspace.CurrentSolution.GetProject(projectId) - // let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) - // this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") - - //member private this.OnProjectAdded(projectId:ProjectId, newSolution:Solution) = this.OnProjectChanged(projectId, newSolution) - - //member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () + member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = + let project = this.Workspace.CurrentSolution.GetProject(projectId) + let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) + this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + member private this.OnProjectAdded(projectId:ProjectId, newSolution:Solution) = this.OnProjectChanged(projectId, newSolution) + member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () override this.Initialize() = base.Initialize() - //let workspaceChanged (args:WorkspaceChangeEventArgs) = - // match args.Kind with - // | WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution) - // | WorkspaceChangeKind.ProjectChanged -> this.OnProjectChanged(args.ProjectId, args.NewSolution) - // | WorkspaceChangeKind.ProjectRemoved -> this.OnProjectRemoved(args.ProjectId, args.NewSolution) - // | _ -> () + let workspaceChanged (args:WorkspaceChangeEventArgs) = + match args.Kind with + | WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution) + | WorkspaceChangeKind.ProjectChanged -> this.OnProjectChanged(args.ProjectId, args.NewSolution) + | WorkspaceChangeKind.ProjectRemoved -> this.OnProjectRemoved(args.ProjectId, args.NewSolution) + | _ -> () this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Shared.Options.ServiceFeatureOnOffOptions.ClosedFileDiagnostic, FSharpConstants.FSharpLanguageName, Nullable false) - //this.Workspace.WorkspaceChanged.Add(workspaceChanged) + this.Workspace.WorkspaceChanged.Add(workspaceChanged) this.Workspace.DocumentClosed.Add <| fun args -> tryRemoveSingleFileProject args.Document.Project.Id Events.SolutionEvents.OnAfterCloseSolution.Add <| fun _ -> @@ -529,27 +526,28 @@ and let projectFileName = site.ProjectFileName() let projectDisplayName = projectDisplayNameOf projectFileName let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) - + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) - if isNull (workspace.ProjectTracker.GetProject projectId) then - let projectContextFactory = package.ComponentModel.GetService(); - let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) + let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) - let hierarchy = - site.ProjectProvider - |> Option.map (fun p -> p :?> IVsHierarchy) - |> Option.toObj + let hierarchy = + site.ProjectProvider + |> Option.map (fun p -> p :?> IVsHierarchy) + |> Option.toObj - // Roslyn is expecting site to be an IVsHierarchy. - // It just so happens that the object that implements IProvideProjectSite is also - // an IVsHierarchy. This assertion is to ensure that the assumption holds true. - Debug.Assert(hierarchy <> null, "About to CreateProjectContext with a non-hierarchy site") + // Roslyn is expecting site to be an IVsHierarchy. + // It just so happens that the object that implements IProvideProjectSite is also + // an IVsHierarchy. This assertion is to ensure that the assumption holds true. + Debug.Assert(hierarchy <> null, "About to CreateProjectContext with a non-hierarchy site") + if isNull (workspace.ProjectTracker.GetProject projectId) then + let projectContextFactory = package.ComponentModel.GetService() let projectContext = projectContextFactory.CreateProjectContext( FSharpConstants.FSharpLanguageName, projectDisplayName, projectFileName, projectGuid, hierarchy, null, errorReporter) let project = projectContext :?> AbstractProject + this.SyncProject(project, projectContext, site, workspace, forceUpdate=false, userOpName=userOpName) site.BuildErrorReporter <- Some(errorReporter :> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) site.AdviseProjectSiteChanges(FSharpConstants.FSharpLanguageServiceCallbackName, From 62e24ca2776c89a68991a7a9e9ed9055205c0741 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Mon, 11 Sep 2017 11:16:22 -0700 Subject: [PATCH 03/13] Address merge issues --- .../src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs | 2 +- .../src/FSharp.Editor/Formatting/EditorFormattingService.fs | 2 +- .../src/FSharp.Editor/LanguageService/SymbolHelpers.fs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs index ea2ba70d2a3..a7e70b22417 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs @@ -21,7 +21,7 @@ type internal FSharpRenameParamToMatchSignature [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs index 0abbd0abddf..292155b12d3 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs @@ -20,7 +20,7 @@ type internal FSharpEditorFormattingService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: FSharpProjectOptionsManager + projectInfoManager: ProjectInfoManager ) = static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, projectOptions: FSharpProjectOptions option, position: int) = diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 3970a6128b8..0ca982b41a5 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -21,7 +21,7 @@ module internal SymbolHelpers = open Microsoft.CodeAnalysis.CodeActions /// Used for local code fixes in a document, e.g. to rename local parameters - let getSymbolUsesOfSymbolAtLocationInDocument (document: Document, position: int, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, userOpName) = + let getSymbolUsesOfSymbolAtLocationInDocument (document: Document, position: int, projectInfoManager: ProjectInfoManager, checker: FSharpChecker, userOpName) = asyncMaybe { let! cancellationToken = Async.CancellationToken |> liftAsync let! sourceText = document.GetTextAsync(cancellationToken) @@ -95,7 +95,7 @@ module internal SymbolHelpers = // A better approach is to use something like createTextChangeCodeFix below, with a delayed function to compute a set of changes to be applied // simultaneously. But that doesn't work for this case, as we want a set of changes to apply acrosss the whole solution. - let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, userOpName) + let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: ProjectInfoManager, checker: FSharpChecker, userOpName) : Async<(Func> * OriginalText) option> = asyncMaybe { do! Option.guard (symbolSpan.Length > 0) From 300956755296e8d8f4f3615ee7fa7dd200f338f7 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Mon, 11 Sep 2017 12:25:45 -0700 Subject: [PATCH 04/13] Feedback --- .../LanguageService/LanguageService.fs | 82 +++++++++---------- .../ProjectSitesAndFiles.fs | 6 +- 2 files changed, 39 insertions(+), 49 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 52ff554f9f6..1385062e061 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -35,11 +35,6 @@ open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.LanguageService open Microsoft.VisualStudio.ComponentModelHost -module LogFile = - let log (text:string) = - use logfile = File.AppendText(@"c:\temp\mylogfile.log") - logfile.WriteLine(text) - // Exposes FSharpChecker as MEF export [); Composition.Shared>] type internal FSharpCheckerProvider @@ -65,21 +60,22 @@ type internal FSharpCheckerProvider // we request Roslyn to reanalyze that individual file. checker.BeforeBackgroundFileCheck.Add(fun (fileName, extraProjectInfo) -> async { - try - match extraProjectInfo with - | Some (:? Workspace as workspace) -> - let solution = workspace.CurrentSolution - let documentIds = solution.GetDocumentIdsWithFilePath(fileName) - if not documentIds.IsEmpty then - let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray - for documentId in docuentIdsFiltered do - Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) - if docuentIdsFiltered.Length > 0 then - analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) - | _ -> () - with ex -> - Assert.Exception(ex) - } |> Async.StartImmediate ) + try + match extraProjectInfo with + | Some (:? Workspace as workspace) -> + let solution = workspace.CurrentSolution + let documentIds = solution.GetDocumentIdsWithFilePath(fileName) + if not documentIds.IsEmpty then + let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray + for documentId in docuentIdsFiltered do + Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) + if docuentIdsFiltered.Length > 0 then + analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) + | _ -> () + with ex -> + Assert.Exception(ex) + } |> Async.StartImmediate + ) checker member this.Checker = checker.Value @@ -109,14 +105,13 @@ type internal ProjectInfoManager // the original options for editing let singleFileProjectTable = ConcurrentDictionary() - // Accumulate sorces and references for each project file + // Accumulate sources and references for each project file let projectInfo = new ConcurrentDictionary() /// Clear a project from the project table member this.ClearInfoForProject(projectId: ProjectId) = projectTable.TryRemove(projectId) |> ignore this.RefreshInfoForProjectsThatReferenceThisProject(projectId) - //@@@@@@@ sourceFiles / referenceFiles / commandlineOptions member this.ClearInfoForSingleFileProject(projectId) = singleFileProjectTable.TryRemove(projectId) |> ignore @@ -345,42 +340,33 @@ and {new IProvideProjectSite with member iProvideProjectSite.GetProjectSite() = - let sources () = - let items,_,_ = projectInfoManager.GetProjectInfo(project.FilePath) - items - let references () = - let _,references,_ = projectInfoManager.GetProjectInfo(project.FilePath) - references - let options () = - let _,references,options = projectInfoManager.GetProjectInfo(project.FilePath) - Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] - let caption () = project.Name - let projFileName () = project.FilePath - let targetFrameworkMoniker = "" - let projectGuid () = project.Id.Id.ToString() - let creationTime = System.DateTime.Now + let fst (a, _, _) = a + let thrd (_, _, c) = c let mutable errorReporter = let reporter = ProjectExternalErrorReporter(project.Id, "FS", this.SystemServiceProvider) Some(reporter:> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) {new Microsoft.VisualStudio.FSharp.LanguageService.IProjectSite with - member __.SourceFilesOnDisk() = sources () - member __.DescriptionOfProject() = caption () - member __.CompilerFlags() = options () - member __.ProjectFileName() = projFileName () + member __.SourceFilesOnDisk() = projectInfoManager.GetProjectInfo(project.FilePath) |> fst + member __.DescriptionOfProject() = project.Name + member __.CompilerFlags() = + let _,references,options = projectInfoManager.GetProjectInfo(project.FilePath) + Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] + member __.ProjectFileName() = project.FilePath member __.AdviseProjectSiteChanges(_,_) = () member __.AdviseProjectSiteCleaned(_,_) = () member __.AdviseProjectSiteClosed(_,_) = () member __.IsIncompleteTypeCheckEnvironment = false - member __.TargetFrameworkMoniker = targetFrameworkMoniker - member __.ProjectGuid = projectGuid () - member __.LoadTime = creationTime + member __.TargetFrameworkMoniker = "" + member __.ProjectGuid = project.Id.Id.ToString() + member __.LoadTime = System.DateTime.Now member __.ProjectProvider = Some iProvideProjectSite - member __.AssemblyReferences() = references () + member __.AssemblyReferences() = projectInfoManager.GetProjectInfo(project.FilePath) |> thrd member __.BuildErrorReporter with get () = errorReporter and set (v) = errorReporter <- v } + // TODO: figure out why this is necessary interface IVsHierarchy with member __.SetSite(psp) = hier.SetSite(psp) member __.GetSite(psp) = hier.GetSite(ref psp) @@ -598,10 +584,16 @@ and base.SetupNewTextView(textView) let textViewAdapter = package.ComponentModel.GetService() - + match textView.GetBuffer() with | (VSConstants.S_OK, textLines) -> let filename = VsTextLines.GetFilename textLines + + + // CPS projects don't implement IProvideProjectSite and IVSProjectHierarchy + // Simple explanation: + // Legacy projects have IVSHierarchy and IPRojectSite + // CPS Projects and loose script files don't match VsRunningDocumentTable.FindDocumentWithoutLocking(package.RunningDocumentTable,filename) with | Some (hier, _) -> match hier with diff --git a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs index b6ee14a600f..92d84db54be 100644 --- a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs +++ b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs @@ -39,7 +39,6 @@ open System.Runtime.InteropServices open Microsoft.VisualStudio open Microsoft.VisualStudio.TextManager.Interop open Microsoft.VisualStudio.Shell.Interop -open Microsoft.FSharp.Compiler.Range open Microsoft.FSharp.Compiler.SourceCodeServices /// An additional interface that an IProjectSite object can implement to indicate it has an FSharpProjectOptions @@ -63,8 +62,7 @@ type private ProjectSiteOfScriptFile(filename:string, referencedProjectFileNames override this.ProjectGuid = "" override this.LoadTime = checkOptions.LoadTime override this.ProjectProvider = None - override this.AssemblyReferences() = checkOptions.OriginalLoadReferences |> List.map(fun (_,p) -> p) |> List.toArray - + override this.AssemblyReferences() = [||] interface IHaveCheckOptions with override this.OriginalCheckOptions() = (referencedProjectFileNames, checkOptions) @@ -184,7 +182,7 @@ type internal ProjectSitesAndFiles() = UseScriptResolutionRules = SourceFile.MustBeSingleFileProject fileName LoadTime = projectSite.LoadTime UnresolvedReferences = None - OriginalLoadReferences = (projectSite.AssemblyReferences() |> Array.map(fun s -> rangeCmdArgs, s) |> Array.toList) + OriginalLoadReferences = [] ExtraProjectInfo=extraProjectInfo Stamp = (if useUniqueStamp then (stamp <- stamp + 1L; Some stamp) else None) } referencedProjectFileNames, options From de68e91afddddf12cb42cf7af01183f8be7e64cc Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Tue, 12 Sep 2017 16:17:19 -0700 Subject: [PATCH 05/13] reduce delta --- .../Classification/ColorizationService.fs | 2 +- .../CodeFix/AddOpenCodeFixProvider.fs | 2 +- .../ImplementInterfaceCodeFixProvider.fs | 2 +- .../CodeFix/ProposeUppercaseLabel.fs | 2 +- .../CodeFix/RemoveUnusedOpens.fs | 2 +- .../CodeFix/RenameParamToMatchSignature.fs | 2 +- .../CodeFix/RenameUnusedValue.fs | 2 +- .../Commands/HelpContextService.fs | 2 +- .../Commands/XmlDocCommandService.fs | 4 +- .../Completion/CompletionProvider.fs | 2 +- .../Completion/CompletionService.fs | 4 +- .../Completion/FileSystemCompletion.fs | 2 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 2 +- .../Debugging/BreakpointResolutionService.fs | 2 +- .../Debugging/LanguageDebugInfoService.fs | 2 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 2 +- .../SimplifyNameDiagnosticAnalyzer.fs | 2 +- .../Diagnostics/UnusedDeclarationsAnalyzer.fs | 2 +- .../UnusedOpensDiagnosticAnalyzer.fs | 2 +- .../DocumentHighlightsService.fs | 2 +- .../Formatting/BraceMatchingService.fs | 2 +- .../Formatting/EditorFormattingService.fs | 2 +- .../Formatting/IndentationService.fs | 2 +- .../InlineRename/InlineRenameService.fs | 6 +- .../LanguageService/LanguageService.fs | 65 ++++++++++--------- .../LanguageService/SymbolHelpers.fs | 6 +- .../Navigation/FindUsagesService.fs | 2 +- .../Navigation/GoToDefinitionService.fs | 4 +- .../Navigation/NavigateToSearchService.fs | 2 +- .../Navigation/NavigationBarItemService.fs | 2 +- .../QuickInfo/QuickInfoProvider.fs | 6 +- .../Structure/BlockStructureService.fs | 4 +- .../ProjectSitesAndFiles.fs | 4 +- 33 files changed, 76 insertions(+), 75 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs b/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs index b35c49b8582..b40aaa4d0a2 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ColorizationService.fs @@ -21,7 +21,7 @@ type internal FSharpColorizationService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SemanticColorization" diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs index 19dbcbfe95f..92622f4fe7e 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs @@ -22,7 +22,7 @@ type internal FSharpAddOpenCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs index dc4ed05a626..494f071ad56 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -29,7 +29,7 @@ type internal FSharpImplementInterfaceCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = ["FS0366"] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs index 2f1419da44c..a01ed2f37ed 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs @@ -12,7 +12,7 @@ type internal FSharpProposeUpperCaseLabelCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = ["FS0053"] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index 130f96bd7ee..1bbab71834d 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -19,7 +19,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() let fixableDiagnosticIds = [IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId] diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs index a7e70b22417..ea2ba70d2a3 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs @@ -21,7 +21,7 @@ type internal FSharpRenameParamToMatchSignature [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs index 0f87562e5b9..3cb96a95e14 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs @@ -20,7 +20,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = inherit CodeFixProvider() diff --git a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs index 0d2a86cc6be..2c7ece30131 100644 --- a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs @@ -19,7 +19,7 @@ type internal FSharpHelpContextService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "ImplementInterfaceCodeFix" diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index f3256ff1d70..2af89506561 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -22,7 +22,7 @@ type internal XmlDocCommandFilter wpfTextView: IWpfTextView, filePath: string, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, workspace: VisualStudioWorkspaceImpl ) = @@ -118,7 +118,7 @@ type internal XmlDocCommandFilter type internal XmlDocCommandFilterProvider [] (checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, workspace: VisualStudioWorkspaceImpl, textDocumentFactoryService: ITextDocumentFactoryService, editorFactory: IVsEditorAdaptersFactoryService) = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index e8a217a30ad..f77988f2702 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -27,7 +27,7 @@ type internal FSharpCompletionProvider workspace: Workspace, serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider ) = diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs index 98b6d87c35e..ab9585c5184 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionService.fs @@ -17,7 +17,7 @@ type internal FSharpCompletionService workspace: Workspace, serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider ) = inherit CompletionServiceWithProviders(workspace) @@ -47,7 +47,7 @@ type internal FSharpCompletionServiceFactory ( serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, assemblyContentProvider: AssemblyContentProvider ) = interface ILanguageServiceFactory with diff --git a/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs b/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs index 42694f084b2..f8a66615f20 100644 --- a/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs +++ b/vsintegration/src/FSharp.Editor/Completion/FileSystemCompletion.fs @@ -22,7 +22,7 @@ type internal Completion = AllowableExtensions = allowableExtensions UseIncludeDirectives = useIncludeDirectives } -type internal HashDirectiveCompletionProvider(workspace: Workspace, projectInfoManager: ProjectInfoManager, completions: Completion list) = +type internal HashDirectiveCompletionProvider(workspace: Workspace, projectInfoManager: FSharpProjectOptionsManager, completions: Completion list) = inherit CommonCompletionProvider() let [] NetworkPath = "\\\\" diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 53592a42803..22310a9bf43 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -25,7 +25,7 @@ type internal FSharpSignatureHelpProvider ( serviceProvider: SVsServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "SignatureHelpProvider" diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs index 802ad32bf82..864a77e44aa 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs @@ -23,7 +23,7 @@ type internal FSharpBreakpointResolutionService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "BreakpointResolution" diff --git a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs index b9fbe70ff35..02ccfc1e6e8 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs @@ -18,7 +18,7 @@ open Microsoft.VisualStudio.FSharp.LanguageService [] [, FSharpConstants.FSharpLanguageName)>] -type internal FSharpLanguageDebugInfoService [](projectInfoManager: ProjectInfoManager) = +type internal FSharpLanguageDebugInfoService [](projectInfoManager: FSharpProjectOptionsManager) = static member GetDataTipInformation(sourceText: SourceText, position: int, tokens: List): TextSpan option = let tokenIndex = tokens |> Seq.tryFindIndex(fun t -> t.TextSpan.Contains(position)) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index f31f18e1102..412496efa35 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -30,7 +30,7 @@ type internal FSharpDocumentDiagnosticAnalyzer() = document.Project.Solution.Workspace.Services.GetService().Checker let getProjectInfoManager(document: Document) = - document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager + document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager static let errorInfoEqualityComparer = { new IEqualityComparer with diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index 50f561b818a..0686c7ddd86 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -24,7 +24,7 @@ type internal SimplifyNameDiagnosticAnalyzer() = inherit DocumentDiagnosticAnalyzer() static let userOpName = "SimplifyNameDiagnosticAnalyzer" - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker let getPlidLength (plid: string list) = (plid |> List.sumBy String.length) + plid.Length static let cache = ConditionalWeakTable>() diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs index 9047f62c13f..b1868f9f5f1 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -17,7 +17,7 @@ type internal UnusedDeclarationsAnalyzer() = inherit DocumentDiagnosticAnalyzer() static let userOpName = "UnusedDeclarationsAnalyzer" - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker let [] DescriptorId = "FS1182" diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 354264d5c0f..53c5d51b3d3 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -143,7 +143,7 @@ module private UnusedOpens = type internal UnusedOpensDiagnosticAnalyzer() = inherit DocumentDiagnosticAnalyzer() - let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().ProjectInfoManager + let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService().FSharpProjectOptionsManager let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService().Checker static let userOpName = "UnusedOpensAnalyzer" diff --git a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs index d43dc7dc23c..e4829fd4764 100644 --- a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs +++ b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs @@ -23,7 +23,7 @@ type internal FSharpHighlightSpan = [] [, FSharpConstants.FSharpLanguageName)>] -type internal FSharpDocumentHighlightsService [] (checkerProvider: FSharpCheckerProvider, projectInfoManager: ProjectInfoManager) = +type internal FSharpDocumentHighlightsService [] (checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager) = static let userOpName = "DocumentHighlights" diff --git a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs index 8c351372869..700768a20c9 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs @@ -12,7 +12,7 @@ type internal FSharpBraceMatchingService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = diff --git a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs index 292155b12d3..0abbd0abddf 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs @@ -20,7 +20,7 @@ type internal FSharpEditorFormattingService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, projectOptions: FSharpProjectOptions option, position: int) = diff --git a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs index ddd5aea68f5..4fa71c024fb 100644 --- a/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs +++ b/vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs @@ -18,7 +18,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices [, FSharpConstants.FSharpLanguageName)>] type internal FSharpIndentationService [] - (projectInfoManager: ProjectInfoManager) = + (projectInfoManager: FSharpProjectOptionsManager) = static member IsSmartIndentEnabled (options: Microsoft.CodeAnalysis.Options.OptionSet) = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName) = FormattingOptions.IndentStyle.Smart diff --git a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs index 15fa5df1328..d2f804ebe55 100644 --- a/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs +++ b/vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs @@ -73,7 +73,7 @@ type internal InlineRenameLocationSet(locationsByDocument: DocumentLocations [], type internal InlineRenameInfo ( checker: FSharpChecker, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, document: Document, triggerSpan: TextSpan, lexerSymbol: LexerSymbol, @@ -141,13 +141,13 @@ type internal InlineRenameInfo type internal InlineRenameService [] ( - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, checkerProvider: FSharpCheckerProvider, [] _refactorNotifyServices: seq ) = static let userOpName = "InlineRename" - static member GetInlineRenameInfo(checker: FSharpChecker, projectInfoManager: ProjectInfoManager, document: Document, sourceText: SourceText, position: int, + static member GetInlineRenameInfo(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager, document: Document, sourceText: SourceText, position: int, defines: string list, options: FSharpProjectOptions) : Async = asyncMaybe { let textLine = sourceText.Lines.GetLineFromPosition(position) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 1385062e061..a78be521224 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -59,22 +59,22 @@ type internal FSharpCheckerProvider // When the F# background builder refreshes the background semantic build context for a file, // we request Roslyn to reanalyze that individual file. checker.BeforeBackgroundFileCheck.Add(fun (fileName, extraProjectInfo) -> - async { - try - match extraProjectInfo with - | Some (:? Workspace as workspace) -> - let solution = workspace.CurrentSolution - let documentIds = solution.GetDocumentIdsWithFilePath(fileName) - if not documentIds.IsEmpty then - let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray - for documentId in docuentIdsFiltered do - Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) - if docuentIdsFiltered.Length > 0 then - analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) - | _ -> () - with ex -> - Assert.Exception(ex) - } |> Async.StartImmediate + async { + try + match extraProjectInfo with + | Some (:? Workspace as workspace) -> + let solution = workspace.CurrentSolution + let documentIds = solution.GetDocumentIdsWithFilePath(fileName) + if not documentIds.IsEmpty then + let docuentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray + for documentId in docuentIdsFiltered do + Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) + if docuentIdsFiltered.Length > 0 then + analyzerService.Reanalyze(workspace,documentIds=docuentIdsFiltered) + | _ -> () + with ex -> + Assert.Exception(ex) + } |> Async.StartImmediate ) checker @@ -91,8 +91,8 @@ type Refreshable<'T> = 'T * (bool -> 'T) // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject. -[); Composition.Shared>] -type internal ProjectInfoManager +[); Composition.Shared>] +type internal FSharpProjectOptionsManager [] ( checkerProvider: FSharpCheckerProvider, @@ -210,6 +210,7 @@ type internal ProjectInfoManager | _ -> this.TryGetOptionsForProject(projectId) [] + /// This handles commandline change notifications from the Dotnet Project-system member this.HandleCommandLineChanges(path:string, sources:ImmutableArray, references:ImmutableArray, options:ImmutableArray) = let fullPath p = if Path.IsPathRooted(p) then p @@ -230,7 +231,7 @@ type internal ProjectInfoManager type internal FSharpCheckerWorkspaceService = inherit Microsoft.CodeAnalysis.Host.IWorkspaceService abstract Checker: FSharpChecker - abstract ProjectInfoManager: ProjectInfoManager + abstract FSharpProjectOptionsManager: FSharpProjectOptionsManager type internal RoamingProfileStorageLocation(keyName: string) = inherit OptionStorageLocation() @@ -249,13 +250,13 @@ type internal FSharpCheckerWorkspaceServiceFactory [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = interface Microsoft.CodeAnalysis.Host.Mef.IWorkspaceServiceFactory with member this.CreateService(_workspaceServices) = upcast { new FSharpCheckerWorkspaceService with member this.Checker = checkerProvider.Checker - member this.ProjectInfoManager = projectInfoManager } + member this.FSharpProjectOptionsManager = projectInfoManager } type [] @@ -310,7 +311,7 @@ and internal FSharpLanguageService(package : FSharpPackage) = inherit AbstractLanguageService(package) - let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value + let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value let projectDisplayNameOf projectFileName = if String.IsNullOrWhiteSpace projectFileName then projectFileName @@ -391,7 +392,7 @@ and member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = let project = this.Workspace.CurrentSolution.GetProject(projectId) let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) - this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId this.Workspace, projectId, siteProvider.GetProjectSite(), this.Workspace, "OnProjectChanged") member private this.OnProjectAdded(projectId:ProjectId, newSolution:Solution) = this.OnProjectChanged(projectId, newSolution) member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () @@ -511,8 +512,9 @@ and let projectGuid = Guid(site.ProjectGuid) let projectFileName = site.ProjectFileName() let projectDisplayName = projectDisplayNameOf projectFileName + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) - + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) @@ -521,13 +523,14 @@ and |> Option.map (fun p -> p :?> IVsHierarchy) |> Option.toObj - // Roslyn is expecting site to be an IVsHierarchy. - // It just so happens that the object that implements IProvideProjectSite is also - // an IVsHierarchy. This assertion is to ensure that the assumption holds true. - Debug.Assert(hierarchy <> null, "About to CreateProjectContext with a non-hierarchy site") - if isNull (workspace.ProjectTracker.GetProject projectId) then let projectContextFactory = package.ComponentModel.GetService() + + // Roslyn is expecting site to be an IVsHierarchy. + // It just so happens that the object that implements IProvideProjectSite is also + // an IVsHierarchy. This assertion is to ensure that the assumption holds true. + Debug.Assert(hierarchy <> null, "About to CreateProjectContext with a non-hierarchy site") + let projectContext = projectContextFactory.CreateProjectContext( FSharpConstants.FSharpLanguageName, projectDisplayName, projectFileName, projectGuid, hierarchy, null, errorReporter) @@ -535,7 +538,6 @@ and let project = projectContext :?> AbstractProject this.SyncProject(project, projectContext, site, workspace, forceUpdate=false, userOpName=userOpName) - site.BuildErrorReporter <- Some(errorReporter :> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) site.AdviseProjectSiteChanges(FSharpConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site, workspace, forceUpdate=true, userOpName="AdviseProjectSiteChanges."+userOpName))) site.AdviseProjectSiteClosed(FSharpConstants.FSharpLanguageServiceCallbackName, @@ -543,7 +545,6 @@ and projectInfoManager.ClearInfoForProject(project.Id) optionsAssociation.Remove(projectContext) |> ignore project.Disconnect())) - for referencedSite in ProjectSitesAndFiles.GetReferencedProjectSites (site, this.SystemServiceProvider) do let referencedProjectId = setup referencedSite project.AddProjectReference(ProjectReference referencedProjectId) @@ -608,7 +609,7 @@ and | id -> let project = this.Workspace.CurrentSolution.GetProject(id.ProjectId) let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) - this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId this.Workspace, id.ProjectId, siteProvider.GetProjectSite(), this.Workspace, "SetupNewTextView") | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 0ca982b41a5..dfe76098b80 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -21,7 +21,7 @@ module internal SymbolHelpers = open Microsoft.CodeAnalysis.CodeActions /// Used for local code fixes in a document, e.g. to rename local parameters - let getSymbolUsesOfSymbolAtLocationInDocument (document: Document, position: int, projectInfoManager: ProjectInfoManager, checker: FSharpChecker, userOpName) = + let getSymbolUsesOfSymbolAtLocationInDocument (document: Document, position: int, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, userOpName) = asyncMaybe { let! cancellationToken = Async.CancellationToken |> liftAsync let! sourceText = document.GetTextAsync(cancellationToken) @@ -40,7 +40,7 @@ module internal SymbolHelpers = } let getSymbolUsesInSolution (symbol: FSharpSymbol, declLoc: SymbolDeclarationLocation, checkFileResults: FSharpCheckFileResults, - projectInfoManager: ProjectInfoManager, checker: FSharpChecker, solution: Solution, userOpName) = + projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, solution: Solution, userOpName) = async { let! symbolUses = match declLoc with @@ -95,7 +95,7 @@ module internal SymbolHelpers = // A better approach is to use something like createTextChangeCodeFix below, with a delayed function to compute a set of changes to be applied // simultaneously. But that doesn't work for this case, as we want a set of changes to apply acrosss the whole solution. - let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: ProjectInfoManager, checker: FSharpChecker, userOpName) + let changeAllSymbolReferences (document: Document, symbolSpan: TextSpan, textChanger: string -> string, projectInfoManager: FSharpProjectOptionsManager, checker: FSharpChecker, userOpName) : Async<(Func> * OriginalText) option> = asyncMaybe { do! Option.guard (symbolSpan.Length > 0) diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index 46e6bf5946f..b964f1d2eff 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -20,7 +20,7 @@ type internal FSharpFindUsagesService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "FindUsages" diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 7d296edef06..9b7b12aecd6 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -33,7 +33,7 @@ type internal FSharpNavigableItem(document: Document, textSpan: TextSpan) = member this.DisplayTaggedParts = ImmutableArray.Empty member this.ChildItems = ImmutableArray.Empty -type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: ProjectInfoManager) = +type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager) = static let userOpName = "GoToDefinition" @@ -239,7 +239,7 @@ type internal FSharpGoToDefinitionService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "GoToDefinition" diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index d29c85e724b..d84202eac73 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -182,7 +182,7 @@ type internal FSharpNavigateToSearchService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = let itemsByDocumentId = ConditionalWeakTable() diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs index bd8f3cc64bd..7e0fdac0def 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs @@ -23,7 +23,7 @@ type internal FSharpNavigationBarItemService [] ( checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager + projectInfoManager: FSharpProjectOptionsManager ) = static let userOpName = "NavigationBarItem" diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 97b40efac68..1324602ffb2 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -38,7 +38,7 @@ module private FSharpQuickInfo = let getTooltipFromRange ( checker: FSharpChecker, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, document: Document, declRange: range, cancellationToken: CancellationToken @@ -82,7 +82,7 @@ module private FSharpQuickInfo = let getTooltipInfo ( checker: FSharpChecker, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, document: Document, position: int, cancellationToken: CancellationToken @@ -162,7 +162,7 @@ type internal FSharpQuickInfoProvider ( [)>] serviceProvider: IServiceProvider, checkerProvider: FSharpCheckerProvider, - projectInfoManager: ProjectInfoManager, + projectInfoManager: FSharpProjectOptionsManager, gotoDefinitionService: FSharpGoToDefinitionService, viewProvider: QuickInfoViewProvider ) = diff --git a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs index 30eced943b2..68a41f19e6d 100644 --- a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs +++ b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs @@ -139,7 +139,7 @@ module internal BlockStructure = open BlockStructure -type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoManager: ProjectInfoManager) = +type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoManager: FSharpProjectOptionsManager) = inherit BlockStructureService() static let userOpName = "BlockStructure" @@ -158,7 +158,7 @@ type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoMan |> RoslynHelpers.StartAsyncAsTask(cancellationToken) [, FSharpConstants.FSharpLanguageName); Shared>] -type internal FSharpBlockStructureServiceFactory [](checkerProvider: FSharpCheckerProvider, projectInfoManager: ProjectInfoManager) = +type internal FSharpBlockStructureServiceFactory [](checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager) = interface ILanguageServiceFactory with member __.CreateLanguageService(_languageServices) = upcast FSharpBlockStructureService(checkerProvider.Checker, projectInfoManager) \ No newline at end of file diff --git a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs index 92d84db54be..a7367999ab4 100644 --- a/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs +++ b/vsintegration/src/FSharp.LanguageService/ProjectSitesAndFiles.fs @@ -14,7 +14,7 @@ // through the nodes of the hierarchy for the F# project. There seems to be an essentially duplicated // version of this code in this file. // -// In our LanguageService.fs, ProjectInfoManager uses this IProjectSite information to incrementally maintain +// In our LanguageService.fs, FSharpProjectOptionsManager uses this IProjectSite information to incrementally maintain // a corresponding F# CompilerService FSharpProjectOptions value. // // In our LanguageService.fs, we also use this IProjectSite information to maintain a @@ -27,7 +27,7 @@ // project.AddProjectReference // // The new F# project system supplies the project information using a Roslyn project in the workspace. -// This means a lot of the stuff above is irrelevant in that case, apart from where ProjectInfoManager +// This means a lot of the stuff above is irrelevant in that case, apart from where FSharpProjectOptionsManager // incrementally maintains a corresponding F# CompilerService FSharpProjectOptions value. namespace Microsoft.VisualStudio.FSharp.LanguageService From 472b3d8800ce3d644610a900e55561531932938f Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Wed, 13 Sep 2017 00:25:14 -0700 Subject: [PATCH 06/13] invalidate ide when a new file is discovered --- .../LanguageService/LanguageService.fs | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index a78be521224..d54694e36ca 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace Microsoft.VisualStudio.FSharp.Editor +namespace rec Microsoft.VisualStudio.FSharp.Editor #nowarn "40" @@ -89,8 +89,6 @@ type Refreshable<'T> = 'T * (bool -> 'T) // This service allows analyzers to get an appropriate FSharpProjectOptions value for a project or single file. // It also allows a 'cheaper' route to get the project options relevant to parsing (e.g. the #define values). // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject. - - [); Composition.Shared>] type internal FSharpProjectOptionsManager [] @@ -98,6 +96,7 @@ type internal FSharpProjectOptionsManager checkerProvider: FSharpCheckerProvider, [)>] serviceProvider: System.IServiceProvider ) = + // A table of information about projects, excluding single-file projects. let projectTable = ConcurrentDictionary>() @@ -108,6 +107,11 @@ type internal FSharpProjectOptionsManager // Accumulate sources and references for each project file let projectInfo = new ConcurrentDictionary() + let notify = new Event() + + [] + member this.NotifyCommandLineChanges = notify.Publish + /// Clear a project from the project table member this.ClearInfoForProject(projectId: ProjectId) = projectTable.TryRemove(projectId) |> ignore @@ -218,6 +222,7 @@ type internal FSharpProjectOptionsManager let sourcePaths = sources |> Seq.map(fun s -> fullPath s.Path) |> Seq.toArray let referencePaths = references |> Seq.map(fun r -> fullPath r.Reference) |> Seq.toArray projectInfo.[path] <- (sourcePaths,referencePaths,options.ToArray()) + notify.Trigger(path) () member __.GetProjectInfo(path:string) = @@ -294,7 +299,7 @@ type override this.CreateEditorFactories() = Seq.empty override this.RegisterMiscellaneousFilesWorkspaceInformation(_) = () -and +type [] [, ".fs")>] [, ".fsi")>] @@ -308,17 +313,19 @@ and [] [] [] - internal FSharpLanguageService(package : FSharpPackage) = + internal FSharpLanguageService(package : FSharpPackage) as this = inherit AbstractLanguageService(package) let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value - let projectDisplayNameOf projectFileName = + let projectDisplayNameOf projectFileName = if String.IsNullOrWhiteSpace projectFileName then projectFileName else Path.GetFileNameWithoutExtension projectFileName let singleFileProjects = ConcurrentDictionary<_, AbstractProject>() + do projectInfoManager.NotifyCommandLineChanges.Add(fun path -> this.HandleCommandLineOptionsChanged(path)) + let tryRemoveSingleFileProject projectId = match singleFileProjects.TryRemove(projectId) with | true, project -> @@ -335,6 +342,11 @@ and let optionsAssociation = ConditionalWeakTable() + member private this.HandleCommandLineOptionsChanged (path) = + let projectDisplayName = projectDisplayNameOf path + let projectId = this.Workspace.ProjectTracker.GetOrCreateProjectIdForPath(path, projectDisplayName) + this.OnProjectChanged(projectId) + member private this.ProvideProjectSiteProvider(workspace:Workspace, project:Project) = let visualStudioWorkspace = workspace :?> VisualStudioWorkspace let hier = visualStudioWorkspace.GetHierarchy(project.Id) @@ -389,11 +401,15 @@ and member __.Unused4() = hier.Unused4() } - member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = + member private this.OnProjectChanged(projectId:ProjectId) = let project = this.Workspace.CurrentSolution.GetProject(projectId) let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId this.Workspace, projectId, siteProvider.GetProjectSite(), this.Workspace, "OnProjectChanged") - member private this.OnProjectAdded(projectId:ProjectId, newSolution:Solution) = this.OnProjectChanged(projectId, newSolution) + + member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) + + member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) + member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () override this.Initialize() = @@ -512,7 +528,6 @@ and let projectGuid = Guid(site.ProjectGuid) let projectFileName = site.ProjectFileName() let projectDisplayName = projectDisplayNameOf projectFileName - let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) @@ -590,7 +605,6 @@ and | (VSConstants.S_OK, textLines) -> let filename = VsTextLines.GetFilename textLines - // CPS projects don't implement IProvideProjectSite and IVSProjectHierarchy // Simple explanation: // Legacy projects have IVSHierarchy and IPRojectSite From 8164c61b168d55d505517aa774d8728ee6034148 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Wed, 13 Sep 2017 14:03:03 -0700 Subject: [PATCH 07/13] Go faster stripes --- .../LanguageService/LanguageService.fs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index d54694e36ca..c2b460608ba 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -155,13 +155,15 @@ type internal FSharpProjectOptionsManager /// Update the info for a project in the project table member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, workspace: Workspace, userOpName) = - this.AddOrUpdateProject(projectId, (fun isRefresh -> - let extraProjectInfo = Some(box workspace) - let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject - let referencedProjects, options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) - let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId - checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") - referencedProjectIds, options)) + async { + this.AddOrUpdateProject(projectId, (fun isRefresh -> + let extraProjectInfo = Some(box workspace) + let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject + let referencedProjects, options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) + let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId + checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") + referencedProjectIds, options)) + } |> Async.Start /// Get compilation defines relevant for syntax processing. /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project From 418e21467917899887cb487902daa5424b40414e Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Thu, 14 Sep 2017 14:28:46 -0700 Subject: [PATCH 08/13] feedback + refactor --- .../LanguageService/LanguageService.fs | 178 +++++++++--------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index c2b460608ba..609bb0dcecd 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -14,9 +14,11 @@ open System.IO open System.Linq open System.Runtime.CompilerServices open System.Runtime.InteropServices +open System.Threading open Microsoft.FSharp.Compiler.CompileOps open Microsoft.FSharp.Compiler.SourceCodeServices +open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Diagnostics @@ -94,6 +96,7 @@ type internal FSharpProjectOptionsManager [] ( checkerProvider: FSharpCheckerProvider, + [)>] workspace: VisualStudioWorkspaceImpl, [)>] serviceProvider: System.IServiceProvider ) = @@ -107,11 +110,14 @@ type internal FSharpProjectOptionsManager // Accumulate sources and references for each project file let projectInfo = new ConcurrentDictionary() - let notify = new Event() + let projectDisplayNameOf projectFileName = + if String.IsNullOrWhiteSpace projectFileName then projectFileName + else Path.GetFileNameWithoutExtension projectFileName + + let tryGetOrCreateProjectId (projectFileName: string) = + let projectDisplayName = projectDisplayNameOf projectFileName + Some (workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName)) - [] - member this.NotifyCommandLineChanges = notify.Publish - /// Clear a project from the project table member this.ClearInfoForProject(projectId: ProjectId) = projectTable.TryRemove(projectId) |> ignore @@ -133,7 +139,7 @@ type internal FSharpProjectOptionsManager member this.AddOrUpdateSingleFileProject(projectId, data) = singleFileProjectTable.[projectId] <- data - + /// Get the exact options for a single-file script member this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, fileContents, workspace: Workspace) = async { let extraProjectInfo = Some(box workspace) @@ -154,17 +160,15 @@ type internal FSharpProjectOptionsManager } /// Update the info for a project in the project table - member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, workspace: Workspace, userOpName) = - async { - this.AddOrUpdateProject(projectId, (fun isRefresh -> - let extraProjectInfo = Some(box workspace) - let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject - let referencedProjects, options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) - let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId - checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") - referencedProjectIds, options)) - } |> Async.Start - + member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, userOpName) = + this.AddOrUpdateProject(projectId, (fun isRefresh -> + let extraProjectInfo = Some(box workspace) + let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject + let referencedProjects, options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) + let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId + checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") + referencedProjectIds, options)) + /// Get compilation defines relevant for syntax processing. /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project /// options for a script. @@ -215,6 +219,68 @@ type internal FSharpProjectOptionsManager | true, (_loadTime, originalOptions) -> Some originalOptions | _ -> this.TryGetOptionsForProject(projectId) + member this.ProvideProjectSiteProvider(project:Project) = + let hier = workspace.GetHierarchy(project.Id) + + {new IProvideProjectSite with + member iProvideProjectSite.GetProjectSite() = + let fst (a, _, _) = a + let thrd (_, _, c) = c + let mutable errorReporter = + let reporter = ProjectExternalErrorReporter(project.Id, "FS", serviceProvider) + Some(reporter:> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) + + {new Microsoft.VisualStudio.FSharp.LanguageService.IProjectSite with + member __.SourceFilesOnDisk() = this.GetProjectInfo(project.FilePath) |> fst + member __.DescriptionOfProject() = project.Name + member __.CompilerFlags() = + let _,references,options = this.GetProjectInfo(project.FilePath) + Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] + member __.ProjectFileName() = project.FilePath + member __.AdviseProjectSiteChanges(_,_) = () + member __.AdviseProjectSiteCleaned(_,_) = () + member __.AdviseProjectSiteClosed(_,_) = () + member __.IsIncompleteTypeCheckEnvironment = false + member __.TargetFrameworkMoniker = "" + member __.ProjectGuid = project.Id.Id.ToString() + member __.LoadTime = System.DateTime.Now + member __.ProjectProvider = Some iProvideProjectSite + member __.AssemblyReferences() = this.GetProjectInfo(project.FilePath) |> thrd + member __.BuildErrorReporter with get () = errorReporter and + set (v) = errorReporter <- v + } + + // TODO: figure out why this is necessary + interface IVsHierarchy with + member __.SetSite(psp) = hier.SetSite(psp) + member __.GetSite(psp) = hier.GetSite(ref psp) + member __.QueryClose(pfCanClose) = hier.QueryClose(ref pfCanClose) + member __.Close() = hier.Close() + member __.GetGuidProperty(itemid, propid, pguid) = hier.GetGuidProperty(itemid, propid, ref pguid) + member __.SetGuidProperty(itemid, propid, rguid) = hier.SetGuidProperty(itemid, propid, ref rguid) + member __.GetProperty(itemid, propid, pvar) = hier.GetProperty(itemid, propid, ref pvar) + member __.SetProperty(itemid, propid, var) = hier.SetProperty(itemid, propid, var) + member __.GetNestedHierarchy(itemid, iidHierarchyNested, ppHierarchyNested, pitemidNested) = hier.GetNestedHierarchy(itemid, ref iidHierarchyNested, ref ppHierarchyNested, ref pitemidNested) + member __.GetCanonicalName(itemid, pbstrName) = hier.GetCanonicalName(itemid, ref pbstrName) + member __.ParseCanonicalName(pszName, pitemid) = hier.ParseCanonicalName(pszName, ref pitemid) + member __.Unused0() = hier.Unused0() + member __.AdviseHierarchyEvents(pEventSink, pdwCookie) = hier.AdviseHierarchyEvents(pEventSink, ref pdwCookie) + member __.UnadviseHierarchyEvents(dwCookie) = hier.UnadviseHierarchyEvents(dwCookie) + member __.Unused1() = hier.Unused1() + member __.Unused2() = hier.Unused2() + member __.Unused3() = hier.Unused3() + member __.Unused4() = hier.Unused4() + } + + member this.UpdateProjectInfoWithProjectId(projectId:ProjectId, userOpName) = + let project = workspace.CurrentSolution.GetProject(projectId) + let siteProvider = this.ProvideProjectSiteProvider(project) + this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId, siteProvider.GetProjectSite(), userOpName) + + member this.UpdateProjectInfoWithPath(path, userOpName) = + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(path, projectDisplayNameOf path) + this.UpdateProjectInfoWithProjectId(projectId, userOpName) + [] /// This handles commandline change notifications from the Dotnet Project-system member this.HandleCommandLineChanges(path:string, sources:ImmutableArray, references:ImmutableArray, options:ImmutableArray) = @@ -224,13 +290,12 @@ type internal FSharpProjectOptionsManager let sourcePaths = sources |> Seq.map(fun s -> fullPath s.Path) |> Seq.toArray let referencePaths = references |> Seq.map(fun r -> fullPath r.Reference) |> Seq.toArray projectInfo.[path] <- (sourcePaths,referencePaths,options.ToArray()) - notify.Trigger(path) - () + this.UpdateProjectInfoWithPath(path, "OnProjectChanged") member __.GetProjectInfo(path:string) = match projectInfo.TryGetValue path with | true, value -> value - | _ -> Array.empty, Array.empty, Array.empty + | _ -> [||], [||], [||] // Used to expose FSharpChecker/ProjectInfo manager to diagnostic providers // Diagnostic providers can be executed in environment that does not use MEF so they can rely only @@ -315,7 +380,7 @@ type [] [] [] - internal FSharpLanguageService(package : FSharpPackage) as this = + internal FSharpLanguageService(package : FSharpPackage) = inherit AbstractLanguageService(package) let projectInfoManager = package.ComponentModel.DefaultExportProvider.GetExport().Value @@ -326,8 +391,6 @@ type let singleFileProjects = ConcurrentDictionary<_, AbstractProject>() - do projectInfoManager.NotifyCommandLineChanges.Add(fun path -> this.HandleCommandLineOptionsChanged(path)) - let tryRemoveSingleFileProject projectId = match singleFileProjects.TryRemove(projectId) with | true, project -> @@ -344,69 +407,8 @@ type let optionsAssociation = ConditionalWeakTable() - member private this.HandleCommandLineOptionsChanged (path) = - let projectDisplayName = projectDisplayNameOf path - let projectId = this.Workspace.ProjectTracker.GetOrCreateProjectIdForPath(path, projectDisplayName) - this.OnProjectChanged(projectId) - - member private this.ProvideProjectSiteProvider(workspace:Workspace, project:Project) = - let visualStudioWorkspace = workspace :?> VisualStudioWorkspace - let hier = visualStudioWorkspace.GetHierarchy(project.Id) - - {new IProvideProjectSite with - member iProvideProjectSite.GetProjectSite() = - let fst (a, _, _) = a - let thrd (_, _, c) = c - let mutable errorReporter = - let reporter = ProjectExternalErrorReporter(project.Id, "FS", this.SystemServiceProvider) - Some(reporter:> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) - - {new Microsoft.VisualStudio.FSharp.LanguageService.IProjectSite with - member __.SourceFilesOnDisk() = projectInfoManager.GetProjectInfo(project.FilePath) |> fst - member __.DescriptionOfProject() = project.Name - member __.CompilerFlags() = - let _,references,options = projectInfoManager.GetProjectInfo(project.FilePath) - Array.concat [options; references |> Array.map(fun r -> "-r:" + r)] - member __.ProjectFileName() = project.FilePath - member __.AdviseProjectSiteChanges(_,_) = () - member __.AdviseProjectSiteCleaned(_,_) = () - member __.AdviseProjectSiteClosed(_,_) = () - member __.IsIncompleteTypeCheckEnvironment = false - member __.TargetFrameworkMoniker = "" - member __.ProjectGuid = project.Id.Id.ToString() - member __.LoadTime = System.DateTime.Now - member __.ProjectProvider = Some iProvideProjectSite - member __.AssemblyReferences() = projectInfoManager.GetProjectInfo(project.FilePath) |> thrd - member __.BuildErrorReporter with get () = errorReporter and - set (v) = errorReporter <- v - } - - // TODO: figure out why this is necessary - interface IVsHierarchy with - member __.SetSite(psp) = hier.SetSite(psp) - member __.GetSite(psp) = hier.GetSite(ref psp) - member __.QueryClose(pfCanClose) = hier.QueryClose(ref pfCanClose) - member __.Close() = hier.Close() - member __.GetGuidProperty(itemid, propid, pguid) = hier.GetGuidProperty(itemid, propid, ref pguid) - member __.SetGuidProperty(itemid, propid, rguid) = hier.SetGuidProperty(itemid, propid, ref rguid) - member __.GetProperty(itemid, propid, pvar) = hier.GetProperty(itemid, propid, ref pvar) - member __.SetProperty(itemid, propid, var) = hier.SetProperty(itemid, propid, var) - member __.GetNestedHierarchy(itemid, iidHierarchyNested, ppHierarchyNested, pitemidNested) = hier.GetNestedHierarchy(itemid, ref iidHierarchyNested, ref ppHierarchyNested, ref pitemidNested) - member __.GetCanonicalName(itemid, pbstrName) = hier.GetCanonicalName(itemid, ref pbstrName) - member __.ParseCanonicalName(pszName, pitemid) = hier.ParseCanonicalName(pszName, ref pitemid) - member __.Unused0() = hier.Unused0() - member __.AdviseHierarchyEvents(pEventSink, pdwCookie) = hier.AdviseHierarchyEvents(pEventSink, ref pdwCookie) - member __.UnadviseHierarchyEvents(dwCookie) = hier.UnadviseHierarchyEvents(dwCookie) - member __.Unused1() = hier.Unused1() - member __.Unused2() = hier.Unused2() - member __.Unused3() = hier.Unused3() - member __.Unused4() = hier.Unused4() - } - member private this.OnProjectChanged(projectId:ProjectId) = - let project = this.Workspace.CurrentSolution.GetProject(projectId) - let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId this.Workspace, projectId, siteProvider.GetProjectSite(), this.Workspace, "OnProjectChanged") + projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectChanged") member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) @@ -522,7 +524,7 @@ type // update the cached options if updated then - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, project.Id, site, project.Workspace, userOpName + ".SyncProject") + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, project.Id, site, userOpName + ".SyncProject") member this.SetupProjectFile(siteProvider: IProvideProjectSite, workspace: VisualStudioWorkspaceImpl, userOpName) = let userOpName = userOpName + ".SetupProjectFile" @@ -532,7 +534,6 @@ type let projectDisplayName = projectDisplayNameOf projectFileName let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, workspace, userOpName) let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) let hierarchy = @@ -570,7 +571,6 @@ type setup (siteProvider.GetProjectSite()) |> ignore member this.SetupStandAloneFile(fileName: string, fileContents: string, workspace: VisualStudioWorkspaceImpl, hier: IVsHierarchy) = - let loadTime = DateTime.Now let projectFileName = fileName let projectDisplayName = projectDisplayNameOf projectFileName @@ -623,9 +623,7 @@ type let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) | id -> - let project = this.Workspace.CurrentSolution.GetProject(id.ProjectId) - let siteProvider = this.ProvideProjectSiteProvider(this.Workspace, project) - projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId this.Workspace, id.ProjectId, siteProvider.GetProjectSite(), this.Workspace, "SetupNewTextView") + projectInfoManager.UpdateProjectInfoWithProjectId(id.ProjectId, "SetupNewTextView") | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) From f8635f0643f881bb68832abaa2d78a9c4a2a988c Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Thu, 14 Sep 2017 14:52:52 -0700 Subject: [PATCH 09/13] tryFindIndex --- src/fsharp/vs/IncrementalBuild.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fsharp/vs/IncrementalBuild.fs b/src/fsharp/vs/IncrementalBuild.fs index 312b5dc3649..f940a554be1 100755 --- a/src/fsharp/vs/IncrementalBuild.fs +++ b/src/fsharp/vs/IncrementalBuild.fs @@ -1743,9 +1743,9 @@ type IncrementalBuilder(tcGlobals,frameworkTcImports, nonFrameworkAssemblyInputs // Never open PDB files for the language service, even if --standalone is specified tcConfigB.openDebugInformationForLaterStaticLinking <- false - match commandLineArgs |> Seq.tryFindIndex(fun s -> s.StartsWith(targetProfileSwitch)) with - | Some idx -> - let profile = commandLineArgs.[idx].Substring(targetProfileSwitch.Length) + match commandLineArgs |> Seq.tryFind(fun s -> s.StartsWith(targetProfileSwitch)) with + | Some arg -> + let profile = arg.Substring(targetProfileSwitch.Length) CompileOptions.SetTargetProfile tcConfigB profile | _ -> () tcConfigB, sourceFilesNew From 3fac6c68ca90d78fd49c6c0372f941a56e6bd54b Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Fri, 15 Sep 2017 00:20:33 -0700 Subject: [PATCH 10/13] Cleanup + Ensure that FSharp.Core.BuildFromSource.proj works at designtime --- .../FSharp.Core/FSharp.Core.BuildFromSource.fsproj | 10 ++++++++-- .../FSharp.Editor/LanguageService/LanguageService.fs | 11 +++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj index 568a78ef099..05df6bd97e1 100644 --- a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj +++ b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj @@ -217,8 +217,14 @@ - - + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 609bb0dcecd..8578dc72179 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -411,19 +411,12 @@ type projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectChanged") member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) - - member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) - - member private this.OnProjectRemoved(_projectId:ProjectId, _newSolution:Solution) = () - override this.Initialize() = base.Initialize() let workspaceChanged (args:WorkspaceChangeEventArgs) = match args.Kind with | WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution) - | WorkspaceChangeKind.ProjectChanged -> this.OnProjectChanged(args.ProjectId, args.NewSolution) - | WorkspaceChangeKind.ProjectRemoved -> this.OnProjectRemoved(args.ProjectId, args.NewSolution) | _ -> () this.Workspace.Options <- this.Workspace.Options.WithChangedOption(Completion.CompletionOptions.BlockForCompletionItems, FSharpConstants.FSharpLanguageName, false) @@ -623,7 +616,9 @@ type let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) | id -> - projectInfoManager.UpdateProjectInfoWithProjectId(id.ProjectId, "SetupNewTextView") + let project = this.Workspace.CurrentSolution.GetProject(id.ProjectId) + let siteProvider = projectInfoManager.ProvideProjectSiteProvider(project) + this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) From ef50517acf130e7bcabe93d5e9352d5054adc06a Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Fri, 15 Sep 2017 15:24:28 -0700 Subject: [PATCH 11/13] final clean up --- .../FSharp.Core.BuildFromSource.fsproj | 14 +++------ .../LanguageService/LanguageService.fs | 29 +++++++++---------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj index 05df6bd97e1..95a32107514 100644 --- a/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj +++ b/src/fsharp/FSharp.Core/FSharp.Core.BuildFromSource.fsproj @@ -13,7 +13,7 @@ $(OtherFlags) --warnon:1182 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1 - + FSCore.resx @@ -212,19 +212,13 @@ - + - - + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 8578dc72179..0c640343e3c 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -407,10 +407,7 @@ type let optionsAssociation = ConditionalWeakTable() - member private this.OnProjectChanged(projectId:ProjectId) = - projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectChanged") - - member private this.OnProjectChanged(projectId:ProjectId, _newSolution:Solution) = this.OnProjectChanged(projectId) + member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectAdded") override this.Initialize() = base.Initialize() @@ -525,17 +522,18 @@ type let projectGuid = Guid(site.ProjectGuid) let projectFileName = site.ProjectFileName() let projectDisplayName = projectDisplayNameOf projectFileName - let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) - - let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) - let hierarchy = - site.ProjectProvider - |> Option.map (fun p -> p :?> IVsHierarchy) - |> Option.toObj + let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) if isNull (workspace.ProjectTracker.GetProject projectId) then - let projectContextFactory = package.ComponentModel.GetService() + projectInfoManager.UpdateProjectInfo(tryGetOrCreateProjectId workspace, projectId, site, userOpName) + let projectContextFactory = package.ComponentModel.GetService(); + let errorReporter = ProjectExternalErrorReporter(projectId, "FS", this.SystemServiceProvider) + + let hierarchy = + site.ProjectProvider + |> Option.map (fun p -> p :?> IVsHierarchy) + |> Option.toObj // Roslyn is expecting site to be an IVsHierarchy. // It just so happens that the object that implements IProvideProjectSite is also @@ -549,6 +547,9 @@ type let project = projectContext :?> AbstractProject this.SyncProject(project, projectContext, site, workspace, forceUpdate=false, userOpName=userOpName) + + site.BuildErrorReporter <- Some (errorReporter :> Microsoft.VisualStudio.Shell.Interop.IVsLanguageServiceBuildErrorReporter2) + site.AdviseProjectSiteChanges(FSharpConstants.FSharpLanguageServiceCallbackName, AdviseProjectSiteChanges(fun () -> this.SyncProject(project, projectContext, site, workspace, forceUpdate=true, userOpName="AdviseProjectSiteChanges."+userOpName))) site.AdviseProjectSiteClosed(FSharpConstants.FSharpLanguageServiceCallbackName, @@ -616,9 +617,7 @@ type let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) | id -> - let project = this.Workspace.CurrentSolution.GetProject(id.ProjectId) - let siteProvider = projectInfoManager.ProvideProjectSiteProvider(project) - this.SetupProjectFile(siteProvider, this.Workspace, "SetupNewTextView") + projectInfoManager.UpdateProjectInfoWithProjectId(id.ProjectId, "SetupNewTextView") | _ -> let fileContents = VsTextLines.GetFileContents(textLines, textViewAdapter) this.SetupStandAloneFile(filename, fileContents, this.Workspace, hier) From b5c5fa9e03c72db7f1bc41bbac32c1e89d8c8832 Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Fri, 15 Sep 2017 15:29:40 -0700 Subject: [PATCH 12/13] label for HandleCommandLineChanges --- .../src/FSharp.Editor/LanguageService/LanguageService.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 0c640343e3c..0b2d64bccb9 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -290,7 +290,7 @@ type internal FSharpProjectOptionsManager let sourcePaths = sources |> Seq.map(fun s -> fullPath s.Path) |> Seq.toArray let referencePaths = references |> Seq.map(fun r -> fullPath r.Reference) |> Seq.toArray projectInfo.[path] <- (sourcePaths,referencePaths,options.ToArray()) - this.UpdateProjectInfoWithPath(path, "OnProjectChanged") + this.UpdateProjectInfoWithPath(path, "HandleCommandLineChanges") member __.GetProjectInfo(path:string) = match projectInfo.TryGetValue path with From f0c57346e865ed64b17011a4ea22f673cc81772d Mon Sep 17 00:00:00 2001 From: Kevin Ransom Date: Fri, 15 Sep 2017 15:57:41 -0700 Subject: [PATCH 13/13] ensure some buildfromsource porojects load --- src/FSharpSource.BuildFromSource.targets | 3 ++- src/buildfromsource.cmd | 2 +- src/fsharp/FSharp.Build/InternalsVisibleTo.fs | 5 +---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/FSharpSource.BuildFromSource.targets b/src/FSharpSource.BuildFromSource.targets index f5f52bfc790..aff873c4912 100644 --- a/src/FSharpSource.BuildFromSource.targets +++ b/src/FSharpSource.BuildFromSource.targets @@ -38,7 +38,8 @@ + Outputs="@(CopyAndSubstituteText->'$(OutDir)%(TargetFilename)')" + Condition="'$(DesignTimeBuild)' != 'true'"> diff --git a/src/buildfromsource.cmd b/src/buildfromsource.cmd index 9d50b36d784..03d44c5b568 100644 --- a/src/buildfromsource.cmd +++ b/src/buildfromsource.cmd @@ -20,7 +20,7 @@ if ERRORLEVEL 1 echo Error: failed && goto :failure rem build and pack tools dotnet restore %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj if ERRORLEVEL 1 echo Error: failed && goto :failure -dotnet pack %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj -c release +dotnet pack %__scriptpath%fsharp\FSharp.Compiler.nuget\FSharp.Compiler.nuget.BuildFromSource.fsproj -c debug if ERRORLEVEL 1 echo Error: failed && goto :failure goto :success diff --git a/src/fsharp/FSharp.Build/InternalsVisibleTo.fs b/src/fsharp/FSharp.Build/InternalsVisibleTo.fs index 8543680d835..d4b4322e152 100644 --- a/src/fsharp/FSharp.Build/InternalsVisibleTo.fs +++ b/src/fsharp/FSharp.Build/InternalsVisibleTo.fs @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. namespace Microsoft.FSharp -open System.Reflection -[] - +[] do() -