From c858314c1e85a7af3f5fbe8396407b960ba9781c Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 12 Mar 2021 01:05:52 -0800 Subject: [PATCH 01/35] Initial analysis fix --- src/fsharp/service/IncrementalBuild.fs | 26 ++++++++++++++----- src/fsharp/service/IncrementalBuild.fsi | 6 +++++ src/fsharp/service/service.fs | 6 ++++- .../LanguageService/FSharpCheckerProvider.fs | 21 ++------------- .../FSharpProjectOptionsManager.fs | 19 +++++++------- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 05c83bb58ef..f606df57bd1 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1079,6 +1079,14 @@ type IncrementalBuilder(tcGlobals, return { state with finalizedBoundModel = Some result }, result } + let tryGetSlot (state: IncrementalBuilderState) slot = + match state.boundModels.[slot] with + | Some boundModel -> + (boundModel, state.stampedFileNames.[slot]) + |> Some + | _ -> + None + let tryGetBeforeSlot (state: IncrementalBuilderState) slot = match slot with | 0 (* first file *) -> @@ -1089,12 +1097,7 @@ type IncrementalBuilder(tcGlobals, | _ -> None | _ -> - match state.boundModels.[slot - 1] with - | Some boundModel -> - (boundModel, state.stampedFileNames.[slot - 1]) - |> Some - | _ -> - None + tryGetSlot state (slot - 1) let evalUpToTargetSlot state (cache: TimeStampCache) ctok targetSlot = cancellable { @@ -1211,6 +1214,17 @@ type IncrementalBuilder(tcGlobals, | Some(boundModel, timestamp) -> PartialCheckResults(boundModel, timestamp) |> Some | _ -> None + member builder.TryGetCheckResultsForFileInProject (filename) = + let cache = TimeStampCache defaultTimeStamp + let state = currentState + let state = computeStampedFileNames state cache + let state = computeStampedReferencedAssemblies state cache + + let slotOfFile = builder.GetSlotOfFileName filename + match tryGetSlot state slotOfFile with + | Some(boundModel, timestamp) -> PartialCheckResults(boundModel, timestamp) |> Some + | _ -> None + member private _.GetCheckResultsBeforeSlotInProject (ctok: CompilationThreadToken, slotOfFile, enablePartialTypeChecking) = cancellable { let cache = TimeStampCache defaultTimeStamp diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index bcaa09b9422..9df44aadf3c 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -183,6 +183,12 @@ type internal IncrementalBuilder = /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. member TryGetCheckResultsBeforeFileInProject: filename: string -> PartialCheckResults option + /// Get the typecheck state of a slot, WITH checking if it is up-to-date w.r.t. However, files will not be parsed or checked. + /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available or if it is not up-to-date. + /// + /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. + member TryGetCheckResultsForFileInProject: filename: string -> PartialCheckResults option + /// Get the preceding typecheck state of a slot. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. /// diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 30aab3c66bd..36c083c6277 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -444,13 +444,17 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options) = + match builder.TryGetCheckResultsForFileInProject filename with + | None -> None + | _ -> + // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, sourceText.GetHashCode(), options))) match cachedResults with | Some (parseResults, checkResults,_,priorTimeStamp) when - (match builder.GetCheckResultsBeforeFileInProjectEvenIfStale filename with + (match builder.TryGetCheckResultsBeforeFileInProject filename with | None -> false | Some(tcPrior) -> tcPrior.TimeStamp = priorTimeStamp && diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index fa2e185cbcc..99a1cc83520 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -21,7 +21,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics type internal FSharpCheckerProvider [] ( - analyzerService: IFSharpDiagnosticAnalyzerService, + _analyzerService: IFSharpDiagnosticAnalyzerService, [)>] workspace: VisualStudioWorkspace, settings: EditorOptions ) = @@ -65,24 +65,7 @@ type internal FSharpCheckerProvider enableBackgroundItemKeyStoreAndSemanticClassification = true, enablePartialTypeChecking = true) - // This is one half of the bridge between the F# background builder and the Roslyn analysis engine. - // 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 - let solution = workspace.CurrentSolution - let documentIds = solution.GetDocumentIdsWithFilePath(fileName) - if not documentIds.IsEmpty then - let documentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray - for documentId in documentIdsFiltered do - Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) - if documentIdsFiltered.Length > 0 then - analyzerService.Reanalyze(workspace,documentIds=documentIdsFiltered) - with ex -> - Assert.Exception(ex) - } |> Async.StartImmediate - ) + checker member this.Checker = checker.Value diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 64e11d78e12..08e62c70a2b 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -55,22 +55,23 @@ module private FSharpProjectOptionsHelpers = let hasProjectVersionChanged (oldProject: Project) (newProject: Project) = oldProject.Version <> newProject.Version - let hasDependentVersionChanged (oldProject: Project) (newProject: Project) = + let hasDependentVersionChanged (oldProject: Project) (newProject: Project) (ct: CancellationToken) = let oldProjectRefs = oldProject.ProjectReferences let newProjectRefs = newProject.ProjectReferences oldProjectRefs.Count() <> newProjectRefs.Count() || (oldProjectRefs, newProjectRefs) ||> Seq.exists2 (fun p1 p2 -> + ct.ThrowIfCancellationRequested() let doesProjectIdDiffer = p1.ProjectId <> p2.ProjectId let p1 = oldProject.Solution.GetProject(p1.ProjectId) let p2 = newProject.Solution.GetProject(p2.ProjectId) doesProjectIdDiffer || p1.Version <> p2.Version ) - let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) = + let isProjectInvalidated (oldProject: Project) (newProject: Project) (settings: EditorOptions) ct = let hasProjectVersionChanged = hasProjectVersionChanged oldProject newProject if settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences then - hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject + hasProjectVersionChanged || hasDependentVersionChanged oldProject newProject ct else hasProjectVersionChanged @@ -151,7 +152,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor | true, site -> Some site | _ -> None - let rec tryComputeOptions (project: Project) = + let rec tryComputeOptions (project: Project) ct = async { let projectId = project.Id match cache.TryGetValue(projectId) with @@ -167,7 +168,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor for projectReference in project.ProjectReferences do let referencedProject = project.Solution.GetProject(projectReference.ProjectId) if referencedProject.Language = FSharpConstants.FSharpLanguageName then - match! tryComputeOptions referencedProject with + match! tryComputeOptions referencedProject ct with | None -> canBail <- true | Some(_, projectOptions) -> referencedProjects.Add(referencedProject.OutputFilePath, projectOptions) @@ -239,9 +240,9 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor return Some(parsingOptions, projectOptions) | true, (oldProject, parsingOptions, projectOptions) -> - if isProjectInvalidated oldProject project settings then + if isProjectInvalidated oldProject project settings ct then cache.TryRemove(projectId) |> ignore - return! tryComputeOptions project + return! tryComputeOptions project ct else return Some(parsingOptions, projectOptions) } @@ -266,7 +267,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor // We do this to prevent any possible cache thrashing in FCS. let project = document.Project.Solution.Workspace.CurrentSolution.GetProject(document.Project.Id) if not (isNull project) then - let! options = tryComputeOptions project + let! options = tryComputeOptions project ct reply.Reply options else reply.Reply None @@ -286,7 +287,7 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor // We do this to prevent any possible cache thrashing in FCS. let project = project.Solution.Workspace.CurrentSolution.GetProject(project.Id) if not (isNull project) then - let! options = tryComputeOptions project + let! options = tryComputeOptions project ct reply.Reply options else reply.Reply None From 38822d2cf1798f072cd3ca1e54a32fdfd034d25f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 12 Mar 2021 10:48:37 -0800 Subject: [PATCH 02/35] Minor cleanup --- src/fsharp/service/IncrementalBuild.fs | 7 ------- src/fsharp/service/IncrementalBuild.fsi | 7 ------- src/fsharp/service/service.fs | 11 +++-------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index f606df57bd1..d08ce495aee 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1195,13 +1195,6 @@ type IncrementalBuilder(tcGlobals, match result with | Some (boundModel, timestamp) -> Some (PartialCheckResults (boundModel, timestamp)) | _ -> None - - - member builder.AreCheckResultsBeforeFileInProjectReady filename = - let slotOfFile = builder.GetSlotOfFileName filename - match tryGetBeforeSlot currentState slotOfFile with - | Some _ -> true - | _ -> false member builder.TryGetCheckResultsBeforeFileInProject (filename) = let cache = TimeStampCache defaultTimeStamp diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 9df44aadf3c..9d8500e95da 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -170,13 +170,6 @@ type internal IncrementalBuilder = /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. member GetCheckResultsBeforeFileInProjectEvenIfStale: filename:string -> PartialCheckResults option - /// Get the preceding typecheck state of a slot, but only if it is up-to-date w.r.t. - /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available. - /// This is a relatively quick operation. - /// - /// This is safe for use from non-compiler threads - member AreCheckResultsBeforeFileInProjectReady: filename:string -> bool - /// Get the preceding typecheck state of a slot, WITH checking if it is up-to-date w.r.t. However, files will not be parsed or checked. /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available or if it is not up-to-date. /// diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 36c083c6277..a7557073153 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -444,6 +444,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options) = + // This is to check if the check results are still valid by their timestamp. + // A return of None means the file needs to be re-evaluated as a dependent has changed; therefore, do not get the cached result. match builder.TryGetCheckResultsForFileInProject filename with | None -> None | _ -> @@ -452,14 +454,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, sourceText.GetHashCode(), options))) match cachedResults with - | Some (parseResults, checkResults,_,priorTimeStamp) - when - (match builder.TryGetCheckResultsBeforeFileInProject filename with - | None -> false - | Some(tcPrior) -> - tcPrior.TimeStamp = priorTimeStamp && - builder.AreCheckResultsBeforeFileInProjectReady(filename)) -> - Some (parseResults,checkResults) + | Some (parseResults, checkResults, _, _) -> Some (parseResults, checkResults) | _ -> None /// 1. Repeatedly try to get cached file check results or get file "lock". From 641c08622fa627da2749b7703cfcf0921ef2f3e0 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 12 Mar 2021 11:12:56 -0800 Subject: [PATCH 03/35] Minor cleanup --- .../LanguageService/FSharpCheckerProvider.fs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index 99a1cc83520..1eae3a0131e 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -21,7 +21,6 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics type internal FSharpCheckerProvider [] ( - _analyzerService: IFSharpDiagnosticAnalyzerService, [)>] workspace: VisualStudioWorkspace, settings: EditorOptions ) = @@ -53,20 +52,16 @@ type internal FSharpCheckerProvider let checker = lazy - let checker = - FSharpChecker.Create( - projectCacheSize = settings.LanguageServicePerformance.ProjectCheckCacheSize, - keepAllBackgroundResolutions = false, - // Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches - (* , MaxMemory = 2300 *) - legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(), - tryGetMetadataSnapshot = tryGetMetadataSnapshot, - keepAllBackgroundSymbolUses = false, - enableBackgroundItemKeyStoreAndSemanticClassification = true, - enablePartialTypeChecking = true) - - - checker + FSharpChecker.Create( + projectCacheSize = settings.LanguageServicePerformance.ProjectCheckCacheSize, + keepAllBackgroundResolutions = false, + // Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches + (* , MaxMemory = 2300 *) + legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(), + tryGetMetadataSnapshot = tryGetMetadataSnapshot, + keepAllBackgroundSymbolUses = false, + enableBackgroundItemKeyStoreAndSemanticClassification = true, + enablePartialTypeChecking = true) member this.Checker = checker.Value From 7399456fe9d017a17d94f99574c325ed88f99ad9 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 17 Mar 2021 12:28:59 -0700 Subject: [PATCH 04/35] Added re-analysis back in just for scripts --- .../LanguageService/FSharpCheckerProvider.fs | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index 1eae3a0131e..9ad00223850 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -21,6 +21,7 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics type internal FSharpCheckerProvider [] ( + analyzerService: IFSharpDiagnosticAnalyzerService, [)>] workspace: VisualStudioWorkspace, settings: EditorOptions ) = @@ -52,16 +53,40 @@ type internal FSharpCheckerProvider let checker = lazy - FSharpChecker.Create( - projectCacheSize = settings.LanguageServicePerformance.ProjectCheckCacheSize, - keepAllBackgroundResolutions = false, - // Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches - (* , MaxMemory = 2300 *) - legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(), - tryGetMetadataSnapshot = tryGetMetadataSnapshot, - keepAllBackgroundSymbolUses = false, - enableBackgroundItemKeyStoreAndSemanticClassification = true, - enablePartialTypeChecking = true) + lazy + let checker = + FSharpChecker.Create( + projectCacheSize = settings.LanguageServicePerformance.ProjectCheckCacheSize, + keepAllBackgroundResolutions = false, + // Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches + (* , MaxMemory = 2300 *) + legacyReferenceResolver=LegacyMSBuildReferenceResolver.getResolver(), + tryGetMetadataSnapshot = tryGetMetadataSnapshot, + keepAllBackgroundSymbolUses = false, + enableBackgroundItemKeyStoreAndSemanticClassification = true, + enablePartialTypeChecking = true) + + // This is one half of the bridge between the F# background builder and the Roslyn analysis engine. + // 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) -> + // Only do this for scripts as misc script Rolsyn projects do not understand the dependencies of the script. e.x "#r "../test.dll"", "#load "test2.fsx"" + if isScriptFile fileName then + async { + try + let solution = workspace.CurrentSolution + let documentIds = solution.GetDocumentIdsWithFilePath(fileName) + if not documentIds.IsEmpty then + let documentIdsFiltered = documentIds |> Seq.filter workspace.IsDocumentOpen |> Seq.toArray + for documentId in documentIdsFiltered do + Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId) + if documentIdsFiltered.Length > 0 then + analyzerService.Reanalyze(workspace,documentIds=documentIdsFiltered) + with ex -> + Assert.Exception(ex) + } |> Async.StartImmediate + ) + checker member this.Checker = checker.Value From c7d1b4f3b61fa959d67f9c8431801c738a5ebeb5 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 17 Mar 2021 14:49:18 -0700 Subject: [PATCH 05/35] Added cacheStamp parameter to check file FCS APIs. Refactored FSharp.Editor to only call the FSharpChecker extensions for checking a file. --- src/fsharp/service/IncrementalBuild.fs | 12 +-- src/fsharp/service/IncrementalBuild.fsi | 13 +-- src/fsharp/service/service.fs | 87 ++++++++++--------- src/fsharp/service/service.fsi | 9 +- .../Classification/ClassificationService.fs | 2 +- .../CodeFix/AddOpenCodeFixProvider.fs | 2 +- .../ConvertCSharpLambdaToFSharpLambda.fs | 4 +- .../CodeFix/ConvertToAnonymousRecord.fs | 4 +- .../ImplementInterfaceCodeFixProvider.fs | 2 +- .../CodeFix/MakeDeclarationMutable.fs | 2 +- .../CodeFix/MakeOuterBindingRecursive.fs | 4 +- .../CodeFix/RemoveReturnOrYield.fs | 4 +- .../CodeFix/RenameUnusedValue.fs | 2 +- .../CodeFix/UseMutationWhenValueIsMutable.fs | 2 +- .../Commands/HelpContextService.fs | 9 +- .../Commands/XmlDocCommandService.fs | 4 +- .../Completion/CompletionProvider.fs | 16 ++-- .../FSharp.Editor/Completion/SignatureHelp.fs | 16 ++-- .../Debugging/BreakpointResolutionService.fs | 14 ++- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 24 ++--- .../SimplifyNameDiagnosticAnalyzer.fs | 2 +- .../Diagnostics/UnusedDeclarationsAnalyzer.fs | 2 +- .../UnusedOpensDiagnosticAnalyzer.fs | 2 +- .../DocumentHighlightsService.fs | 15 ++-- .../FSharpCheckerExtensions.fs | 58 ++++++++----- .../LanguageService/FSharpCheckerProvider.fs | 1 - .../LanguageService/SymbolHelpers.fs | 4 +- .../Navigation/FindUsagesService.fs | 2 +- .../Navigation/GoToDefinition.fs | 32 +++---- .../Navigation/NavigateToSearchService.fs | 7 +- .../Navigation/NavigationBarItemService.fs | 4 +- .../QuickInfo/QuickInfoProvider.fs | 12 +-- .../Structure/BlockStructureService.fs | 4 +- .../UnitTests/BreakpointResolutionService.fs | 6 +- .../UnitTests/CompletionProviderTests.fs | 7 +- .../DocumentDiagnosticAnalyzerTests.fs | 5 +- .../DocumentHighlightsServiceTests.fs | 4 +- .../UnitTests/FsxCompletionProviderTests.fs | 6 +- .../UnitTests/GoToDefinitionServiceTests.fs | 16 ++-- .../tests/UnitTests/QuickInfoTests.fs | 5 +- .../SemanticColorizationServiceTests.fs | 4 +- .../UnitTests/SignatureHelpProviderTests.fs | 25 +++--- .../tests/UnitTests/Tests.RoslynHelpers.fs | 35 ++++++++ .../UnitTests/VisualFSharp.UnitTests.fsproj | 1 + 44 files changed, 272 insertions(+), 219 deletions(-) create mode 100644 vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index d08ce495aee..03403258adc 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1207,16 +1207,8 @@ type IncrementalBuilder(tcGlobals, | Some(boundModel, timestamp) -> PartialCheckResults(boundModel, timestamp) |> Some | _ -> None - member builder.TryGetCheckResultsForFileInProject (filename) = - let cache = TimeStampCache defaultTimeStamp - let state = currentState - let state = computeStampedFileNames state cache - let state = computeStampedReferencedAssemblies state cache - - let slotOfFile = builder.GetSlotOfFileName filename - match tryGetSlot state slotOfFile with - | Some(boundModel, timestamp) -> PartialCheckResults(boundModel, timestamp) |> Some - | _ -> None + member builder.AreCheckResultsBeforeFileInProjectReady filename = + (builder.TryGetCheckResultsBeforeFileInProject filename).IsSome member private _.GetCheckResultsBeforeSlotInProject (ctok: CompilationThreadToken, slotOfFile, enablePartialTypeChecking) = cancellable { diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 9d8500e95da..bcaa09b9422 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -170,17 +170,18 @@ type internal IncrementalBuilder = /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. member GetCheckResultsBeforeFileInProjectEvenIfStale: filename:string -> PartialCheckResults option - /// Get the preceding typecheck state of a slot, WITH checking if it is up-to-date w.r.t. However, files will not be parsed or checked. - /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available or if it is not up-to-date. + /// Get the preceding typecheck state of a slot, but only if it is up-to-date w.r.t. + /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available. + /// This is a relatively quick operation. /// - /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. - member TryGetCheckResultsBeforeFileInProject: filename: string -> PartialCheckResults option + /// This is safe for use from non-compiler threads + member AreCheckResultsBeforeFileInProjectReady: filename:string -> bool - /// Get the typecheck state of a slot, WITH checking if it is up-to-date w.r.t. However, files will not be parsed or checked. + /// Get the preceding typecheck state of a slot, WITH checking if it is up-to-date w.r.t. However, files will not be parsed or checked. /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available or if it is not up-to-date. /// /// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread. - member TryGetCheckResultsForFileInProject: filename: string -> PartialCheckResults option + member TryGetCheckResultsBeforeFileInProject: filename: string -> PartialCheckResults option /// Get the preceding typecheck state of a slot. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index a7557073153..595e0f03186 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -67,14 +67,14 @@ module Helpers = && FSharpProjectOptions.UseSameProject(o1,o2) /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. parsing - let AreSameForParsing((fileName1: string, source1Hash: int, options1), (fileName2, source2Hash, options2)) = + let AreSameForParsing((fileName1: string, source1Hash: int64, options1), (fileName2, source2Hash, options2)) = fileName1 = fileName2 && options1 = options2 && source1Hash = source2Hash let AreSimilarForParsing((fileName1, _, _), (fileName2, _, _)) = fileName1 = fileName2 /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. checking - let AreSameForChecking3((fileName1: string, source1Hash: int, options1: FSharpProjectOptions), (fileName2, source2Hash, options2)) = + let AreSameForChecking3((fileName1: string, source1Hash: int64, options1: FSharpProjectOptions), (fileName2, source2Hash, options2)) = (fileName1 = fileName2) && FSharpProjectOptions.AreSameForChecking(options1,options2) && source1Hash = source2Hash @@ -193,7 +193,8 @@ module CompileHelpers = System.Console.SetError error | None -> () -type SourceTextHash = int +type SourceTextHash = int64 +type CacheStamp = int64 type FileName = string type FilePath = string type ProjectPath = string @@ -364,7 +365,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let parseCacheLock = Lock() // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.parseFileInProjectCache. Most recently used cache for parsing files. - let parseFileCache = MruCache(parseFileCacheSize, areSimilar = AreSimilarForParsing, areSame = AreSameForParsing) + let parseFileCache = MruCache(parseFileCacheSize, areSimilar = AreSimilarForParsing, areSame = AreSameForParsing) // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.checkFileInProjectCachePossiblyStale // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.checkFileInProjectCache @@ -382,7 +383,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC // Also keyed on source. This can only be out of date if the antecedent is out of date let checkFileInProjectCache = - MruCache + MruCache (keepStrongly=checkFileInProjectCacheSize, areSame=AreSameForChecking3, areSimilar=AreSubsumable3) @@ -398,15 +399,15 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC static let mutable actualCheckFileCount = 0 - member _.RecordCheckFileInProjectResults(filename,options,parsingOptions,parseResults,fileVersion,priorTimeStamp,checkAnswer,sourceText) = + member _.RecordCheckFileInProjectResults(filename,options,parsingOptions,parseResults,fileVersion,priorTimeStamp,checkAnswer,hash,cacheStamp) = match checkAnswer with | None -> () | Some typedResults -> actualCheckFileCount <- actualCheckFileCount + 1 parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCachePossiblyStale.Set(ltok, (filename,options),(parseResults,typedResults,fileVersion)) - checkFileInProjectCache.Set(ltok, (filename, sourceText, options),(parseResults,typedResults,fileVersion,priorTimeStamp)) - parseFileCache.Set(ltok, (filename, sourceText, parsingOptions), parseResults)) + checkFileInProjectCache.Set(ltok, (filename, cacheStamp, options),(parseResults,typedResults,fileVersion,priorTimeStamp)) + parseFileCache.Set(ltok, (filename, hash, parsingOptions), parseResults)) member bc.ImplicitlyStartCheckProjectInBackground(options, userOpName) = if implicitlyStartBackgroundWork then @@ -415,7 +416,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member _.ParseFile(filename: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string) = async { if cache then - let hash = sourceText.GetHashCode() + let hash = sourceText.GetHashCode() |> int64 match parseCacheLock.AcquireLock(fun ltok -> parseFileCache.TryGet(ltok, (filename, hash, options))) with | Some res -> return res | None -> @@ -443,19 +444,19 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC return FSharpParseFileResults(diagnostics = diagnostics, input = parseTree, parseHadErrors = false, dependencyFiles = builder.AllDependenciesDeprecated) } - member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options) = - // This is to check if the check results are still valid by their timestamp. - // A return of None means the file needs to be re-evaluated as a dependent has changed; therefore, do not get the cached result. - match builder.TryGetCheckResultsForFileInProject filename with - | None -> None - | _ -> + member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options, cacheStamp: int64 option) = + // If a cache stamp is not provided, we need to do a full-up-to-date check on the timestamps for the dependencies. + let recheckDeps = cacheStamp.IsNone + if recheckDeps && not (builder.AreCheckResultsBeforeFileInProjectReady filename) then None + else + let cacheStamp = defaultArg cacheStamp (sourceText.GetHashCode() |> int64) - // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date - let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, sourceText.GetHashCode(), options))) + // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date + let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, cacheStamp, options))) - match cachedResults with - | Some (parseResults, checkResults, _, _) -> Some (parseResults, checkResults) - | _ -> None + match cachedResults with + | Some (parseResults, checkResults, _, _) -> Some (parseResults, checkResults) + | _ -> None /// 1. Repeatedly try to get cached file check results or get file "lock". /// @@ -479,20 +480,23 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC builder: IncrementalBuilder, tcPrior: PartialCheckResults, tcInfo: TcInfo, - creationDiags: FSharpDiagnostic[]) = - + creationDiags: FSharpDiagnostic[], + cacheStamp: int64 option) = + async { let beingCheckedFileKey = fileName, options, fileVersion let stopwatch = Stopwatch.StartNew() let rec loop() = async { // results may appear while we were waiting for the lock, let's recheck if it's the case - let cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) + let cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options, cacheStamp) match cachedResults with | Some (_, checkResults) -> return FSharpCheckFileAnswer.Succeeded checkResults | None -> if beingCheckedFileTable.TryAdd(beingCheckedFileKey, ()) then + let hash: SourceTextHash = sourceText.GetHashCode() |> int64 + let cacheStamp = defaultArg cacheStamp hash try // Get additional script #load closure information if applicable. // For scripts, this will have been recorded by GetProjectOptionsFromScript. @@ -521,7 +525,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC suggestNamesForErrors) |> Cancellable.toAsync let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, Array.ofList builder.SourceFiles, options.UseScriptResolutionRules) reactor.SetPreferredUILang tcConfig.preferredUiLang - bc.RecordCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, tcPrior.TimeStamp, Some checkAnswer, sourceText.GetHashCode()) + bc.RecordCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, tcPrior.TimeStamp, Some checkAnswer, hash, cacheStamp) return FSharpCheckFileAnswer.Succeeded checkAnswer finally let dummy = ref () @@ -549,7 +553,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match builderOpt with | Some builder -> - match bc.GetCachedCheckFileResult(builder, filename, sourceText, options) with + match bc.GetCachedCheckFileResult(builder, filename, sourceText, options, None) with | Some (_, checkResults) -> return Some (builder, creationDiags, Some (FSharpCheckFileAnswer.Succeeded checkResults)) | _ -> return Some (builder, creationDiags, None) | _ -> return None // the builder wasn't ready @@ -571,7 +575,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match tcPrior with | Some(tcPrior, tcInfo) -> - let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags) + let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags, None) return Some checkResults | None -> return None // the incremental builder was not up to date finally @@ -579,7 +583,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC } /// Type-check the result obtained by parsing. Force the evaluation of the antecedent type checking context if needed. - member bc.CheckFileInProject(parseResults: FSharpParseFileResults, filename, fileVersion, sourceText: ISourceText, options, userOpName) = + member bc.CheckFileInProject(parseResults: FSharpParseFileResults, filename, fileVersion, sourceText: ISourceText, options, cacheStamp, userOpName) = let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "CheckFileInProject", filename, action) async { @@ -591,7 +595,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | None -> return FSharpCheckFileAnswer.Succeeded (FSharpCheckFileResults.MakeEmpty(filename, creationDiags, keepAssemblyContents)) | Some builder -> // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date - let cachedResults = bc.GetCachedCheckFileResult(builder, filename, sourceText, options) + let cachedResults = bc.GetCachedCheckFileResult(builder, filename, sourceText, options, cacheStamp) match cachedResults with | Some (_, checkResults) -> return FSharpCheckFileAnswer.Succeeded checkResults @@ -609,14 +613,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let! tcInfo = tcPrior.GetTcInfo() |> Eventually.toCancellable return (tcPrior, tcInfo) } - let! checkAnswer = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags) + let! checkAnswer = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags, cacheStamp) return checkAnswer finally bc.ImplicitlyStartCheckProjectInBackground(options, userOpName) } /// Parses and checks the source file and returns untyped AST and check results. - member bc.ParseAndCheckFileInProject (filename:string, fileVersion, sourceText: ISourceText, options:FSharpProjectOptions, userOpName) = + member bc.ParseAndCheckFileInProject (filename:string, fileVersion, sourceText: ISourceText, options:FSharpProjectOptions, cacheStamp, userOpName) = let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "ParseAndCheckFileInProject", filename, action) async { @@ -638,7 +642,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC return (parseResults, FSharpCheckFileAnswer.Aborted) | Some builder -> - let cachedResults = bc.GetCachedCheckFileResult(builder, filename, sourceText, options) + let cachedResults = bc.GetCachedCheckFileResult(builder, filename, sourceText, options, cacheStamp) match cachedResults with | Some (parseResults, checkResults) -> @@ -665,7 +669,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC reactor.SetPreferredUILang tcPrior.TcConfig.preferredUiLang let parseDiags, parseTree, anyErrors = ParseAndCheckFile.parseFile (sourceText, filename, parsingOptions, userOpName, suggestNamesForErrors) let parseResults = FSharpParseFileResults(parseDiags, parseTree, anyErrors, builder.AllDependenciesDeprecated) - let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags) + let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, creationDiags, cacheStamp) Logger.LogBlockMessageStop (filename + strGuid + "-Successful") LogCompilerFunctionId.Service_ParseAndCheckFileInProject @@ -765,11 +769,12 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | Some sc -> return Some (sc.GetView ()) }) /// Try to get recent approximate type check results for a file. - member _.TryGetRecentCheckResultsForFile(filename: string, options:FSharpProjectOptions, sourceText: ISourceText option, _userOpName: string) = + member _.TryGetRecentCheckResultsForFile(filename: string, options:FSharpProjectOptions, sourceText: ISourceText option, cacheStamp: CacheStamp option, _userOpName: string) = parseCacheLock.AcquireLock (fun ltok -> match sourceText with | Some sourceText -> - match checkFileInProjectCache.TryGet(ltok,(filename,sourceText.GetHashCode(),options)) with + let cacheStamp = defaultArg cacheStamp (sourceText.GetHashCode() |> int64) + match checkFileInProjectCache.TryGet(ltok,(filename,cacheStamp,options)) with | Some (a,b,c,_) -> Some (a,b,c) | None -> checkFileInProjectCachePossiblyStale.TryGet(ltok,(filename,options)) | None -> checkFileInProjectCachePossiblyStale.TryGet(ltok,(filename,options))) @@ -1070,7 +1075,7 @@ type FSharpChecker(legacyReferenceResolver, member _.MatchBraces(filename, sourceText: ISourceText, options: FSharpParsingOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" - let hash = sourceText.GetHashCode() + let hash = sourceText.GetHashCode() |> int64 async { match braceMatchCache.TryGet(AnyCallerThread, (filename, hash, options)) with | Some res -> return res @@ -1109,9 +1114,9 @@ type FSharpChecker(legacyReferenceResolver, backgroundCompiler.GetBackgroundCheckResultsForFileInProject(filename,options, userOpName) /// Try to get recent approximate type check results for a file. - member _.TryGetRecentCheckResultsForFile(filename: string, options:FSharpProjectOptions, ?sourceText, ?userOpName: string) = + member _.TryGetRecentCheckResultsForFile(filename: string, options:FSharpProjectOptions, ?sourceText, ?userOpName: string, ?cacheStamp: int64) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.TryGetRecentCheckResultsForFile(filename,options,sourceText, userOpName) + backgroundCompiler.TryGetRecentCheckResultsForFile(filename,options,sourceText,cacheStamp,userOpName) member _.Compile(argv: string[], ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" @@ -1251,17 +1256,17 @@ type FSharpChecker(legacyReferenceResolver, /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. - member ic.CheckFileInProject(parseResults:FSharpParseFileResults, filename:string, fileVersion:int, sourceText:ISourceText, options:FSharpProjectOptions, ?userOpName: string) = + member ic.CheckFileInProject(parseResults:FSharpParseFileResults, filename:string, fileVersion:int, sourceText:ISourceText, options:FSharpProjectOptions, ?userOpName: string, ?cacheStamp: int64) = let userOpName = defaultArg userOpName "Unknown" ic.CheckMaxMemoryReached() - backgroundCompiler.CheckFileInProject(parseResults,filename,fileVersion,sourceText,options,userOpName) + backgroundCompiler.CheckFileInProject(parseResults,filename,fileVersion,sourceText,options,cacheStamp,userOpName) /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. - member ic.ParseAndCheckFileInProject(filename:string, fileVersion:int, sourceText:ISourceText, options:FSharpProjectOptions, ?userOpName: string) = + member ic.ParseAndCheckFileInProject(filename:string, fileVersion:int, sourceText:ISourceText, options:FSharpProjectOptions, ?userOpName: string, ?cacheStamp: int64) = let userOpName = defaultArg userOpName "Unknown" ic.CheckMaxMemoryReached() - backgroundCompiler.ParseAndCheckFileInProject(filename, fileVersion, sourceText, options, userOpName) + backgroundCompiler.ParseAndCheckFileInProject(filename, fileVersion, sourceText, options, cacheStamp, userOpName) member ic.ParseAndCheckProject(options, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index 0e5d5c9218e..fdb0a8d4766 100644 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -121,7 +121,8 @@ type public FSharpChecker = /// The full source for the file. /// The options for the project or script. /// An optional string used for tracing compiler operations associated with this request. - member CheckFileInProject: parseResults: FSharpParseFileResults * filename: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async + /// Used to determine if we should use cached results. If None, it will use ISourceText.GetHashCode. + member CheckFileInProject: parseResults: FSharpParseFileResults * filename: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string * ?cacheStamp: int64 -> Async /// /// @@ -140,7 +141,8 @@ type public FSharpChecker = /// The source for the file. /// The options for the project or script. /// An optional string used for tracing compiler operations associated with this request. - member ParseAndCheckFileInProject: filename: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async + /// Used to determine if we should use cached results. If None, it will use ISourceText.GetHashCode. + member ParseAndCheckFileInProject: filename: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string * ?cacheStamp: int64 -> Async /// /// Parse and typecheck all files in a project. @@ -349,7 +351,8 @@ type public FSharpChecker = /// The options for the project or script, used to determine active --define conditionals and other options relevant to parsing. /// Optionally, specify source that must match the previous parse precisely. /// An optional string used for tracing compiler operations associated with this request. - member TryGetRecentCheckResultsForFile: filename: string * options:FSharpProjectOptions * ?sourceText: ISourceText * ?userOpName: string -> (FSharpParseFileResults * FSharpCheckFileResults * (*version*)int) option + /// Used to determine if we should use cached results. If None, it will use ISourceText.GetHashCode. + member TryGetRecentCheckResultsForFile: filename: string * options:FSharpProjectOptions * ?sourceText: ISourceText * ?userOpName: string * ?cacheStamp: int64 -> (FSharpParseFileResults * FSharpCheckFileResults * (*version*)int) option /// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation. member InvalidateAll: unit -> unit diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index 0abfb224940..a3844ae749e 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -179,7 +179,7 @@ type internal FSharpClassificationService do! semanticClassificationCache.SetAsync(document, classificationDataLookup) |> liftAsync addSemanticClassificationByLookup sourceText textSpan classificationDataLookup result else - let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = false, userOpName=userOpName) + let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = false, userOpName=userOpName) let targetRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText) let classificationData = checkResults.GetSemanticClassification (Some targetRange) addSemanticClassification sourceText textSpan classificationData result diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs index 7c1bc8e75f0..3890eba616f 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs @@ -90,7 +90,7 @@ type internal FSharpAddOpenCodeFixProvider let document = context.Document let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) let! sourceText = context.Document.GetTextAsync(context.CancellationToken) - let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName) + let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName) let line = sourceText.Lines.GetLineFromPosition(context.Span.End) let linePos = sourceText.Lines.GetLinePosition(context.Span.End) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs index af96ed0b07c..169588e1c84 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs @@ -23,10 +23,10 @@ type internal FSharpConvertCSharpLambdaToFSharpLambdaCodeFixProvider override _.RegisterCodeFixesAsync context = asyncMaybe { - let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName) - let! parseResults = checkerProvider.Checker.ParseFile(context.Document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync + let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName) + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let errorRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) let! fullParenRange, lambdaArgRange, lambdaBodyRange = parseResults.TryRangeOfParenEnclosingOpEqualsGreaterUsage errorRange.Start diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs b/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs index 2592e8d9aa2..3710101ed4e 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs @@ -29,9 +29,9 @@ type internal FSharpConvertToAnonymousRecordCodeFixProvider asyncMaybe { let document = context.Document let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) - let! sourceText = context.Document.GetTextAsync(context.CancellationToken) - let! parseResults = checkerProvider.Checker.ParseFile(document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync + let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName=userOpName) + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let errorRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText) let! recordRange = parseResults.TryRangeOfRecordExpressionContainingPos errorRange.Start let! recordSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, recordRange) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs index f25a57441b8..c21a1123380 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -145,7 +145,7 @@ type internal FSharpImplementInterfaceCodeFixProvider let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName) let cancellationToken = context.CancellationToken let! sourceText = context.Document.GetTextAsync(cancellationToken) - let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, sourceText = sourceText, userOpName = userOpName) + let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition context.Span.Start let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions // Notice that context.Span doesn't return reliable ranges to find tokens at exact positions. diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs index a9cb5ba1e04..9aab9475320 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs @@ -46,7 +46,7 @@ type internal FSharpMakeDeclarationMutableFixProvider let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName) let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let decl = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs b/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs index 34d4487b3fa..67b586688e5 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs @@ -24,10 +24,10 @@ type internal FSharpMakeOuterBindingRecursiveCodeFixProvider override _.RegisterCodeFixesAsync context = asyncMaybe { - let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName) - let! parseResults = checkerProvider.Checker.ParseFile(context.Document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync + let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName) + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let diagnosticRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) do! Option.guard (parseResults.IsPosContainedInApplication diagnosticRange.Start) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs index be68ed8240f..59e6ff102c1 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs @@ -23,10 +23,10 @@ type internal FSharpRemoveReturnOrYieldCodeFixProvider override _.RegisterCodeFixesAsync context = asyncMaybe { - let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName) - let! parseResults = checkerProvider.Checker.ParseFile(context.Document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync + let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName=userOpName) + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let errorRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) let! exprRange = parseResults.TryRangeOfExprInYieldOrReturn errorRange.Start let! exprSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, exprRange) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs index 292509db74f..f7538842ad1 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs @@ -42,7 +42,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider // where backtickes are replaced with parens. if not (PrettyNaming.IsOperatorOrBacktickedName ident) && not (ident.StartsWith "``") then let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) - let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName) let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, context.Span.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs b/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs index 6f1583d07ae..44a1fa5682d 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs @@ -56,7 +56,7 @@ type internal FSharpUseMutationWhenValueIsMutableFixProvider let textLine = sourceText.Lines.GetLineFromPosition adjustedPosition let textLinePos = sourceText.Lines.GetLinePosition adjustedPosition let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName) let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, adjustedPosition, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland) diff --git a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs index 51c52182df1..1f77bba3428 100644 --- a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs @@ -13,6 +13,7 @@ open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.EditorServices open FSharp.Compiler.Syntax open FSharp.Compiler.Text +open Microsoft.CodeAnalysis [] [, FSharpConstants.FSharpLanguageName)>] @@ -24,9 +25,10 @@ type internal FSharpHelpContextService ) = static let userOpName = "ImplementInterfaceCodeFix" - static member GetHelpTerm(checker: FSharpChecker, sourceText : SourceText, fileName, options, span: TextSpan, tokens: List, textVersion, perfOptions) : Async = + static member GetHelpTerm(checker: FSharpChecker, document: Document, options, span: TextSpan, tokens: List, perfOptions) : Async = asyncMaybe { - let! _, _, check = checker.ParseAndCheckDocument(fileName, textVersion, sourceText, options, perfOptions, userOpName = userOpName) + let! _, _, check = checker.ParseAndCheckDocument(document, options, perfOptions, userOpName) + let! sourceText = document.GetTextAsync() |> liftTaskAsync let textLines = sourceText.Lines let lineInfo = textLines.GetLineFromPosition(span.Start) let line = lineInfo.LineNumber @@ -101,12 +103,11 @@ type internal FSharpHelpContextService asyncMaybe { let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) let textLine = sourceText.Lines.GetLineFromPosition(textSpan.Start) let classifiedSpans = Tokenizer.getClassifiedSpans(document.Id, sourceText, textLine.Span, Some document.Name, defines, cancellationToken) let perfOptions = document.FSharpOptions.LanguageServicePerformance - return! FSharpHelpContextService.GetHelpTerm(checkerProvider.Checker, sourceText, document.FilePath, projectOptions, textSpan, classifiedSpans, textVersion.GetHashCode(), perfOptions) + return! FSharpHelpContextService.GetHelpTerm(checkerProvider.Checker, document, projectOptions, textSpan, classifiedSpans, perfOptions) } |> Async.map (Option.defaultValue "") |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index 5e7f33d5aa4..4dd22f0ffa1 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -70,8 +70,8 @@ type internal XmlDocCommandFilter let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName) let! cancellationToken = Async.CancellationToken |> liftAsync let! sourceText = document.GetTextAsync(cancellationToken) - let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) - let xmlDocables = XmlDocParser.GetXmlDocables (sourceText.ToFSharpSourceText(), parsedInput) + let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName) + let xmlDocables = XmlDocParser.GetXmlDocables (sourceText.ToFSharpSourceText(), parseResults.ParseTree) let xmlDocablesBelowThisLine = // +1 because looking below current line for e.g. a 'member' xmlDocables |> List.filter (fun (XmlDocable(line,_indent,_paramNames)) -> line = curLineNum+1) diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 4ae416cc9c2..f99d696c62e 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -107,11 +107,12 @@ type internal FSharpCompletionProvider (triggerChar = '.' || (intelliSenseOptions.ShowAfterCharIsTyped && CompletionUtils.isStartingNewWord(sourceText, triggerPosition))) - static member ProvideCompletionsAsyncAux(checker: FSharpChecker, sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, filePath: string, - textVersionHash: int, getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) = + static member ProvideCompletionsAsyncAux(checker: FSharpChecker, document: Document, caretPosition: int, options: FSharpProjectOptions, + getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) = asyncMaybe { - let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName = userOpName) + let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(document, options, languageServicePerformanceOptions, userOpName = userOpName) + let! sourceText = document.GetTextAsync() |> liftTaskAsync let textLines = sourceText.Lines let caretLinePos = textLines.GetLinePosition(caretPosition) let caretLine = textLines.GetLineFromPosition(caretPosition) @@ -223,14 +224,13 @@ type internal FSharpCompletionProvider let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) - let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) let getAllSymbols(fileCheckResults: FSharpCheckFileResults) = if settings.IntelliSense.IncludeSymbolsFromUnopenedNamespacesOrModules then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) else [] let! results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, projectOptions, document.FilePath, - textVersion.GetHashCode(), getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, context.Document, context.Position, projectOptions, + getAllSymbols, settings.LanguageServicePerformance, settings.IntelliSense) context.AddItems(results) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask context.CancellationToken @@ -292,14 +292,14 @@ type internal FSharpCompletionProvider let textWithItemCommitted = sourceText.WithChanges(TextChange(item.Span, nameInCode)) let line = sourceText.Lines.GetLineFromPosition(item.Span.Start) let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) - let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) + let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName) let fullNameIdents = fullName |> Option.map (fun x -> x.Split '.') |> Option.defaultValue [||] let insertionPoint = if settings.CodeFixes.AlwaysPlaceOpensAtTopLevel then OpenStatementInsertionPoint.TopLevel else OpenStatementInsertionPoint.Nearest - let ctx = ParsedInput.FindNearestPointToInsertOpenDeclaration line.LineNumber parsedInput fullNameIdents insertionPoint + let ctx = ParsedInput.FindNearestPointToInsertOpenDeclaration line.LineNumber parseResults.ParseTree fullNameIdents insertionPoint let finalSourceText, changedSpanStartPos = OpenDeclarationHelper.insertOpenDeclaration textWithItemCommitted ctx ns let fullChangingSpan = TextSpan.FromBounds(changedSpanStartPos, item.Span.End) let changedSpan = TextSpan.FromBounds(changedSpanStartPos, item.Span.End + (finalSourceText.Length - sourceText.Length)) diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 5baf4bf593f..d4a6c337fc6 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -446,21 +446,20 @@ type internal FSharpSignatureHelpProvider defines: string list, checker: FSharpChecker, documentationBuilder: IDocumentationBuilder, - sourceText: SourceText, caretPosition: int, options: FSharpProjectOptions, - filePath: string, - textVersionHash: int, triggerTypedChar: char option, possibleCurrentSignatureHelpSessionKind: CurrentSignatureHelpSessionKind option ) = asyncMaybe { + let! sourceText = document.GetTextAsync() |> liftTaskAsync + let textLines = sourceText.Lines let perfOptions = document.FSharpOptions.LanguageServicePerformance let caretLinePos = textLines.GetLinePosition(caretPosition) let caretLineColumn = caretLinePos.Character - let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, perfOptions, userOpName = userOpName) + let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(document, options, perfOptions, userOpName = userOpName) let adjustedColumnInSource = let rec loop ch pos = @@ -487,7 +486,7 @@ type internal FSharpSignatureHelpProvider sourceText, caretPosition, adjustedColumnInSource, - filePath) + document.FilePath) | _, Some FunctionApplication when adjustedColumnChar <> ',' && adjustedColumnChar <> '(' && adjustedColumnChar <> '<' -> return! FSharpSignatureHelpProvider.ProvideParametersAsyncAux( @@ -499,7 +498,7 @@ type internal FSharpSignatureHelpProvider sourceText, caretPosition, adjustedColumnInSource, - filePath) + document.FilePath) | _ -> let! paramInfoLocations = parseResults.FindParameterLocations(Position.fromZ caretLinePos.Line caretLineColumn) return! @@ -522,8 +521,6 @@ type internal FSharpSignatureHelpProvider asyncMaybe { let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) - let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) let checker = checkerProvider.Checker let triggerTypedChar = @@ -539,11 +536,8 @@ type internal FSharpSignatureHelpProvider defines, checker, documentationBuilder, - sourceText, position, projectOptions, - document.FilePath, - textVersion.GetHashCode(), triggerTypedChar, possibleCurrentSignatureHelpSessionKind) match signatureHelpDataOpt with diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs index fc542a396e6..77f3081d879 100644 --- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs +++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs @@ -26,8 +26,12 @@ type internal FSharpBreakpointResolutionService ) = static let userOpName = "BreakpointResolution" - static member GetBreakpointLocation(checker: FSharpChecker, sourceText: SourceText, fileName: string, textSpan: TextSpan, parsingOptions: FSharpParsingOptions) = + static member GetBreakpointLocation(checker: FSharpChecker, document: Document, textSpan: TextSpan, parsingOptions: FSharpParsingOptions) = async { + let! ct = Async.CancellationToken + + let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask + let textLinePos = sourceText.Lines.GetLinePosition(textSpan.Start) let textInLine = sourceText.GetSubText(sourceText.Lines.[textLinePos.Line].Span).ToString() @@ -36,16 +40,18 @@ type internal FSharpBreakpointResolutionService else let textLineColumn = textLinePos.Character let fcsTextLineNumber = Line.fromZ textLinePos.Line // Roslyn line numbers are zero-based, FSharp.Compiler.Service line numbers are 1-based - let! parseResults = checker.ParseFile(fileName, sourceText.ToFSharpSourceText(), parsingOptions, userOpName = userOpName) - return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn) + let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName) + match parseResults with + | Some parseResults -> return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn) + | _ -> return None } interface IFSharpBreakpointResolutionService with member this.ResolveBreakpointAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken): Task = asyncMaybe { let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) + let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, document, textSpan, parsingOptions) let! sourceText = document.GetTextAsync(cancellationToken) - let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, parsingOptions) let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) return FSharpBreakpointResolutionResult.CreateSpanResult(document, span) } diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 2ff45d77c38..47d1443c23e 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -56,15 +56,23 @@ type internal FSharpDocumentDiagnosticAnalyzer hash } - static member GetDiagnostics(checker: FSharpChecker, filePath: string, sourceText: SourceText, textVersionHash: int, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = + static member GetDiagnostics(checker: FSharpChecker, document: Document, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = async { - let fsSourceText = sourceText.ToFSharpSourceText() - let! parseResults = checker.ParseFile(filePath, fsSourceText, parsingOptions, userOpName=userOpName) + let! ct = Async.CancellationToken + + let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName) + match parseResults with + | None -> return ImmutableArray.Empty + | Some parseResults -> + + let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask + let filePath = document.FilePath + let! errors = async { match diagnosticType with | DiagnosticsType.Semantic -> - let! checkResultsAnswer = checker.CheckFileInProject(parseResults, filePath, textVersionHash, fsSourceText, options, userOpName=userOpName) + let! checkResultsAnswer = checker.CheckDocument(document, parseResults, options, userOpName) match checkResultsAnswer with | FSharpCheckFileAnswer.Aborted -> return [||] | FSharpCheckFileAnswer.Succeeded results -> @@ -109,10 +117,8 @@ type internal FSharpDocumentDiagnosticAnalyzer member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = asyncMaybe { let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) - let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) return! - FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) + FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document, parsingOptions, projectOptions, DiagnosticsType.Syntax) |> liftAsync } |> Async.map (Option.defaultValue ImmutableArray.Empty) @@ -121,11 +127,9 @@ type internal FSharpDocumentDiagnosticAnalyzer member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = asyncMaybe { let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) - let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then return! - FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic) + FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic) |> liftAsync else return ImmutableArray.Empty diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index 2431de357aa..4a5244a368b 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -49,7 +49,7 @@ type internal SimplifyNameDiagnosticAnalyzer | _ -> let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker - let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName=userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName) let! result = SimplifyNames.getSimplifiableNames(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync let mutable diag = ResizeArray() for r in result do diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs index c5d9e6b8c8b..aa456ef9f28 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -33,7 +33,7 @@ type internal UnusedDeclarationsAnalyzer | (_parsingOptions, projectOptions) -> let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker - let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName) let! unusedRanges = UnusedDeclarations.getUnusedDeclarations( checkResults, (isScriptFile document.FilePath)) |> liftAsync return unusedRanges diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index a00523409b2..259a2665db1 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -30,7 +30,7 @@ type internal UnusedOpensDiagnosticAnalyzer asyncMaybe { do! Option.guard document.FSharpOptions.CodeFixes.UnusedOpens let! sourceText = document.GetTextAsync() - let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, userOpName = userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, userOpName = userOpName) let! unusedOpens = UnusedOpens.getUnusedOpens(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync return unusedOpens } diff --git a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs index 46262e048ed..c2309227658 100644 --- a/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs +++ b/vsintegration/src/FSharp.Editor/DocumentHighlights/DocumentHighlightsService.fs @@ -51,14 +51,16 @@ type internal FSharpDocumentHighlightsService [] (checkerP |> Seq.distinctBy (fun span -> span.TextSpan.Start) |> Seq.toArray - static member GetDocumentHighlights(checker: FSharpChecker, documentKey: DocumentId, sourceText: SourceText, filePath: string, position: int, - defines: string list, options: FSharpProjectOptions, textVersionHash: int, languageServicePerformanceOptions: LanguageServicePerformanceOptions) : Async = + static member GetDocumentHighlights(checker: FSharpChecker, document: Document, position: int, + defines: string list, options: FSharpProjectOptions, languageServicePerformanceOptions: LanguageServicePerformanceOptions) : Async = asyncMaybe { + let! sourceText = document.GetTextAsync() |> liftTaskAsync + let filePath = document.FilePath let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! symbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false, false) - let! _, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName = userOpName) + let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false, false) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, languageServicePerformanceOptions, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland) let symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) return @@ -75,12 +77,9 @@ type internal FSharpDocumentHighlightsService [] (checkerP member _.GetDocumentHighlightsAsync(document, position, _documentsToSearch, cancellationToken) : Task> = asyncMaybe { let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) - let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let perfOptions = document.FSharpOptions.LanguageServicePerformance - let! spans = FSharpDocumentHighlightsService.GetDocumentHighlights(checkerProvider.Checker, document.Id, sourceText, document.FilePath, - position, defines, projectOptions, textVersion.GetHashCode(), perfOptions) + let! spans = FSharpDocumentHighlightsService.GetDocumentHighlights(checkerProvider.Checker, document, position, defines, projectOptions, perfOptions) let highlightSpans = spans |> Array.map (fun span -> diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs index e70577b9363..c164214c693 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs @@ -9,17 +9,46 @@ open Microsoft.CodeAnalysis.Text open FSharp.Compiler.CodeAnalysis type FSharpChecker with - member checker.ParseDocument(document: Document, parsingOptions: FSharpParsingOptions, sourceText: SourceText, userOpName: string) = + member checker.ParseDocument(document: Document, parsingOptions: FSharpParsingOptions, userOpName: string) = asyncMaybe { + let! ct = Async.CancellationToken |> liftAsync + + let! sourceText = document.GetTextAsync(ct) |> liftTaskAsync + let! fileParseResults = checker.ParseFile(document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync - return fileParseResults.ParseTree + return fileParseResults + } + + member checker.CheckDocument(document: Document, parseResults: FSharpParseFileResults, options: FSharpProjectOptions, userOpName: string) = + async { + let! ct = Async.CancellationToken + + let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask + let! textVersion = document.GetTextVersionAsync(ct) |> Async.AwaitTask + let! cacheStamp = document.Project.GetDependentVersionAsync(ct) |> Async.AwaitTask + + let filePath = document.FilePath + let textVersionHash = textVersion.GetHashCode() + let cacheStamp = int64(cacheStamp.GetHashCode()) + + return! checker.CheckFileInProject(parseResults, filePath, textVersionHash, sourceText.ToFSharpSourceText(), options,cacheStamp=cacheStamp,userOpName=userOpName) } - member checker.ParseAndCheckDocument(filePath: string, textVersionHash: int, sourceText: SourceText, options: FSharpProjectOptions, languageServicePerformanceOptions: LanguageServicePerformanceOptions, userOpName: string) = + member checker.ParseAndCheckDocument(document: Document, options: FSharpProjectOptions, languageServicePerformanceOptions: LanguageServicePerformanceOptions, userOpName: string) = async { + let! ct = Async.CancellationToken + + let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask + let! textVersion = document.GetTextVersionAsync(ct) |> Async.AwaitTask + let! cacheStamp = document.Project.GetDependentVersionAsync(ct) |> Async.AwaitTask + + let filePath = document.FilePath + let textVersionHash = textVersion.GetHashCode() + let cacheStamp = int64(cacheStamp.GetHashCode()) + let parseAndCheckFile = async { - let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToFSharpSourceText(), options, userOpName=userOpName) + let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToFSharpSourceText(), options, cacheStamp=cacheStamp, userOpName=userOpName) return match checkFileAnswer with | FSharpCheckFileAnswer.Aborted -> @@ -51,7 +80,7 @@ type FSharpChecker with | Some x -> async.Return (Some x) | None -> async { - match checker.TryGetRecentCheckResultsForFile(filePath, options) with + match checker.TryGetRecentCheckResultsForFile(filePath, options, cacheStamp=cacheStamp, userOpName=userOpName) with | Some (parseResults, checkFileResults, _) -> return Some (parseResults, checkFileResults) | None -> @@ -63,26 +92,11 @@ type FSharpChecker with return bindParsedInput results } - - member checker.ParseAndCheckDocument(document: Document, options: FSharpProjectOptions, userOpName: string, ?allowStaleResults: bool, ?sourceText: SourceText) = + member checker.ParseAndCheckDocument(document: Document, options: FSharpProjectOptions, userOpName: string, ?allowStaleResults: bool) = async { - let! cancellationToken = Async.CancellationToken - let! sourceText = - match sourceText with - | Some x -> async.Return x - | None -> document.GetTextAsync(cancellationToken) |> Async.AwaitTask - let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask let perfOpts = match allowStaleResults with | Some b -> { document.FSharpOptions.LanguageServicePerformance with AllowStaleCompletionResults = b } | _ -> document.FSharpOptions.LanguageServicePerformance - return! checker.ParseAndCheckDocument(document.FilePath, textVersion.GetHashCode(), sourceText, options, perfOpts, userOpName=userOpName) + return! checker.ParseAndCheckDocument(document, options, perfOpts, userOpName=userOpName) } - - - member checker.TryParseAndCheckFileInProject (projectOptions, fileName, sourceText: SourceText, userOpName) = async { - let! (parseResults, checkAnswer) = checker.ParseAndCheckFileInProject (fileName,0,sourceText.ToFSharpSourceText(),projectOptions, userOpName=userOpName) - match checkAnswer with - | FSharpCheckFileAnswer.Aborted -> return None - | FSharpCheckFileAnswer.Succeeded checkResults -> return Some (parseResults,checkResults) - } diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs index 9ad00223850..317448f5cb8 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerProvider.fs @@ -53,7 +53,6 @@ type internal FSharpCheckerProvider let checker = lazy - lazy let checker = FSharpChecker.Create( projectCacheSize = settings.LanguageServicePerformance.ProjectCheckCacheSize, diff --git a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs index 9d49d42fb8f..3ed760c5bae 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs @@ -22,8 +22,6 @@ module internal SymbolHelpers = asyncMaybe { let! cancellationToken = Async.CancellationToken |> liftAsync let! sourceText = document.GetTextAsync(cancellationToken) - let! textVersion = document.GetTextVersionAsync(cancellationToken) - let textVersionHash = textVersion.GetHashCode() let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line @@ -31,7 +29,7 @@ module internal SymbolHelpers = let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let settings = document.FSharpOptions - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document.FilePath, textVersionHash, sourceText, projectOptions, settings.LanguageServicePerformance, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, settings.LanguageServicePerformance, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland) let! ct = Async.CancellationToken |> liftAsync let symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol, cancellationToken=ct) diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index 9aa6f22a67e..53a0e68bd25 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -53,7 +53,7 @@ type internal FSharpFindUsagesService let! sourceText = document.GetTextAsync(context.CancellationToken) |> Async.AwaitTask |> liftAsync let checker = checkerProvider.Checker let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, context.CancellationToken, userOpName) - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition(position).ToString() let lineNumber = sourceText.Lines.GetLinePosition(position).Line + 1 let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index 5e7a92b33d0..df85f013fc8 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -191,7 +191,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let fcsTextLineNumber = Line.fromZ textLinePos.Line let lineText = (sourceText.Lines.GetLineFromPosition position).ToString() - let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, userOpName=userOpName) let idRange = lexerSymbol.Ident.idRange let! fsSymbolUse = checkFileResults.GetSymbolUseAtLocation (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland) let symbol = fsSymbolUse.Symbol @@ -204,7 +204,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let! implDoc = originDocument.Project.Solution.TryGetDocumentFromPath fsfilePath let! implSourceText = implDoc.GetTextAsync () let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDoc, CancellationToken.None, userOpName) - let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, sourceText=implSourceText, userOpName=userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, userOpName=userOpName) let symbolUses = checkFileResults.GetUsesOfSymbolInFile symbol let! implSymbol = symbolUses |> Array.tryHead let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, implSymbol.Range) @@ -217,18 +217,16 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP /// if the symbol is defined in the given file, return its declaration location, otherwise use the targetSymbol to find the first /// instance of its presence in the provided source file. The first case is needed to return proper declaration location for /// recursive type definitions, where the first its usage may not be the declaration. - member _.FindSymbolDeclarationInFile(targetSymbolUse: FSharpSymbolUse, filePath: string, sourceText: SourceText, options: FSharpProjectOptions, fileVersion:int) = + member _.FindSymbolDeclarationInDocument(targetSymbolUse: FSharpSymbolUse, document: Document, options: FSharpProjectOptions) = asyncMaybe { + let filePath = document.FilePath match targetSymbolUse.Symbol.DeclarationLocation with | Some decl when decl.FileName = filePath -> return decl | _ -> - let! _, checkFileAnswer = checker.ParseAndCheckFileInProject (filePath, fileVersion, sourceText.ToFSharpSourceText(), options, userOpName = userOpName) |> liftAsync - match checkFileAnswer with - | FSharpCheckFileAnswer.Aborted -> return! None - | FSharpCheckFileAnswer.Succeeded checkFileResults -> - let symbolUses = checkFileResults.GetUsesOfSymbolInFile targetSymbolUse.Symbol - let! implSymbol = symbolUses |> Array.tryHead - return implSymbol.Range + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, userOpName) + let symbolUses = checkFileResults.GetUsesOfSymbolInFile targetSymbolUse.Symbol + let! implSymbol = symbolUses |> Array.tryHead + return implSymbol.Range } member private this.FindDefinitionAtPosition(originDocument: Document, position: int) = @@ -244,7 +242,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let preferSignature = isSignatureFile originDocument.FilePath - let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, userOpName=userOpName) let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position,originDocument.FilePath, defines, SymbolLookupKind.Greedy, false, false) let idRange = lexerSymbol.Ident.idRange @@ -286,11 +284,9 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let implFilePath = Path.ChangeExtension (originDocument.FilePath,"fs") if not (File.Exists implFilePath) then return! None else let! implDocument = originDocument.Project.Solution.TryGetDocumentFromPath implFilePath - let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync - let! implVersion = implDocument.GetTextVersionAsync () |> liftTaskAsync - let! targetRange = this.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText, projectOptions, implVersion.GetHashCode()) - + let! targetRange = this.FindSymbolDeclarationInDocument(targetSymbolUse, implDocument, projectOptions) + let! implSourceText = implDocument.GetTextAsync() |> liftTaskAsync let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange) let navItem = FSharpGoToDefinitionNavigableItem (implDocument, implTextSpan) return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange) @@ -324,12 +320,12 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP else sigDocument.FilePath let! implDocument = originDocument.Project.Solution.TryGetDocumentFromPath implFilePath - let! implVersion = implDocument.GetTextVersionAsync () |> liftTaskAsync - let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(implDocument, CancellationToken.None, userOpName) - let! targetRange = this.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText, projectOptions, implVersion.GetHashCode()) + let! targetRange = this.FindSymbolDeclarationInDocument(targetSymbolUse, implDocument, projectOptions) + let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync let! implTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (implSourceText, targetRange) let navItem = FSharpGoToDefinitionNavigableItem (implDocument, implTextSpan) return (FSharpGoToDefinitionResult.NavigableItem(navItem), idRange) diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index 0260ebd0c59..ee864e3c623 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -177,9 +177,12 @@ type internal FSharpNavigateToSearchService let GetNavigableItems(document: Document, parsingOptions: FSharpParsingOptions, kinds: IImmutableSet) = async { let! cancellationToken = Async.CancellationToken - let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask - let! parseResults = checkerProvider.Checker.ParseFile(document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions) + let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName) + match parseResults with + | None -> return [||] + | Some parseResults -> + let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask let navItems parsedInput = NavigateTo.GetNavigableItems parsedInput |> Array.filter (fun i -> kinds.Contains(navigateToItemKindToRoslynKind i.Kind)) diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs index b89e7fbafbb..c83fb363a2b 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigationBarItemService.fs @@ -29,8 +29,8 @@ type internal FSharpNavigationBarItemService asyncMaybe { let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) - let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText=sourceText, userOpName=userOpName) - let navItems = Navigation.getNavigation parsedInput + let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName=userOpName) + let navItems = Navigation.getNavigation parseResults.ParseTree let rangeToTextSpan range = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) return navItems.Declarations diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index ef29e2a7546..03f7ab11341 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -61,7 +61,7 @@ module internal FSharpQuickInfo = let! extParsingOptions, extProjectOptions = projectInfoManager.TryGetOptionsByProject(document.Project, cancellationToken) let extDefines = CompilerEnvironment.GetCompilationDefinesForEditing extParsingOptions let! extLexerSymbol = Tokenizer.getSymbolAtPosition(extDocId, extSourceText, extSpan.Start, declRange.FileName, extDefines, SymbolLookupKind.Greedy, true, true) - let! _, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, sourceText=extSourceText, userOpName = userOpName) + let! _, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, userOpName = userOpName) let extQuickInfoText = extCheckFileResults.GetToolTip @@ -98,7 +98,7 @@ module internal FSharpQuickInfo = let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true, true) let idRange = lexerSymbol.Ident.idRange - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText=sourceText, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, userOpName = userOpName) let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line let lineText = (sourceText.Lines.GetLineFromPosition position).ToString() @@ -178,14 +178,16 @@ type internal FSharpAsyncQuickInfoSource ) = // test helper - static member ProvideQuickInfo(checker:FSharpChecker, documentId:DocumentId, sourceText:SourceText, filePath:string, position:int, parsingOptions:FSharpParsingOptions, options:FSharpProjectOptions, textVersionHash:int, languageServicePerformanceOptions: LanguageServicePerformanceOptions) = + static member ProvideQuickInfo(checker:FSharpChecker, document: Document, position:int, parsingOptions:FSharpParsingOptions, options:FSharpProjectOptions, languageServicePerformanceOptions: LanguageServicePerformanceOptions) = asyncMaybe { - let! _, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName=FSharpQuickInfo.userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, languageServicePerformanceOptions, userOpName=FSharpQuickInfo.userOpName) + let! sourceText = document.GetTextAsync() + let filePath = document.FilePath let textLine = sourceText.Lines.GetLineFromPosition position let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based let textLineString = textLine.ToString() let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions - let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true, true) + let! symbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true, true) let res = checkFileResults.GetToolTip (textLineNumber, symbol.Ident.idRange.EndColumn, textLineString, symbol.FullIsland, FSharpTokenTag.IDENT) match res with | ToolTipText [] diff --git a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs index e9437fcb1af..2a4a7a58da6 100644 --- a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs +++ b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs @@ -151,8 +151,8 @@ type internal FSharpBlockStructureService [] (checkerProvi asyncMaybe { let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) - let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText, userOpName) - return createBlockSpans document.FSharpOptions.Advanced.IsBlockStructureEnabled sourceText parsedInput |> Seq.toImmutableArray + let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName) + return createBlockSpans document.FSharpOptions.Advanced.IsBlockStructureEnabled sourceText parseResults.ParseTree |> Seq.toImmutableArray } |> Async.map (Option.defaultValue ImmutableArray<_>.Empty) |> Async.map FSharpBlockStructure diff --git a/vsintegration/tests/UnitTests/BreakpointResolutionService.fs b/vsintegration/tests/UnitTests/BreakpointResolutionService.fs index f2289f7aa2b..8ed7f3fd01c 100644 --- a/vsintegration/tests/UnitTests/BreakpointResolutionService.fs +++ b/vsintegration/tests/UnitTests/BreakpointResolutionService.fs @@ -72,10 +72,12 @@ let main argv = let searchPosition = code.IndexOf(searchToken) Assert.IsTrue(searchPosition >= 0, "SearchToken '{0}' is not found in code", searchToken) - let sourceText = SourceText.From(code) + let document, sourceText = RoslynTestHelpers.CreateDocument code let searchSpan = TextSpan.FromBounds(searchPosition, searchPosition + searchToken.Length) + + // let document = Microsoft.CodeAnalysis.DocumentInfo.Create(Microsoft.CodeAnalysis.DocumentId() let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions - let actualResolutionOption = FSharpBreakpointResolutionService.GetBreakpointLocation(checker, sourceText, fileName, searchSpan, parsingOptions) |> Async.RunSynchronously + let actualResolutionOption = FSharpBreakpointResolutionService.GetBreakpointLocation(checker, document, searchSpan, parsingOptions) |> Async.RunSynchronously match actualResolutionOption with | None -> Assert.IsTrue(expectedResolution.IsNone, "BreakpointResolutionService failed to resolve breakpoint position") diff --git a/vsintegration/tests/UnitTests/CompletionProviderTests.fs b/vsintegration/tests/UnitTests/CompletionProviderTests.fs index b10dde9af37..a101e4b6334 100644 --- a/vsintegration/tests/UnitTests/CompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/CompletionProviderTests.fs @@ -54,8 +54,9 @@ let formatCompletions(completions : string seq) = let VerifyCompletionListWithOptions(fileContents: string, marker: string, expected: string list, unexpected: string list, opts) = let caretPosition = fileContents.IndexOf(marker) + marker.Length + let document, _ = RoslynTestHelpers.CreateDocument fileContents let results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions opts, filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions opts, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously |> Option.defaultValue (ResizeArray()) |> Seq.map(fun result -> result.DisplayText) @@ -104,9 +105,9 @@ let VerifyCompletionList(fileContents, marker, expected, unexpected) = let VerifyCompletionListExactly(fileContents: string, marker: string, expected: string list) = let caretPosition = fileContents.IndexOf(marker) + marker.Length - + let document, _ = RoslynTestHelpers.CreateDocument fileContents let actual = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions [| |], filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions [| |], (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously |> Option.defaultValue (ResizeArray()) |> Seq.toList diff --git a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs index 41d071a5607..e46f6728751 100644 --- a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs @@ -40,9 +40,10 @@ type DocumentDiagnosticAnalyzerTests() = let getDiagnostics (fileContents: string) = async { + let document, _ = RoslynTestHelpers.CreateDocument fileContents let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions - let! syntacticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, filePath, SourceText.From(fileContents), 0, parsingOptions, projectOptions, DiagnosticsType.Syntax) - let! semanticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, filePath, SourceText.From(fileContents), 0, parsingOptions, projectOptions, DiagnosticsType.Semantic) + let! syntacticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Syntax) + let! semanticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic) return syntacticDiagnostics.AddRange(semanticDiagnostics) } |> Async.RunSynchronously diff --git a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs index ca5a91dabce..a3df0f1c81d 100644 --- a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs +++ b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs @@ -52,8 +52,8 @@ let internal projectOptions = { } let private getSpans (sourceText: SourceText) (caretPosition: int) = - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - FSharpDocumentHighlightsService.GetDocumentHighlights(checker, documentId, sourceText, filePath, caretPosition, [], projectOptions, 0, LanguageServicePerformanceOptions.Default) + let document = RoslynTestHelpers.CreateDocument(sourceText) + FSharpDocumentHighlightsService.GetDocumentHighlights(checker, document, caretPosition, [], projectOptions, LanguageServicePerformanceOptions.Default) |> Async.RunSynchronously |> Option.defaultValue [||] diff --git a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs index 5c322868c39..7a0d76c9d59 100644 --- a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs @@ -60,8 +60,9 @@ type Worker () = let VerifyCompletionList(fileContents: string, marker: string, expected: string list, unexpected: string list) = let caretPosition = fileContents.IndexOf(marker) + marker.Length + let document, _ = RoslynTestHelpers.CreateDocument(fileContents) let results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions, filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously |> Option.defaultValue (ResizeArray()) |> Seq.map(fun result -> result.DisplayText) @@ -108,9 +109,10 @@ type Worker () = member _.VerifyCompletionListExactly(fileContents: string, marker: string, expected: List) = let caretPosition = fileContents.IndexOf(marker) + marker.Length + let document, _ = RoslynTestHelpers.CreateDocument(fileContents) let expected = expected |> Seq.toList let actual = - let x = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, SourceText.From(fileContents), caretPosition, projectOptions, filePath, 0, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) + let x = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously x |> Option.defaultValue (ResizeArray()) |> Seq.toList diff --git a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs index 0462a1812e9..ea3780d796c 100644 --- a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs +++ b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs @@ -42,20 +42,18 @@ module GoToDefinitionServiceTests = let private findDefinition ( checker: FSharpChecker, - documentKey: DocumentId, - sourceText: SourceText, - filePath: string, + document: Document, + sourceText: SourceText, position: int, defines: string list, - options: FSharpProjectOptions, - textVersionHash: int + options: FSharpProjectOptions ) : range option = maybe { let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! lexerSymbol = Tokenizer.getSymbolAtPosition(documentKey, sourceText, position, filePath, defines, SymbolLookupKind.Greedy, false, false) - let! _, _, checkFileResults = checker.ParseAndCheckDocument (filePath, textVersionHash, sourceText, options, LanguageServicePerformanceOptions.Default, userOpName=userOpName) |> Async.RunSynchronously + let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, options, LanguageServicePerformanceOptions.Default, userOpName=userOpName) |> Async.RunSynchronously let declarations = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false) @@ -86,9 +84,9 @@ module GoToDefinitionServiceTests = File.WriteAllText(filePath, fileContents) let caretPosition = fileContents.IndexOf(caretMarker) + caretMarker.Length - 1 // inside the marker - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) + let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) let actual = - findDefinition(checker, documentId, SourceText.From(fileContents), filePath, caretPosition, [], options, 0) + findDefinition(checker, document, sourceText, caretPosition, [], options) |> Option.map (fun range -> (range.StartLine, range.EndLine, range.StartColumn, range.EndColumn)) if actual <> expected then diff --git a/vsintegration/tests/UnitTests/QuickInfoTests.fs b/vsintegration/tests/UnitTests/QuickInfoTests.fs index 0441d8fa170..3842f32c3a4 100644 --- a/vsintegration/tests/UnitTests/QuickInfoTests.fs +++ b/vsintegration/tests/UnitTests/QuickInfoTests.fs @@ -15,9 +15,8 @@ module QuickInfo = let internal GetQuickInfo (project:FSharpProject) (fileName:string) (caretPosition:int) = async { let code = File.ReadAllText(fileName) - let sourceText = SourceText.From(code) - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) // only used for caching purposes - return! FSharpAsyncQuickInfoSource.ProvideQuickInfo(checker, documentId, sourceText, fileName, caretPosition, FSharpParsingOptions.Default, project.Options, 0, LanguageServicePerformanceOptions.Default) + let document, _ = RoslynTestHelpers.CreateDocument(code) + return! FSharpAsyncQuickInfoSource.ProvideQuickInfo(checker, document, caretPosition, FSharpParsingOptions.Default, project.Options, LanguageServicePerformanceOptions.Default) } |> Async.RunSynchronously let GetQuickInfoText (project:FSharpProject) (fileName:string) (caretPosition:int) = diff --git a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs index 967719024e4..807d13a5008 100644 --- a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs +++ b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs @@ -33,8 +33,8 @@ type SemanticClassificationServiceTests() = let getRanges (source: string) : SemanticClassificationItem list = asyncMaybe { - - let! _, _, checkFileResults = checker.ParseAndCheckDocument(filePath, 0, SourceText.From(source), projectOptions, perfOptions, "") + let document, _ = RoslynTestHelpers.CreateDocument(source) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "") return checkFileResults.GetSemanticClassification(None) } |> Async.RunSynchronously diff --git a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs index 96fe558cc79..d513824b457 100644 --- a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs @@ -54,11 +54,11 @@ let GetSignatureHelp (project:FSharpProject) (fileName:string) (caretPosition:in let caretLinePos = textLines.GetLinePosition(caretPosition) let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 1 + let document = RoslynTestHelpers.CreateDocument(sourceText) let parseResults, _, checkFileResults = let x = - checker.ParseAndCheckDocument(fileName, textVersionHash, sourceText, project.Options, perfOptions, "TestSignatureHelpProvider") + checker.ParseAndCheckDocument(document, project.Options, perfOptions, "TestSignatureHelpProvider") |> Async.RunSynchronously x.Value @@ -104,11 +104,11 @@ let assertSignatureHelpForMethodCalls (fileContents: string) (marker: string) (e let caretLinePos = textLines.GetLinePosition(caretPosition) let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 + let document = RoslynTestHelpers.CreateDocument(sourceText) let parseResults, _, checkFileResults = let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") + checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "TestSignatureHelpProvider") |> Async.RunSynchronously if x.IsNone then @@ -141,14 +141,12 @@ let assertSignatureHelpForMethodCalls (fileContents: string) (marker: string) (e let assertSignatureHelpForFunctionApplication (fileContents: string) (marker: string) expectedArgumentCount expectedArgumentIndex = let caretPosition = fileContents.LastIndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) + let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) let parseResults, _, checkFileResults = let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") + checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "TestSignatureHelpProvider") |> Async.RunSynchronously if x.IsNone then @@ -167,7 +165,7 @@ let assertSignatureHelpForFunctionApplication (fileContents: string) (marker: st FSharpSignatureHelpProvider.ProvideParametersAsyncAux( parseResults, checkFileResults, - documentId, + document.Id, [], DefaultDocumentationProvider, sourceText, @@ -429,14 +427,13 @@ M.f """ let marker = "id " let caretPosition = fileContents.IndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) + + let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) let parseResults, _, checkFileResults = let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") + checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "TestSignatureHelpProvider") |> Async.RunSynchronously if x.IsNone then @@ -455,7 +452,7 @@ M.f FSharpSignatureHelpProvider.ProvideParametersAsyncAux( parseResults, checkFileResults, - documentId, + document.Id, [], DefaultDocumentationProvider, sourceText, diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs new file mode 100644 index 00000000000..43ad19a9005 --- /dev/null +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -0,0 +1,35 @@ +namespace Microsoft.VisualStudio.FSharp.Editor.Tests.Roslyn + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text + +[] +type RoslynTestHelpers private () = + + static member CreateDocument (text: SourceText) = + let workspace = new AdhocWorkspace() + let sol = workspace.CurrentSolution + + let projId = ProjectId.CreateNewId() + let projInfo = + ProjectInfo.Create( + projId, + VersionStamp.Create(), + "test", + "test", + "F#" + ) + let docId = DocumentId.CreateNewId(projId) + let loader = TextLoader.From(text.Container, VersionStamp.Create()) + let docInfo = DocumentInfo.Create(docId, "test.fs", sourceCodeKind=SourceCodeKind.Regular, loader=loader, isGenerated=true) + + let projInfo = projInfo.WithDocuments([docInfo]) + + let sol = sol.AddProject(projInfo) + + sol.GetProject(projId).Documents |> Seq.find (fun x -> x.Id.Equals(docId)) + + static member CreateDocument (code: string) = + let text = SourceText.From(code) + RoslynTestHelpers.CreateDocument(text), text + diff --git a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj index d2161ed8a4b..ab0064b7dd8 100644 --- a/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj +++ b/vsintegration/tests/UnitTests/VisualFSharp.UnitTests.fsproj @@ -38,6 +38,7 @@ + From adab61dce75e64dbad5ae3836311f030b4805559 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 17 Mar 2021 15:17:50 -0700 Subject: [PATCH 06/35] Fixing build --- .../src/FSharp.Editor/Refactor/AddExplicitTypeToParameter.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitTypeToParameter.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitTypeToParameter.fs index 569cc1b57dd..f2c73274dd4 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitTypeToParameter.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitTypeToParameter.fs @@ -38,7 +38,7 @@ type internal FSharpAddExplicitTypeToParameterRefactoring let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName) let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland) From e1e4434f55b68779fbdb388f7f3f6274b24472e1 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 18 Mar 2021 11:12:04 -0700 Subject: [PATCH 07/35] Fixing tests --- .../SurfaceArea.netstandard.fs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 51f59bb0a47..15053e39bfb 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1437,7 +1437,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_ActualParseFileCount() FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_CurrentQueueLength() FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_MaxMemory() FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_PauseBeforeBackgroundWork() -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer] CheckFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer] CheckFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults] ParseAndCheckProject(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] GetBackgroundParseResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) @@ -1446,7 +1446,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],System.Int32]] Compile(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedInput], System.String, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) @@ -1465,7 +1465,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Mi FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_BeforeBackgroundFileCheck() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileChecked() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileParsed() -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,System.Int32]] TryGetRecentCheckResultsForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText], Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,System.Int32]] TryGetRecentCheckResultsForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromProjectOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions) @@ -1481,8 +1481,10 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_ImplicitlyStartBackgroundWo FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_MaxMemory(Int32) FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_PauseBeforeBackgroundWork(Int32) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults +FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPositionContainedInACurriedParameter(FSharp.Compiler.Text.Position) +FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsTypeAnnotationGivenAtPosition(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean ParseHadErrors FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean get_ParseHadErrors() FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] Diagnostics @@ -1500,8 +1502,6 @@ FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FShar FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.Range]] GetAllArgumentsForFunctionApplicationAtPostion(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Syntax.Ident,System.Int32]] TryIdentOfPipelineContainingPosAndNumArgsApplied(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range]] TryRangeOfParenEnclosingOpEqualsGreaterUsage(FSharp.Compiler.Text.Position) -FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position) -FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsTypeAnnotationGivenAtPosition(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String FileName FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String get_FileName() FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String[] DependencyFiles @@ -4152,6 +4152,7 @@ FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsEventAddMethod FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsEventRemoveMethod FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsExplicitInterfaceImplementation FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsExtensionMember +FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsFunction FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsImplicitConstructor FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsInstanceMember FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsInstanceMemberInCompiledCode @@ -4167,7 +4168,6 @@ FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsTypeFunction FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsUnresolved FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsValCompiledAsMethod FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsValue -FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean IsFunction FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_EventIsStandard() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_HasGetterMethod() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_HasSetterMethod() @@ -4182,6 +4182,7 @@ FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsEventAddMet FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsEventRemoveMethod() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsExplicitInterfaceImplementation() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsExtensionMember() +FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsFunction() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsImplicitConstructor() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsInstanceMember() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsInstanceMemberInCompiledCode() @@ -4197,7 +4198,6 @@ FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsTypeFunctio FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsUnresolved() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsValCompiledAsMethod() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsValue() -FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: Boolean get_IsFunction() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: FSharp.Compiler.Symbols.FSharpAccessibility Accessibility FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: FSharp.Compiler.Symbols.FSharpAccessibility get_Accessibility() FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue: FSharp.Compiler.Symbols.FSharpEntity ApparentEnclosingEntity From d729592be16712c48c80e7c6701b44f916c39ef8 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 18 Mar 2021 12:33:51 -0700 Subject: [PATCH 08/35] Fixing tests --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 43ad19a9005..11fbf6c92dd 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -8,6 +8,7 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() + workspace. let sol = workspace.CurrentSolution let projId = ProjectId.CreateNewId() @@ -17,7 +18,7 @@ type RoslynTestHelpers private () = VersionStamp.Create(), "test", "test", - "F#" + LanguageNames.CSharp ) let docId = DocumentId.CreateNewId(projId) let loader = TextLoader.From(text.Container, VersionStamp.Create()) From edf0cb1e9b7bbf6c4b2bbabd826abd41b88f4880 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 18 Mar 2021 14:32:37 -0700 Subject: [PATCH 09/35] Fixing build --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 11fbf6c92dd..c59d094f8a0 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -8,7 +8,6 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() - workspace. let sol = workspace.CurrentSolution let projId = ProjectId.CreateNewId() From 3af59e6481960889a45f380603aace1b6b8dfa34 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 18 Mar 2021 15:42:35 -0700 Subject: [PATCH 10/35] Fixing tests --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index c59d094f8a0..d154831eff5 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -19,15 +19,7 @@ type RoslynTestHelpers private () = "test", LanguageNames.CSharp ) - let docId = DocumentId.CreateNewId(projId) - let loader = TextLoader.From(text.Container, VersionStamp.Create()) - let docInfo = DocumentInfo.Create(docId, "test.fs", sourceCodeKind=SourceCodeKind.Regular, loader=loader, isGenerated=true) - - let projInfo = projInfo.WithDocuments([docInfo]) - - let sol = sol.AddProject(projInfo) - - sol.GetProject(projId).Documents |> Seq.find (fun x -> x.Id.Equals(docId)) + workspace.AddDocument(projId, "test.fs", text) static member CreateDocument (code: string) = let text = SourceText.From(code) From a70be9cf080c18a6b3ef47be37770e2680b3a9c7 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 18 Mar 2021 23:39:57 -0700 Subject: [PATCH 11/35] Fixing tests --- .../tests/UnitTests/Tests.RoslynHelpers.fs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index d154831eff5..0449d80c7dc 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -8,18 +8,8 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() - let sol = workspace.CurrentSolution - - let projId = ProjectId.CreateNewId() - let projInfo = - ProjectInfo.Create( - projId, - VersionStamp.Create(), - "test", - "test", - LanguageNames.CSharp - ) - workspace.AddDocument(projId, "test.fs", text) + let proj = workspace.AddProject("test", LanguageNames.CSharp) + workspace.AddDocument(proj.Id, "test.fs", text) static member CreateDocument (code: string) = let text = SourceText.From(code) From 0183a2688dd56f6b97ba59b1c87f70ffbde40164 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 10:09:31 -0700 Subject: [PATCH 12/35] Trying to fix tests --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 0449d80c7dc..2276333b96e 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -9,7 +9,14 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() let proj = workspace.AddProject("test", LanguageNames.CSharp) - workspace.AddDocument(proj.Id, "test.fs", text) + + let docInfo = + let docId = DocumentId.CreateNewId(proj.Id) + DocumentInfo.Create(docId, + "test.fs", + loader=TextLoader.From(text.Container, VersionStamp.Create(), "C:\test.fs")) + + workspace.AddDocument(docInfo) static member CreateDocument (code: string) = let text = SourceText.From(code) From c53322f7c25ee93d2f22c234355884304f287899 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 10:19:08 -0700 Subject: [PATCH 13/35] Force remove cache --- src/fsharp/service/service.fs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 595e0f03186..b6c73b7c6d5 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -447,10 +447,11 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options, cacheStamp: int64 option) = // If a cache stamp is not provided, we need to do a full-up-to-date check on the timestamps for the dependencies. let recheckDeps = cacheStamp.IsNone - if recheckDeps && not (builder.AreCheckResultsBeforeFileInProjectReady filename) then None + let cacheStamp = defaultArg cacheStamp (sourceText.GetHashCode() |> int64) + if recheckDeps && not (builder.AreCheckResultsBeforeFileInProjectReady filename) then + parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.RemoveAnySimilar(ltok, (filename, cacheStamp, options))) + None else - let cacheStamp = defaultArg cacheStamp (sourceText.GetHashCode() |> int64) - // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, cacheStamp, options))) From 163fbcbab0df684616d35fb698fa297e9fd78f76 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 11:27:29 -0700 Subject: [PATCH 14/35] Trying to fix test --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 2276333b96e..4a5f246cbb4 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -14,7 +14,8 @@ type RoslynTestHelpers private () = let docId = DocumentId.CreateNewId(proj.Id) DocumentInfo.Create(docId, "test.fs", - loader=TextLoader.From(text.Container, VersionStamp.Create(), "C:\test.fs")) + loader=TextLoader.From(text.Container, VersionStamp.Create()), + filePath="C:\test.fs") workspace.AddDocument(docInfo) From d45e796cafad4170dae492aded821b9f9e048a01 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 12:44:08 -0700 Subject: [PATCH 15/35] Trying to fix --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 4a5f246cbb4..45dd62cbe83 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -15,7 +15,7 @@ type RoslynTestHelpers private () = DocumentInfo.Create(docId, "test.fs", loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath="C:\test.fs") + filePath="""C:\test.fs""") workspace.AddDocument(docInfo) From 9f92c0bf7db75a5e0d8750a1d37c9456ae41812c Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 14:12:47 -0700 Subject: [PATCH 16/35] Updating test again --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 45dd62cbe83..617ac94cb6e 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -8,14 +8,14 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() - let proj = workspace.AddProject("test", LanguageNames.CSharp) + let proj = workspace.AddProject("testProject", LanguageNames.CSharp) let docInfo = let docId = DocumentId.CreateNewId(proj.Id) DocumentInfo.Create(docId, - "test.fs", + "testFile.fs", loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath="""C:\test.fs""") + filePath="testFile.fs") workspace.AddDocument(docInfo) From 6eb5e1c7244590f027fd04a1bfffc43eba77409f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 16:16:50 -0700 Subject: [PATCH 17/35] Still trying to fix tests --- vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs | 4 ++-- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs b/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs index 96e9a37537e..c6a9298ff87 100644 --- a/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs +++ b/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs @@ -144,8 +144,8 @@ module internal ProjectOptionsBuilder = let SingleFileProject(code:string) = code |> sprintf @" - - + + diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 617ac94cb6e..622bfc038f9 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -8,14 +8,14 @@ type RoslynTestHelpers private () = static member CreateDocument (text: SourceText) = let workspace = new AdhocWorkspace() - let proj = workspace.AddProject("testProject", LanguageNames.CSharp) + let proj = workspace.AddProject("test", LanguageNames.CSharp) let docInfo = let docId = DocumentId.CreateNewId(proj.Id) DocumentInfo.Create(docId, - "testFile.fs", + "test.fs", loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath="testFile.fs") + filePath="test.fs") workspace.AddDocument(docInfo) From 3364dc288ac6fa9112ed9f784bb3e84d209f76e5 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 16:48:33 -0700 Subject: [PATCH 18/35] Fixing build --- .../CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs index 7eb60b25c90..cbf1b645648 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs @@ -47,7 +47,7 @@ type internal FSharpAddTypeAnnotationToObjectOfIndeterminateTypeFixProvider let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName) let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) let decl = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false) From 895cf2dd5f886fcf2c207294ee2eec664f0e395f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 17:45:37 -0700 Subject: [PATCH 19/35] Trying to fix tests --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 622bfc038f9..45dd62cbe83 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -15,7 +15,7 @@ type RoslynTestHelpers private () = DocumentInfo.Create(docId, "test.fs", loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath="test.fs") + filePath="""C:\test.fs""") workspace.AddDocument(docInfo) From 9064891b619d7b391dea42b3a2f4c26c4d17a41f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 18:14:31 -0700 Subject: [PATCH 20/35] Passing filepath to creating a test document --- .../tests/UnitTests/BreakpointResolutionService.fs | 2 +- .../tests/UnitTests/CompletionProviderTests.fs | 4 ++-- .../UnitTests/DocumentDiagnosticAnalyzerTests.fs | 2 +- .../tests/UnitTests/FsxCompletionProviderTests.fs | 4 ++-- .../tests/UnitTests/GoToDefinitionServiceTests.fs | 2 +- vsintegration/tests/UnitTests/QuickInfoTests.fs | 2 +- .../UnitTests/SemanticColorizationServiceTests.fs | 2 +- .../tests/UnitTests/SignatureHelpProviderTests.fs | 8 ++++---- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 12 ++++++------ 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/vsintegration/tests/UnitTests/BreakpointResolutionService.fs b/vsintegration/tests/UnitTests/BreakpointResolutionService.fs index 8ed7f3fd01c..e9437195d8e 100644 --- a/vsintegration/tests/UnitTests/BreakpointResolutionService.fs +++ b/vsintegration/tests/UnitTests/BreakpointResolutionService.fs @@ -72,7 +72,7 @@ let main argv = let searchPosition = code.IndexOf(searchToken) Assert.IsTrue(searchPosition >= 0, "SearchToken '{0}' is not found in code", searchToken) - let document, sourceText = RoslynTestHelpers.CreateDocument code + let document, sourceText = RoslynTestHelpers.CreateDocument(fileName, code) let searchSpan = TextSpan.FromBounds(searchPosition, searchPosition + searchToken.Length) // let document = Microsoft.CodeAnalysis.DocumentInfo.Create(Microsoft.CodeAnalysis.DocumentId() diff --git a/vsintegration/tests/UnitTests/CompletionProviderTests.fs b/vsintegration/tests/UnitTests/CompletionProviderTests.fs index a101e4b6334..69c6b3afb23 100644 --- a/vsintegration/tests/UnitTests/CompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/CompletionProviderTests.fs @@ -54,7 +54,7 @@ let formatCompletions(completions : string seq) = let VerifyCompletionListWithOptions(fileContents: string, marker: string, expected: string list, unexpected: string list, opts) = let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, _ = RoslynTestHelpers.CreateDocument fileContents + let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let results = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions opts, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously @@ -105,7 +105,7 @@ let VerifyCompletionList(fileContents, marker, expected, unexpected) = let VerifyCompletionListExactly(fileContents: string, marker: string, expected: string list) = let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, _ = RoslynTestHelpers.CreateDocument fileContents + let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let actual = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions [| |], (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously diff --git a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs index e46f6728751..d9e21ed88be 100644 --- a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs @@ -40,7 +40,7 @@ type DocumentDiagnosticAnalyzerTests() = let getDiagnostics (fileContents: string) = async { - let document, _ = RoslynTestHelpers.CreateDocument fileContents + let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions let! syntacticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Syntax) let! semanticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic) diff --git a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs index 7a0d76c9d59..6b2e9227a71 100644 --- a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs @@ -60,7 +60,7 @@ type Worker () = let VerifyCompletionList(fileContents: string, marker: string, expected: string list, unexpected: string list) = let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, _ = RoslynTestHelpers.CreateDocument(fileContents) + let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let results = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously @@ -109,7 +109,7 @@ type Worker () = member _.VerifyCompletionListExactly(fileContents: string, marker: string, expected: List) = let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, _ = RoslynTestHelpers.CreateDocument(fileContents) + let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let expected = expected |> Seq.toList let actual = let x = FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) diff --git a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs index ea3780d796c..f77a3e6e9cf 100644 --- a/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs +++ b/vsintegration/tests/UnitTests/GoToDefinitionServiceTests.fs @@ -84,7 +84,7 @@ module GoToDefinitionServiceTests = File.WriteAllText(filePath, fileContents) let caretPosition = fileContents.IndexOf(caretMarker) + caretMarker.Length - 1 // inside the marker - let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) + let document, sourceText = RoslynTestHelpers.CreateDocument(filePath, fileContents) let actual = findDefinition(checker, document, sourceText, caretPosition, [], options) |> Option.map (fun range -> (range.StartLine, range.EndLine, range.StartColumn, range.EndColumn)) diff --git a/vsintegration/tests/UnitTests/QuickInfoTests.fs b/vsintegration/tests/UnitTests/QuickInfoTests.fs index 3842f32c3a4..688ca2624ee 100644 --- a/vsintegration/tests/UnitTests/QuickInfoTests.fs +++ b/vsintegration/tests/UnitTests/QuickInfoTests.fs @@ -15,7 +15,7 @@ module QuickInfo = let internal GetQuickInfo (project:FSharpProject) (fileName:string) (caretPosition:int) = async { let code = File.ReadAllText(fileName) - let document, _ = RoslynTestHelpers.CreateDocument(code) + let document, _ = RoslynTestHelpers.CreateDocument(fileName, code) return! FSharpAsyncQuickInfoSource.ProvideQuickInfo(checker, document, caretPosition, FSharpParsingOptions.Default, project.Options, LanguageServicePerformanceOptions.Default) } |> Async.RunSynchronously diff --git a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs index 807d13a5008..179ab6f4b07 100644 --- a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs +++ b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs @@ -33,7 +33,7 @@ type SemanticClassificationServiceTests() = let getRanges (source: string) : SemanticClassificationItem list = asyncMaybe { - let document, _ = RoslynTestHelpers.CreateDocument(source) + let document, _ = RoslynTestHelpers.CreateDocument(filePath, source) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "") return checkFileResults.GetSemanticClassification(None) } diff --git a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs index d513824b457..0b39647afe5 100644 --- a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs @@ -55,7 +55,7 @@ let GetSignatureHelp (project:FSharpProject) (fileName:string) (caretPosition:in let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default - let document = RoslynTestHelpers.CreateDocument(sourceText) + let document = RoslynTestHelpers.CreateDocument(filePath, sourceText) let parseResults, _, checkFileResults = let x = checker.ParseAndCheckDocument(document, project.Options, perfOptions, "TestSignatureHelpProvider") @@ -105,7 +105,7 @@ let assertSignatureHelpForMethodCalls (fileContents: string) (marker: string) (e let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default - let document = RoslynTestHelpers.CreateDocument(sourceText) + let document = RoslynTestHelpers.CreateDocument(filePath, sourceText) let parseResults, _, checkFileResults = let x = checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "TestSignatureHelpProvider") @@ -141,7 +141,7 @@ let assertSignatureHelpForMethodCalls (fileContents: string) (marker: string) (e let assertSignatureHelpForFunctionApplication (fileContents: string) (marker: string) expectedArgumentCount expectedArgumentIndex = let caretPosition = fileContents.LastIndexOf(marker) + marker.Length - let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) + let document, sourceText = RoslynTestHelpers.CreateDocument(filePath, fileContents) let perfOptions = LanguageServicePerformanceOptions.Default let parseResults, _, checkFileResults = @@ -428,7 +428,7 @@ M.f let marker = "id " let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, sourceText = RoslynTestHelpers.CreateDocument(fileContents) + let document, sourceText = RoslynTestHelpers.CreateDocument(filePath, fileContents) let perfOptions = LanguageServicePerformanceOptions.Default let parseResults, _, checkFileResults = diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 45dd62cbe83..c219b35de44 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -6,20 +6,20 @@ open Microsoft.CodeAnalysis.Text [] type RoslynTestHelpers private () = - static member CreateDocument (text: SourceText) = + static member CreateDocument (filePath, text: SourceText) = let workspace = new AdhocWorkspace() - let proj = workspace.AddProject("test", LanguageNames.CSharp) + let proj = workspace.AddProject("test.fsproj", LanguageNames.CSharp) let docInfo = let docId = DocumentId.CreateNewId(proj.Id) DocumentInfo.Create(docId, - "test.fs", + filePath, loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath="""C:\test.fs""") + filePath=filePath) workspace.AddDocument(docInfo) - static member CreateDocument (code: string) = + static member CreateDocument (filePath, code: string) = let text = SourceText.From(code) - RoslynTestHelpers.CreateDocument(text), text + RoslynTestHelpers.CreateDocument(filePath, text), text From c7d1561d10619f3f15849b50b30d64f2790e6da0 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 18:17:05 -0700 Subject: [PATCH 21/35] fixing build --- vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs index a3df0f1c81d..4959fb8f56b 100644 --- a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs +++ b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs @@ -52,7 +52,7 @@ let internal projectOptions = { } let private getSpans (sourceText: SourceText) (caretPosition: int) = - let document = RoslynTestHelpers.CreateDocument(sourceText) + let document = RoslynTestHelpers.CreateDocument(filePath, sourceText) FSharpDocumentHighlightsService.GetDocumentHighlights(checker, document, caretPosition, [], projectOptions, LanguageServicePerformanceOptions.Default) |> Async.RunSynchronously |> Option.defaultValue [||] From 20c1313b9d35c579a52755e9ff9a46d14d7d85c7 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 19 Mar 2021 18:22:54 -0700 Subject: [PATCH 22/35] Still trying to fix tests --- vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs b/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs index c6a9298ff87..96e9a37537e 100644 --- a/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs +++ b/vsintegration/tests/UnitTests/ProjectOptionsBuilder.fs @@ -144,8 +144,8 @@ module internal ProjectOptionsBuilder = let SingleFileProject(code:string) = code |> sprintf @" - - + + From 57b34e32c16068addbe858f729eebb8bb7070ad3 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 11:05:51 -0700 Subject: [PATCH 23/35] Use SourceCodeKind.Regular --- vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index c219b35de44..e3886cd15a6 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -15,7 +15,8 @@ type RoslynTestHelpers private () = DocumentInfo.Create(docId, filePath, loader=TextLoader.From(text.Container, VersionStamp.Create()), - filePath=filePath) + filePath=filePath, + sourceCodeKind=SourceCodeKind.Regular) workspace.AddDocument(docInfo) From 8cc0ca3e513aa72376d09c29562839028f73781a Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 11:13:25 -0700 Subject: [PATCH 24/35] Fixing tests --- vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs index 0b39647afe5..df7ff193736 100644 --- a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs @@ -55,7 +55,7 @@ let GetSignatureHelp (project:FSharpProject) (fileName:string) (caretPosition:in let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default - let document = RoslynTestHelpers.CreateDocument(filePath, sourceText) + let document = RoslynTestHelpers.CreateDocument(fileName, sourceText) let parseResults, _, checkFileResults = let x = checker.ParseAndCheckDocument(document, project.Options, perfOptions, "TestSignatureHelpProvider") From 4f886e07bf441f16c82428bcd520d82ef8d54fee Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 12:38:25 -0700 Subject: [PATCH 25/35] Minor update to verify no errors --- .../tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs index d9e21ed88be..1576061f6fc 100644 --- a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs @@ -54,7 +54,8 @@ type DocumentDiagnosticAnalyzerTests() = | Some(flags) -> {projectOptions with OtherOptions = Array.append projectOptions.OtherOptions flags} let errors = getDiagnostics fileContents - Assert.AreEqual(0, errors.Length, "There should be no errors generated") + if not errors.IsEmpty then + Assert.Fail("There should be no errors generated", errors) member private this.VerifyErrorAtMarker(fileContents: string, expectedMarker: string, ?expectedMessage: string) = let errors = getDiagnostics fileContents |> Seq.filter(fun e -> e.Severity = DiagnosticSeverity.Error) |> Seq.toArray From f902148b43c0500f8f68487aac0fe5b84c817191 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 12:48:42 -0700 Subject: [PATCH 26/35] Creating version stamps with date times for tests --- .../tests/UnitTests/Tests.RoslynHelpers.fs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index e3886cd15a6..48dda28d28c 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -1,5 +1,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor.Tests.Roslyn +open System open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text @@ -8,13 +9,23 @@ type RoslynTestHelpers private () = static member CreateDocument (filePath, text: SourceText) = let workspace = new AdhocWorkspace() - let proj = workspace.AddProject("test.fsproj", LanguageNames.CSharp) + let projInfo = + let projId = ProjectId.CreateNewId() + ProjectInfo.Create( + projId, + VersionStamp.Create(DateTime.UtcNow), + "test.fsproj", + "test.dll", + LanguageNames.CSharp + ) + let proj = workspace.AddProject(projInfo) let docInfo = let docId = DocumentId.CreateNewId(proj.Id) - DocumentInfo.Create(docId, + DocumentInfo.Create( + docId, filePath, - loader=TextLoader.From(text.Container, VersionStamp.Create()), + loader=TextLoader.From(text.Container, VersionStamp.Create(DateTime.UtcNow)), filePath=filePath, sourceCodeKind=SourceCodeKind.Regular) From a4a0a1142244fe0e272bf7b012fd023898055a72 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 13:57:00 -0700 Subject: [PATCH 27/35] still trying to fix tests --- .../tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs index 1576061f6fc..4ae4c6ad812 100644 --- a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs @@ -41,7 +41,7 @@ type DocumentDiagnosticAnalyzerTests() = let getDiagnostics (fileContents: string) = async { let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) - let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions + let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } let! syntacticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Syntax) let! semanticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic) return syntacticDiagnostics.AddRange(semanticDiagnostics) From c9e7a4703dbb4beaa63b8b7f4bd8e610dd6c2607 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 13:57:57 -0700 Subject: [PATCH 28/35] Make projects unique in testing diagnostics --- .../tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs index 4ae4c6ad812..25e6f9f4060 100644 --- a/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/UnitTests/DocumentDiagnosticAnalyzerTests.fs @@ -40,8 +40,9 @@ type DocumentDiagnosticAnalyzerTests() = let getDiagnostics (fileContents: string) = async { + let projectOptions = { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) - let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } + let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions projectOptions let! syntacticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Syntax) let! semanticDiagnostics = FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic) return syntacticDiagnostics.AddRange(semanticDiagnostics) From b9a17802003b6ed2f50c6dd73e81dfc959270062 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 14:52:57 -0700 Subject: [PATCH 29/35] Trying to pass tests --- vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs index 4959fb8f56b..baf54d9ee50 100644 --- a/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs +++ b/vsintegration/tests/UnitTests/DocumentHighlightsServiceTests.fs @@ -52,6 +52,7 @@ let internal projectOptions = { } let private getSpans (sourceText: SourceText) (caretPosition: int) = + let projectOptions = { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } let document = RoslynTestHelpers.CreateDocument(filePath, sourceText) FSharpDocumentHighlightsService.GetDocumentHighlights(checker, document, caretPosition, [], projectOptions, LanguageServicePerformanceOptions.Default) |> Async.RunSynchronously From a5844047e3b4dd4d95def5d5d65d97b54f39307f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 15:51:19 -0700 Subject: [PATCH 30/35] This should fix the rest --- .../UnitTests/FsxCompletionProviderTests.fs | 66 +------------------ .../tests/UnitTests/Tests.RoslynHelpers.fs | 4 +- 2 files changed, 5 insertions(+), 65 deletions(-) diff --git a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs index 6b2e9227a71..e9c7188d064 100644 --- a/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/FsxCompletionProviderTests.fs @@ -38,7 +38,6 @@ open UnitTests.TestLib.LanguageService // AppDomain helper type Worker () = - inherit MarshalByRefObject() let filePath = "C:\\test.fsx" let projectOptions = { @@ -55,59 +54,8 @@ type Worker () = Stamp = None } - let formatCompletions(completions : string seq) = - "\n\t" + String.Join("\n\t", completions) - - let VerifyCompletionList(fileContents: string, marker: string, expected: string list, unexpected: string list) = - let caretPosition = fileContents.IndexOf(marker) + marker.Length - let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) - let results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) - |> Async.RunSynchronously - |> Option.defaultValue (ResizeArray()) - |> Seq.map(fun result -> result.DisplayText) - - let expectedFound = - expected - |> Seq.filter results.Contains - - let expectedNotFound = - expected - |> Seq.filter (expectedFound.Contains >> not) - - let unexpectedNotFound = - unexpected - |> Seq.filter (results.Contains >> not) - - let unexpectedFound = - unexpected - |> Seq.filter (unexpectedNotFound.Contains >> not) - - // If either of these are true, then the test fails. - let hasExpectedNotFound = not (Seq.isEmpty expectedNotFound) - let hasUnexpectedFound = not (Seq.isEmpty unexpectedFound) - - if hasExpectedNotFound || hasUnexpectedFound then - let expectedNotFoundMsg = - if hasExpectedNotFound then - sprintf "\nExpected completions not found:%s\n" (formatCompletions expectedNotFound) - else - String.Empty - - let unexpectedFoundMsg = - if hasUnexpectedFound then - sprintf "\nUnexpected completions found:%s\n" (formatCompletions unexpectedFound) - else - String.Empty - - let completionsMsg = sprintf "\nin Completions:%s" (formatCompletions results) - - let msg = sprintf "%s%s%s" expectedNotFoundMsg unexpectedFoundMsg completionsMsg - - Assert.Fail(msg) - member _.VerifyCompletionListExactly(fileContents: string, marker: string, expected: List) = - + let projectOptions = { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } let caretPosition = fileContents.IndexOf(marker) + marker.Length let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let expected = expected |> Seq.toList @@ -129,17 +77,7 @@ type Worker () = module FsxCompletionProviderTests = - let pathToThisDll = Assembly.GetExecutingAssembly().CodeBase - - let getWorker () = - - let adSetup = - let setup = new System.AppDomainSetup () - setup.PrivateBinPath <- pathToThisDll - setup - - let ad = AppDomain.CreateDomain((Guid()).ToString(), null, adSetup) - (ad.CreateInstanceFromAndUnwrap(pathToThisDll, typeof.FullName)) :?> Worker + let getWorker () = Worker() [] let fsiShouldTriggerCompletionInFsxFile() = diff --git a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs index 48dda28d28c..6ccdbacc715 100644 --- a/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs +++ b/vsintegration/tests/UnitTests/Tests.RoslynHelpers.fs @@ -1,6 +1,7 @@ namespace Microsoft.VisualStudio.FSharp.Editor.Tests.Roslyn open System +open System.IO open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text @@ -8,6 +9,7 @@ open Microsoft.CodeAnalysis.Text type RoslynTestHelpers private () = static member CreateDocument (filePath, text: SourceText) = + let isScript = String.Equals(Path.GetExtension(filePath), ".fsx", StringComparison.OrdinalIgnoreCase) let workspace = new AdhocWorkspace() let projInfo = let projId = ProjectId.CreateNewId() @@ -27,7 +29,7 @@ type RoslynTestHelpers private () = filePath, loader=TextLoader.From(text.Container, VersionStamp.Create(DateTime.UtcNow)), filePath=filePath, - sourceCodeKind=SourceCodeKind.Regular) + sourceCodeKind= if isScript then SourceCodeKind.Script else SourceCodeKind.Regular) workspace.AddDocument(docInfo) From 657ea0ebb06c3f62da181616d8bb7d681bc567df Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 22 Mar 2021 20:17:46 -0700 Subject: [PATCH 31/35] Adding back original logic for GetCachedCheckFileResult when cacheStamp is None --- src/fsharp/service/service.fs | 43 ++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index b6c73b7c6d5..4329db1fbac 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -445,19 +445,36 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options, cacheStamp: int64 option) = - // If a cache stamp is not provided, we need to do a full-up-to-date check on the timestamps for the dependencies. - let recheckDeps = cacheStamp.IsNone - let cacheStamp = defaultArg cacheStamp (sourceText.GetHashCode() |> int64) - if recheckDeps && not (builder.AreCheckResultsBeforeFileInProjectReady filename) then - parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.RemoveAnySimilar(ltok, (filename, cacheStamp, options))) - None - else - // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date - let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, cacheStamp, options))) - - match cachedResults with - | Some (parseResults, checkResults, _, _) -> Some (parseResults, checkResults) - | _ -> None + let stamp = + match cacheStamp with + | None -> sourceText.GetHashCode() |> int64 + | Some cacheStamp -> cacheStamp + + // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date + let cachedResults = parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.TryGet(ltok, (filename, stamp, options))) + + let result = + if cacheStamp.IsSome then + match cachedResults with + | Some (parseResults, checkResults, _, _) -> Some (parseResults, checkResults) + | _ -> None + else + match cachedResults with + | Some (parseResults, checkResults,_,priorTimeStamp) + when + (match builder.GetCheckResultsBeforeFileInProjectEvenIfStale filename with + | None -> false + | Some(tcPrior) -> + tcPrior.TimeStamp = priorTimeStamp && + builder.AreCheckResultsBeforeFileInProjectReady(filename)) -> + Some (parseResults,checkResults) + | _ -> + None + + if result.IsNone then + parseCacheLock.AcquireLock (fun ltok -> checkFileInProjectCache.RemoveAnySimilar(ltok, (filename, stamp, options))) + + result /// 1. Repeatedly try to get cached file check results or get file "lock". /// From f8ae29d4c84cf56372716811f748d1a055d258bb Mon Sep 17 00:00:00 2001 From: Will Smith Date: Tue, 23 Mar 2021 10:25:09 -0700 Subject: [PATCH 32/35] fixing tests --- vsintegration/tests/UnitTests/CompletionProviderTests.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/UnitTests/CompletionProviderTests.fs b/vsintegration/tests/UnitTests/CompletionProviderTests.fs index 69c6b3afb23..8e2c70cfb47 100644 --- a/vsintegration/tests/UnitTests/CompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/CompletionProviderTests.fs @@ -104,10 +104,11 @@ let VerifyCompletionList(fileContents, marker, expected, unexpected) = let VerifyCompletionListExactly(fileContents: string, marker: string, expected: string list) = + let projectOptions = { projectOptions [| |] with ProjectId = Some(Guid.NewGuid().ToString()) } let caretPosition = fileContents.IndexOf(marker) + marker.Length let document, _ = RoslynTestHelpers.CreateDocument(filePath, fileContents) let actual = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions [| |], (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, document, caretPosition, projectOptions, (fun _ -> []), LanguageServicePerformanceOptions.Default, IntelliSenseOptions.Default) |> Async.RunSynchronously |> Option.defaultValue (ResizeArray()) |> Seq.toList From 4e45d471d13d4bcab9efcfa97b53d7d33389edd4 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Tue, 23 Mar 2021 13:48:24 -0700 Subject: [PATCH 33/35] fixing tests --- .../tests/UnitTests/SemanticColorizationServiceTests.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs index 179ab6f4b07..3846e2b6308 100644 --- a/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs +++ b/vsintegration/tests/UnitTests/SemanticColorizationServiceTests.fs @@ -32,6 +32,7 @@ type SemanticClassificationServiceTests() = let perfOptions = { LanguageServicePerformanceOptions.Default with AllowStaleCompletionResults = false } let getRanges (source: string) : SemanticClassificationItem list = + let projectOptions = { projectOptions with ProjectId = Some(Guid.NewGuid().ToString()) } asyncMaybe { let document, _ = RoslynTestHelpers.CreateDocument(filePath, source) let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, perfOptions, "") From 4672cd1298824bdb0093128acda98c28703cea4f Mon Sep 17 00:00:00 2001 From: Will Smith Date: Tue, 23 Mar 2021 15:00:54 -0700 Subject: [PATCH 34/35] Got a CancellationTokenSource has been disposed in a VS test. Adding a lock around it. --- src/fsharp/service/Reactor.fs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fsharp/service/Reactor.fs b/src/fsharp/service/Reactor.fs index 5f5eebe711a..7b356175f0a 100755 --- a/src/fsharp/service/Reactor.fs +++ b/src/fsharp/service/Reactor.fs @@ -41,6 +41,7 @@ type Reactor() = // so that when the reactor picks up a thread from the thread pool we can set the culture let mutable culture = CultureInfo(CultureInfo.CurrentUICulture.Name) + let gate = obj() let mutable bgOpCts = new CancellationTokenSource() let sw = new System.Diagnostics.Stopwatch() @@ -87,7 +88,7 @@ type Reactor() = | None -> None | Some (bgUserOpName, bgOpName, bgOpArg, bgOp) -> let oldBgOpCts = bgOpCts - bgOpCts <- new CancellationTokenSource() + lock gate (fun () -> bgOpCts <- new CancellationTokenSource()) oldBgOpCts.Dispose() Some (bgUserOpName, bgOpName, bgOpArg, bgOp ctok) @@ -114,7 +115,7 @@ type Reactor() = | Some (bgUserOpName, bgOpName, bgOpArg, bgOp) -> Trace.TraceInformation("Reactor: {0:n3} --> wait for background {1}.{2} ({3}), remaining {4}", DateTime.Now.TimeOfDay.TotalSeconds, bgUserOpName, bgOpName, bgOpArg, inbox.CurrentQueueLength) let oldBgOpCts = bgOpCts - bgOpCts <- new CancellationTokenSource() + lock gate (fun () -> bgOpCts <- new CancellationTokenSource()) oldBgOpCts.Dispose() try @@ -179,12 +180,12 @@ type Reactor() = // [Foreground Mailbox Accessors] ----------------------------------------------------------- member _.SetBackgroundOp(bgOpOpt) = Trace.TraceInformation("Reactor: {0:n3} enqueue start background, length {1}", DateTime.Now.TimeOfDay.TotalSeconds, builder.CurrentQueueLength) - bgOpCts.Cancel() + lock gate (fun () -> bgOpCts.Cancel()) builder.Post(SetBackgroundOp bgOpOpt) member _.CancelBackgroundOp() = Trace.TraceInformation("FCS: trying to cancel any active background work") - bgOpCts.Cancel() + lock gate (fun () -> bgOpCts.Cancel()) member _.EnqueueOp(userOpName, opName, opArg, op) = Trace.TraceInformation("Reactor: {0:n3} enqueue {1}.{2} ({3}), length {4}", DateTime.Now.TimeOfDay.TotalSeconds, userOpName, opName, opArg, builder.CurrentQueueLength) From 48cfe41d8f31274989659504570d44126be36ea8 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Tue, 23 Mar 2021 15:03:03 -0700 Subject: [PATCH 35/35] Fixing lock --- src/fsharp/service/Reactor.fs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fsharp/service/Reactor.fs b/src/fsharp/service/Reactor.fs index 7b356175f0a..e8d8de2f403 100755 --- a/src/fsharp/service/Reactor.fs +++ b/src/fsharp/service/Reactor.fs @@ -87,9 +87,11 @@ type Reactor() = match bgOpOpt with | None -> None | Some (bgUserOpName, bgOpName, bgOpArg, bgOp) -> - let oldBgOpCts = bgOpCts - lock gate (fun () -> bgOpCts <- new CancellationTokenSource()) - oldBgOpCts.Dispose() + lock gate (fun () -> + let oldBgOpCts = bgOpCts + bgOpCts <- new CancellationTokenSource() + oldBgOpCts.Dispose() + ) Some (bgUserOpName, bgOpName, bgOpArg, bgOp ctok) //Trace.TraceInformation("Reactor: --> set background op, remaining {0}", inbox.CurrentQueueLength) @@ -114,9 +116,11 @@ type Reactor() = | None -> () | Some (bgUserOpName, bgOpName, bgOpArg, bgOp) -> Trace.TraceInformation("Reactor: {0:n3} --> wait for background {1}.{2} ({3}), remaining {4}", DateTime.Now.TimeOfDay.TotalSeconds, bgUserOpName, bgOpName, bgOpArg, inbox.CurrentQueueLength) - let oldBgOpCts = bgOpCts - lock gate (fun () -> bgOpCts <- new CancellationTokenSource()) - oldBgOpCts.Dispose() + lock gate (fun () -> + let oldBgOpCts = bgOpCts + bgOpCts <- new CancellationTokenSource() + oldBgOpCts.Dispose() + ) try Eventually.force bgOpCts.Token bgOp |> ignore