diff --git a/ReSharper.FSharp/Directory.Build.props b/ReSharper.FSharp/Directory.Build.props
index db6c9e9455..1ec0b8c36e 100644
--- a/ReSharper.FSharp/Directory.Build.props
+++ b/ReSharper.FSharp/Directory.Build.props
@@ -33,5 +33,14 @@
$(Subplatform).Psi.Features_test_Framework.Props
$(Subplatform).Rider_RdBackend.Common.Props
$(Subplatform).Rider_Rider.Backend.Props
+ true
+ $(MSBuildThisFileDirectory)../../fsharp
+
+
+
+
+
+
+
diff --git a/ReSharper.FSharp/TypeProviders.Host.targets b/ReSharper.FSharp/TypeProviders.Host.targets
index 0ab3216525..b5db342ab0 100644
--- a/ReSharper.FSharp/TypeProviders.Host.targets
+++ b/ReSharper.FSharp/TypeProviders.Host.targets
@@ -14,7 +14,7 @@
-
+
diff --git a/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.NetCore/FSharp.TypeProviders.Host.NetCore.csproj b/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.NetCore/FSharp.TypeProviders.Host.NetCore.csproj
index aa48a1b6db..3f8fb7eb90 100644
--- a/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.NetCore/FSharp.TypeProviders.Host.NetCore.csproj
+++ b/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.NetCore/FSharp.TypeProviders.Host.NetCore.csproj
@@ -25,7 +25,6 @@
-
@@ -46,4 +45,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.csproj b/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.csproj
index 00b4dc0d6a..fe58864288 100644
--- a/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.csproj
+++ b/ReSharper.FSharp/src/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host/FSharp.TypeProviders.Host.csproj
@@ -26,7 +26,6 @@
-
@@ -39,4 +38,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Common/FSharp.Common.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Common/FSharp.Common.fsproj
index 4e64e7f372..1a10bb2efb 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Common/FSharp.Common.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Common/FSharp.Common.fsproj
@@ -12,6 +12,7 @@
true
JetBrains.ReSharper.Plugins.FSharp
JetBrains.ReSharper.Plugins.FSharp.Common
+ FS0057
@@ -73,7 +74,6 @@
-
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Checker/FcsCheckerService.fs b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Checker/FcsCheckerService.fs
index 178eb0518f..af8cda3953 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Checker/FcsCheckerService.fs
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Checker/FcsCheckerService.fs
@@ -25,6 +25,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Shim.AssemblyReader
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.CSharp
+open JetBrains.ReSharper.Psi.Caches
open JetBrains.ReSharper.Psi.Modules
open JetBrains.ReSharper.Psi.Tree
open JetBrains.ReSharper.Psi.VB
@@ -36,6 +37,7 @@ module FcsCheckerService =
SourceText.ofString(document.GetText())
+// add the project key?
type FcsProject =
{ OutputPath: VirtualFileSystemPath
ProjectOptions: FSharpProjectOptions
@@ -74,6 +76,59 @@ type FcsProject =
writer.WriteLine()
+[]
+type FcsSnapshotCache(fcsProjectProvider: IFcsProjectProvider, locks: IShellLocks) =
+ let snapshots = Dictionary()
+
+ let rec removeReferences (projectKey: FcsProjectKey) =
+ match fcsProjectProvider.GetReferencedModule(projectKey) with
+ | None -> ()
+ | Some referencedModule ->
+
+ for referencingProject in referencedModule.ReferencingProjects do
+ removeReferences referencingProject
+ snapshots.Remove(referencingProject) |> ignore
+
+ let remove (psiModule: IPsiModule) =
+ let projectKey = FcsProjectKey.Create(psiModule)
+ snapshots.Remove(projectKey) |> ignore
+ removeReferences projectKey
+
+ member this.GetProjectSnapshot(projectKey: FcsProjectKey, options: FSharpProjectOptions) =
+ // todo: use source files in file snapshots?
+ lock this (fun _ ->
+ snapshots.GetOrCreateValue(projectKey, fun (projectKey: FcsProjectKey) ->
+ FSharpProjectSnapshot.FromOptions(options).RunAsTask()
+ )
+ )
+
+ interface IPsiSourceFileCache with
+ member this.MarkAsDirty(sourceFile) =
+ locks.AssertWriteAccessAllowed()
+ remove sourceFile.PsiModule
+
+ member this.OnDocumentChange(sourceFile, _) =
+ locks.AssertWriteAccessAllowed()
+ remove sourceFile.PsiModule
+
+ member this.OnPsiChange(elementContainingChanges, _) =
+ if isNotNull elementContainingChanges then
+ locks.AssertWriteAccessAllowed()
+ remove (elementContainingChanges.GetPsiModule())
+
+ member this.HasDirtyFiles = false
+ member this.UpToDate _ = true
+ member this.SyncUpdate _ = ()
+
+ member this.Build(_, _) = null
+ member this.Drop _ = ()
+ member this.Dump(_, _) = ()
+ member this.Load(_, _) = null
+ member this.Merge(_, _) = ()
+ member this.MergeLoaded _ = ()
+ member this.Save(_, _) = ()
+
+
[]
type FcsProjectInvalidationType =
/// Used when invalidation is needed for a project still known to FCS.
@@ -88,14 +143,17 @@ type FcsProjectInvalidationType =
type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotifier: OnSolutionCloseNotifier,
settingsStore: ISettingsStore, locks: IShellLocks, configurations: RunsProducts.ProductConfigurations) =
- let checker =
- Environment.SetEnvironmentVariable("FCS_CheckFileInProjectCacheSize", "20")
+ let settingsStoreLive = settingsStore.BindToContextLive(lifetime, ContextRange.ApplicationWide)
- let settingsStoreLive = settingsStore.BindToContextLive(lifetime, ContextRange.ApplicationWide)
+ let getSettingProperty name =
+ let setting = SettingsUtil.getEntry settingsStore name
+ settingsStoreLive.GetValueProperty(lifetime, setting, null)
- let getSettingProperty name =
- let setting = SettingsUtil.getEntry settingsStore name
- settingsStoreLive.GetValueProperty(lifetime, setting, null)
+ // TODO: double check setting
+ let useTransparentCompiler = true //(getSettingProperty "UseTransparentCompiler").Value
+
+ let checker =
+ Environment.SetEnvironmentVariable("FCS_CheckFileInProjectCacheSize", "20")
let skipImpl = getSettingProperty "SkipImplementationAnalysis"
let analyzerProjectReferencesInParallel = getSettingProperty "ParallelProjectReferencesAnalysis"
@@ -106,7 +164,8 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
keepAllBackgroundResolutions = false,
keepAllBackgroundSymbolUses = false,
enablePartialTypeChecking = skipImpl.Value,
- parallelReferenceResolution = analyzerProjectReferencesInParallel.Value)
+ parallelReferenceResolution = analyzerProjectReferencesInParallel.Value,
+ useTransparentCompiler = useTransparentCompiler)
checker
@@ -119,6 +178,7 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
member val AssemblyReaderShim = Unchecked.defaultof with get, set
member x.Checker = checker.Value
+ member val UseTransparentCompiler = useTransparentCompiler
member this.AssertFcsAccessThread() =
()
@@ -174,8 +234,19 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
let source = FcsCheckerService.getSourceText sourceFile.Document
logger.Trace("ParseAndCheckFile: start {0}, {1}", path, opName)
+ let getParseAndCheckResults () =
+ if useTransparentCompiler then
+ let projectKey = FcsProjectKey.Create(psiModule)
+ let fcsSnapshotCache = sourceFile.GetSolution().GetComponent()
+ let snapshot = fcsSnapshotCache.GetProjectSnapshot(projectKey, options)
+ match x.Checker.ParseAndCheckFileInProject(path, snapshot).RunAsTask() with
+ | _, FSharpCheckFileAnswer.Aborted -> None
+ | parseFileResults, FSharpCheckFileAnswer.Succeeded checkFileResults -> Some(parseFileResults, checkFileResults)
+ else
+ x.Checker.ParseAndCheckDocument(path, source, options, allowStaleResults, opName).RunAsTask()
+
// todo: don't cancel the computation when file didn't change
- match x.Checker.ParseAndCheckDocument(path, source, options, allowStaleResults, opName).RunAsTask() with
+ match getParseAndCheckResults () with
| Some (parseResults, checkResults) ->
logger.Trace("ParseAndCheckFile: finish {0}, {1}", path, opName)
Some { ParseResults = parseResults; CheckResults = checkResults }
@@ -198,11 +269,25 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
let path = file.GetLocation().FullPath
logger.Trace("TryGetStaleCheckResults: start {0}, {1}", path, opName)
- match x.Checker.TryGetRecentCheckResultsForFile(path, options) with
- | Some (_, checkResults, _) ->
+ let recentCheckResults =
+ if not useTransparentCompiler then
+ x.Checker.TryGetRecentCheckResultsForFile(path, options)
+ |> Option.map (fun (_, checkResults, _) -> checkResults)
+ else
+ match x.FcsProjectProvider.GetFcsProject(file.PsiModule) with
+ | None -> None
+ | Some fcsProject ->
+
+ let projectKey = FcsProjectKey.Create(file.PsiModule)
+ let fcsSnapshotCache = file.GetSolution().GetComponent()
+ let snapshot = fcsSnapshotCache.GetProjectSnapshot(projectKey, fcsProject.ProjectOptions)
+ x.Checker.TryGetRecentCheckResultsForFile(path, snapshot)
+ |> Option.map snd
+
+ match recentCheckResults with
+ | Some checkResults ->
logger.Trace("TryGetStaleCheckResults: finish {0}, {1}", path, opName)
Some checkResults
-
| _ ->
logger.Trace("TryGetStaleCheckResults: fail {0}, {1}", path, opName)
None
@@ -210,7 +295,8 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
member x.GetCachedScriptOptions(path) =
if checker.IsValueCreated then
checker.Value.GetCachedScriptOptions(path)
- else None
+ else
+ None
member x.InvalidateFcsProject(projectOptions: FSharpProjectOptions, invalidationType: FcsProjectInvalidationType) =
if checker.IsValueCreated then
@@ -220,7 +306,13 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
checker.Value.ClearCache(Seq.singleton projectOptions)
| FcsProjectInvalidationType.Remove ->
logger.Trace("Invalidate FcsProject in FCS: {0}", projectOptions.ProjectFileName)
- checker.Value.InvalidateConfiguration(projectOptions)
+ if useTransparentCompiler then
+ // InvalidateConfiguration isn't required for the transparent compiler as it works differently.
+ // InvalidateConfiguration in the BackgroundCompiler will recreate the createBuilderNode.
+ // This is not required in the TransparentCompiler and so Clearing the cache would be the proper equivalent.
+ checker.Value.ClearCache(Seq.singleton projectOptions)
+ else
+ checker.Value.InvalidateConfiguration(projectOptions)
/// Use with care: returns wrong symbol inside its non-recursive declaration, see dotnet/fsharp#7694.
member x.ResolveNameAtLocation(sourceFile: IPsiSourceFile, names, coords, resolveExpr: bool, opName) =
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/ProjectModel/FSharpScriptPsiModuleFactory.fs b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/ProjectModel/FSharpScriptPsiModuleFactory.fs
index 2c049d4689..9c2b8f2135 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/ProjectModel/FSharpScriptPsiModuleFactory.fs
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/ProjectModel/FSharpScriptPsiModuleFactory.fs
@@ -263,7 +263,13 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
|> Option.iter (fun psiModule ->
match checkerService.GetCachedScriptOptions(path.FullPath) with
| Some options -> checkerService.InvalidateFcsProject(options, FcsProjectInvalidationType.Remove)
- | None -> ()
+ | None ->
+ if checkerService.UseTransparentCompiler then
+ // The transparent compiler always returns GetCachedScriptOptions
+ // We can easily construct the project identifier (as it is done in GetProjectOptionsFromScript/GetProjectSnapshotFromScript)
+ // and clear the cache that way.
+ let projectIdentifier = ProjectSnapshot.FSharpProjectIdentifier($"%s{path.FullPath}.fsproj", "")
+ checkerService.Checker.ClearCache(Seq.singleton projectIdentifier)
scriptsFromProjectFiles.RemoveValue(path, psiModule) |> ignore
removePsiModule psiModule
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Settings/FSharpOptions.fs b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Settings/FSharpOptions.fs
index f180cba49b..69f92f2da9 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Settings/FSharpOptions.fs
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Common/src/Settings/FSharpOptions.fs
@@ -29,6 +29,7 @@ module FSharpOptions =
let [] nonFSharpProjectInMemoryReferences = "Analyze C# and VB.NET project references in-memory"
let [] outOfScopeCompletion = "Enable out of scope items completion"
let [] topLevelOpenCompletion = "Add 'open' declarations to top level module or namespace"
+ let [] useTransparentCompilerDescription = "Use TransparentCompiler"
[, "FSharpOptions")>]
@@ -46,7 +47,10 @@ type FSharpOptions =
mutable EnableOutOfScopeCompletion: bool
[]
- mutable TopLevelOpenCompletion: bool }
+ mutable TopLevelOpenCompletion: bool
+
+ []
+ mutable UseTransparentCompiler: bool }
type FantomasLocationSettings =
| AutoDetected = 0
@@ -155,6 +159,9 @@ type FSharpOptionsProvider(lifetime, solution, settings, settingsSchema) =
member val NonFSharpProjectInMemoryReferences =
base.GetValueProperty("NonFSharpProjectInMemoryReferences").Value with get, set
+ member val UseTransparentCompiler =
+ base.GetValueProperty("UseTransparentCompiler").Value
+
member this.UpdateAssemblyReaderSetting() =
this.NonFSharpProjectInMemoryReferences <-
base.GetValueProperty("NonFSharpProjectInMemoryReferences").Value
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.ProjectModelBase/FSharp.ProjectModelBase.csproj b/ReSharper.FSharp/src/FSharp/FSharp.ProjectModelBase/FSharp.ProjectModelBase.csproj
index 8675fb00d2..34437a84d5 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.ProjectModelBase/FSharp.ProjectModelBase.csproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.ProjectModelBase/FSharp.ProjectModelBase.csproj
@@ -16,7 +16,6 @@
-
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Daemon/FSharp.Psi.Daemon.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Daemon/FSharp.Psi.Daemon.fsproj
index d09f9474b0..19cda6c7ed 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Daemon/FSharp.Psi.Daemon.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Daemon/FSharp.Psi.Daemon.fsproj
@@ -83,7 +83,6 @@
-
@@ -92,4 +91,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Features/FSharp.Psi.Features.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Features/FSharp.Psi.Features.fsproj
index b37f139a1d..3796339eec 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Features/FSharp.Psi.Features.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Features/FSharp.Psi.Features.fsproj
@@ -124,7 +124,6 @@
-
@@ -165,4 +164,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj
index fc0dbc626e..f849ff1c12 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj
@@ -142,7 +142,6 @@
-
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Services/FSharp.Psi.Services.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Services/FSharp.Psi.Services.fsproj
index 54176c82f2..dbdbdeb6f3 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Psi.Services/FSharp.Psi.Services.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi.Services/FSharp.Psi.Services.fsproj
@@ -88,7 +88,6 @@
-
@@ -97,4 +96,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi/FSharp.Psi.csproj b/ReSharper.FSharp/src/FSharp/FSharp.Psi/FSharp.Psi.csproj
index 8689b3c193..ff44f3d6a7 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Psi/FSharp.Psi.csproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi/FSharp.Psi.csproj
@@ -32,7 +32,6 @@
-
@@ -51,4 +50,4 @@
-
\ No newline at end of file
+
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Tests.Host/FSharp.Tests.Host.fsproj b/ReSharper.FSharp/src/FSharp/FSharp.Tests.Host/FSharp.Tests.Host.fsproj
index 9c4ca23083..1b060eee8a 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.Tests.Host/FSharp.Tests.Host.fsproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.Tests.Host/FSharp.Tests.Host.fsproj
@@ -21,7 +21,6 @@
-
diff --git a/ReSharper.FSharp/src/FSharp/FSharp.TypeProviders.Protocol/FSharp.TypeProviders.Protocol.csproj b/ReSharper.FSharp/src/FSharp/FSharp.TypeProviders.Protocol/FSharp.TypeProviders.Protocol.csproj
index 096eb79234..b215d4fd02 100644
--- a/ReSharper.FSharp/src/FSharp/FSharp.TypeProviders.Protocol/FSharp.TypeProviders.Protocol.csproj
+++ b/ReSharper.FSharp/src/FSharp/FSharp.TypeProviders.Protocol/FSharp.TypeProviders.Protocol.csproj
@@ -17,7 +17,6 @@
-
diff --git a/ReSharper.FSharp/test/src/FSharp.Common.Tests/FSharp.Common.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Common.Tests/FSharp.Common.Tests.fsproj
index 94e775834b..40be2ad749 100644
--- a/ReSharper.FSharp/test/src/FSharp.Common.Tests/FSharp.Common.Tests.fsproj
+++ b/ReSharper.FSharp/test/src/FSharp.Common.Tests/FSharp.Common.Tests.fsproj
@@ -20,7 +20,6 @@
-
diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj
index 641af1b8a8..4b9ffb53b9 100644
--- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj
+++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj
@@ -142,7 +142,6 @@
-
diff --git a/ReSharper.FSharp/test/src/FSharp.Tests.Common/FSharp.Tests.Common.fsproj b/ReSharper.FSharp/test/src/FSharp.Tests.Common/FSharp.Tests.Common.fsproj
index 844bd07cf0..f5c57209df 100644
--- a/ReSharper.FSharp/test/src/FSharp.Tests.Common/FSharp.Tests.Common.fsproj
+++ b/ReSharper.FSharp/test/src/FSharp.Tests.Common/FSharp.Tests.Common.fsproj
@@ -24,7 +24,6 @@
-
diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj
index c99878c9be..c5f7b82480 100644
--- a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj
+++ b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj
@@ -63,7 +63,6 @@
-