Skip to content

Commit bb1067a

Browse files
committed
add restart type providers action
1 parent e3f5173 commit bb1067a

File tree

14 files changed

+133
-21
lines changed

14 files changed

+133
-21
lines changed

ReSharper.FSharp/src/FSharp.Common/src/Checker/FcsCheckerService.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ open JetBrains.ReSharper.Psi.CSharp
2323
open JetBrains.ReSharper.Psi.Modules
2424
open JetBrains.ReSharper.Psi.Tree
2525
open JetBrains.ReSharper.Psi.VB
26+
open JetBrains.ReSharper.Resources.Shell
2627
open JetBrains.Util
2728

2829
module FcsCheckerService =
@@ -154,6 +155,7 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
154155
|> Seq.iter x.InvalidateFcsProject
155156

156157
member x.InvalidateFcsProjects(solution: ISolution, isApplicable: IProject -> bool) =
158+
use lock = ReadLockCookie.Create()
157159
if checker.IsValueCreated then
158160
solution.GetAllProjects()
159161
|> Seq.filter isApplicable

ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ module FSharpExperimentalFeatures =
7777
let [<Literal>] formatter = "Enable F# code formatter"
7878
let [<Literal>] fsiInteractiveEditor = "Enable analysis of F# Interactive editor (experimental)"
7979
let [<Literal>] outOfProcessTypeProviders = "Host type providers out-of-process (solution reload required)"
80+
let [<Literal>] hostTypeProvidersFromTempFolder = "Host type providers from Temp folder"
8081

8182

8283
[<SettingsKey(typeof<FSharpOptions>, "F# experimental features")>]
@@ -94,7 +95,10 @@ type FSharpExperimentalFeatures =
9495
mutable FsiInteractiveEditor: bool
9596

9697
[<SettingsEntry(true, FSharpExperimentalFeatures.outOfProcessTypeProviders)>]
97-
mutable OutOfProcessTypeProviders: bool }
98+
mutable OutOfProcessTypeProviders: bool
99+
100+
[<SettingsEntry(false, FSharpExperimentalFeatures.hostTypeProvidersFromTempFolder)>]
101+
mutable HostTypeProvidersFromTempFolder: bool }
98102

99103

100104
[<AllowNullLiteral>]
@@ -129,6 +133,7 @@ type FSharpExperimentalFeaturesProvider(lifetime, solution, settings, settingsSc
129133
member val RedundantParensAnalysis = base.GetValueProperty<bool>("RedundantParensAnalysis")
130134
member val Formatter = base.GetValueProperty<bool>("Formatter")
131135
member val OutOfProcessTypeProviders = base.GetValueProperty<bool>("OutOfProcessTypeProviders")
136+
member val HostTypeProvidersFromTempFolder = base.GetValueProperty<bool>("HostTypeProvidersFromTempFolder")
132137

133138

134139
module FSharpTypeHintOptions =
@@ -176,6 +181,11 @@ type FSharpOptionsPage(lifetime: Lifetime, optionsPageContext, settings,
176181
this.AddBoolOption((fun key -> key.EnableReactorMonitor), RichText(enableFcsReactorMonitor), null) |> ignore
177182
this.AddBoolOption((fun key -> key.BackgroundTypeCheck), RichText(backgroundTypeCheck), null) |> ignore
178183
this.AddBoolOption((fun key -> key.OutOfProcessTypeProviders), RichText(FSharpExperimentalFeatures.outOfProcessTypeProviders), null) |> ignore
184+
do
185+
use indent = this.Indent()
186+
[ this.AddBoolOption((fun key -> key.HostTypeProvidersFromTempFolder), RichText(FSharpExperimentalFeatures.hostTypeProvidersFromTempFolder), null) ]
187+
|> Seq.iter (fun checkbox ->
188+
this.AddBinding(checkbox, BindingStyle.IsEnabledProperty, (fun key -> key.OutOfProcessTypeProviders), id))
179189

180190
if configurations.IsInternalMode() then
181191
this.AddHeader("Experimental features options")

ReSharper.FSharp/src/FSharp.Common/src/Shim/TypeProviders/ExtensionTypingProviderShim.fs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ open FSharp.Core.CompilerServices
88
open JetBrains.Core
99
open JetBrains.Lifetimes
1010
open JetBrains.ProjectModel
11+
open JetBrains.ProjectModel.Tasks
12+
open JetBrains.Rd.Tasks
13+
open JetBrains.ReSharper.Feature.Services.Daemon
14+
open JetBrains.ReSharper.Plugins.FSharp.Checker
1115
open JetBrains.ReSharper.Plugins.FSharp.Settings
1216
open JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Protocol
1317
open JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Protocol.Exceptions
1418
open JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Protocol.Models
19+
open JetBrains.ReSharper.Psi.Files
1520

1621
type IProxyExtensionTypingProvider =
1722
inherit IExtensionTypingProvider
@@ -22,10 +27,13 @@ type IProxyExtensionTypingProvider =
2227
[<SolutionComponent>]
2328
type ExtensionTypingProviderShim(solution: ISolution, toolset: ISolutionToolset,
2429
experimentalFeatures: FSharpExperimentalFeaturesProvider,
30+
checkerService: FcsCheckerService, daemon: IDaemon, psiFiles: IPsiFiles,
31+
scheduler: ISolutionLoadTasksScheduler,
2532
typeProvidersLoadersFactory: TypeProvidersExternalProcessFactory) as this =
2633
let lifetime = solution.GetLifetime()
2734
let defaultShim = ExtensionTypingProvider
2835
let outOfProcess = experimentalFeatures.OutOfProcessTypeProviders
36+
let hostFromTemp = experimentalFeatures.HostTypeProvidersFromTempFolder
2937

3038
let mutable connection: TypeProvidersConnection = null
3139
let mutable typeProvidersHostLifetime: LifetimeDefinition = null
@@ -35,22 +43,37 @@ type ExtensionTypingProviderShim(solution: ISolution, toolset: ISolutionToolset,
3543
isNotNull connection && connection.IsActive
3644

3745
let terminateConnection () =
38-
if isConnectionAlive() then typeProvidersHostLifetime.Terminate()
46+
if isConnectionAlive () then typeProvidersHostLifetime.Terminate()
3947

4048
let connect () =
4149
if not (isConnectionAlive ()) then
4250
typeProvidersHostLifetime <- Lifetime.Define(lifetime)
4351
connection <- typeProvidersLoadersFactory.Create(typeProvidersHostLifetime.Lifetime).Run()
4452
typeProvidersManager <- TypeProvidersManager(connection) :?> _
4553

54+
let restart _ =
55+
let paths = typeProvidersManager.GetAssemblies()
56+
terminateConnection ()
57+
checkerService.InvalidateFcsProjects(solution, fun x -> paths.Contains(x.Location))
58+
psiFiles.IncrementModificationTimestamp(null)
59+
daemon.Invalidate()
60+
Unit.Instance
61+
4662
do
47-
lifetime.Bracket((fun () -> ExtensionTypingProvider <- this),
48-
fun () -> ExtensionTypingProvider <- defaultShim)
63+
lifetime.Bracket((fun () -> ExtensionTypingProvider <- this), fun () -> ExtensionTypingProvider <- defaultShim)
4964

5065
toolset.Changed.Advise(lifetime, fun _ -> terminateConnection ())
5166
outOfProcess.Change.Advise(lifetime, fun enabled ->
5267
if enabled.HasNew && not enabled.New then terminateConnection ())
5368

69+
hostFromTemp.Change.Advise(lifetime, fun enabled ->
70+
if enabled.HasNew && not enabled.New then terminateConnection ())
71+
72+
let rdTypeProvidersHost = solution.RdFSharpModel().FSharpTypeProvidersHost
73+
74+
rdTypeProvidersHost.RestartTypeProviders.Set(restart)
75+
rdTypeProvidersHost.IsLaunched.Set(fun _ -> isNotNull connection)
76+
5477
interface IProxyExtensionTypingProvider with
5578
member this.InstantiateTypeProvidersOfAssembly(runTimeAssemblyFileName: string,
5679
designTimeAssemblyNameString: string, resolutionEnvironment: ResolutionEnvironment,
@@ -66,7 +89,7 @@ type ExtensionTypingProviderShim(solution: ISolution, toolset: ISolutionToolset,
6689
try
6790
typeProvidersManager.GetOrCreate(runTimeAssemblyFileName, designTimeAssemblyNameString,
6891
resolutionEnvironment, isInvalidationSupported, isInteractive, systemRuntimeContainsType,
69-
systemRuntimeAssemblyVersion, compilerToolsPath)
92+
systemRuntimeAssemblyVersion, compilerToolsPath, hostFromTemp.Value)
7093
with :? TypeProvidersInstantiationException as e ->
7194
logError (TypeProviderError(e.FcsNumber, "", m, [e.Message]))
7295
[]

ReSharper.FSharp/src/FSharp.Common/src/Shim/TypeProviders/TypeProvidersManager.fs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ type internal TypeProvidersCache() =
4848
member x.Get(id) =
4949
proxyTypeProvidersPerId.[id]
5050

51+
member x.GetProvidersLocations() =
52+
typeProvidersPerAssembly.Keys
53+
|> Seq.map snd
54+
|> Seq.distinct
55+
|> Seq.map FileSystemPath.Parse
56+
|> HashSet
57+
5158
member x.Dump() =
5259
let typeProviders =
5360
proxyTypeProvidersPerId
@@ -68,8 +75,10 @@ type IProxyTypeProvidersManager =
6875
isInteractive: bool *
6976
systemRuntimeContainsType: (string -> bool) *
7077
systemRuntimeAssemblyVersion: Version *
71-
compilerToolsPath: string list -> ITypeProvider list
78+
compilerToolsPath: string list *
79+
shadowCopyDesignTimeAssembly: bool -> ITypeProvider list
7280

81+
abstract member GetAssemblies: unit -> HashSet<FileSystemPath>
7382
abstract member Dump: unit -> string
7483

7584
type TypeProvidersManager(connection: TypeProvidersConnection) =
@@ -85,8 +94,8 @@ type TypeProvidersManager(connection: TypeProvidersConnection) =
8594
member x.GetOrCreate(runTimeAssemblyFileName: string, designTimeAssemblyNameString: string,
8695
resolutionEnvironment: ResolutionEnvironment, isInvalidationSupported: bool, isInteractive: bool,
8796
systemRuntimeContainsType: string -> bool, systemRuntimeAssemblyVersion: Version,
88-
compilerToolsPath: string list) =
89-
let envKey = $"{designTimeAssemblyNameString}+{resolutionEnvironment.resolutionFolder}"
97+
compilerToolsPath: string list, shadowCopyDesignTimeAssembly) =
98+
let envKey = (designTimeAssemblyNameString, resolutionEnvironment.resolutionFolder)
9099

91100
let result =
92101
let fakeTcImports = getFakeTcImports systemRuntimeContainsType
@@ -96,7 +105,8 @@ type TypeProvidersManager(connection: TypeProvidersConnection) =
96105
InstantiateTypeProvidersOfAssemblyParameters(runTimeAssemblyFileName,
97106
designTimeAssemblyNameString, resolutionEnvironment.toRdResolutionEnvironment(),
98107
isInvalidationSupported, isInteractive, systemRuntimeAssemblyVersion.ToString(),
99-
compilerToolsPath |> Array.ofList, fakeTcImports), RpcTimeouts.Maximal))
108+
compilerToolsPath |> Array.ofList, fakeTcImports, shadowCopyDesignTimeAssembly),
109+
RpcTimeouts.Maximal))
100110

101111
let typeProviderProxies =
102112
[ for tp in result.TypeProviders ->
@@ -113,3 +123,6 @@ type TypeProvidersManager(connection: TypeProvidersConnection) =
113123

114124
member this.Dump() =
115125
$"{typeProviders.Dump()}\n\n{tpContext.Dump()}"
126+
127+
member this.GetAssemblies() =
128+
typeProviders.GetProvidersLocations()

ReSharper.FSharp/src/FSharp.TypeProviders.Host/src/Hosts/TypeProvidersHost.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ private InstantiationResult InstantiateTypeProvidersOfAssembly(InstantiateTypePr
111111
return new InstantiationResult(rdTypeProviders.ToArray(), cachedIds.ToArray());
112112
}
113113

114-
private static Unit Die(Unit _)
114+
private Unit Die(Unit _)
115115
{
116+
myTypeProvidersContext.TypeProvidersLoader.Dispose();
116117
Environment.Exit(0);
117118
return Unit.Instance;
118119
}

ReSharper.FSharp/src/FSharp.TypeProviders.Host/src/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ internal static class Program
66
{
77
public static void Main(string[] args)
88
{
9-
AppDomain.CurrentDomain.AssemblyResolve += RiderPluginAssemblyResolver.Resolve;
9+
AppDomain.CurrentDomain.AssemblyResolve += TypeProvidersAssemblyResolver.Resolve;
1010
MainInternal(args);
1111
}
1212

ReSharper.FSharp/src/FSharp.TypeProviders.Host/src/RiderPluginAssemblyResolver.cs renamed to ReSharper.FSharp/src/FSharp.TypeProviders.Host/src/TypeProvidersAssemblyResolver.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
namespace JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Host
77
{
8-
public static class RiderPluginAssemblyResolver
8+
public static class TypeProvidersAssemblyResolver
99
{
1010
private const string AdditionalProbingPathsEnvVar = "RIDER_PLUGIN_ADDITIONAL_PROBING_PATHS";
1111
private static readonly List<string> OurAdditionalProbingPaths = new List<string>();
1212

13-
static RiderPluginAssemblyResolver()
13+
static TypeProvidersAssemblyResolver()
1414
{
1515
var paths = Environment.GetEnvironmentVariable(AdditionalProbingPathsEnvVar);
1616
if (string.IsNullOrWhiteSpace(paths)) return;

ReSharper.FSharp/src/FSharp.TypeProviders.Host/src/TypeProvidersContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public IProvidedRdModelsCreator<CustomAttributeData, RdCustomAttributeData>
5555
public TypeProvidersContext(ILogger logger)
5656
{
5757
Logger = logger;
58-
TypeProvidersLoader = new TypeProvidersLoader();
58+
TypeProvidersLoader = new TypeProvidersLoader(logger);
5959

6060
TypeProvidersCache = new TypeProvidersCache();
6161
ProvidedTypesCache = new ProvidedTypesCache(ProvidedTypesComparer.Instance);
Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,53 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using FSharp.Compiler;
5+
using JetBrains.Diagnostics;
46
using JetBrains.ReSharper.Plugins.FSharp.Shim.TypeProviders;
57
using JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Protocol.Exceptions;
68
using JetBrains.ReSharper.Plugins.FSharp.Util;
79
using JetBrains.Rider.FSharp.TypeProviders.Protocol.Server;
10+
using JetBrains.Util;
811
using Microsoft.FSharp.Collections;
912
using Microsoft.FSharp.Core;
1013
using Microsoft.FSharp.Core.CompilerServices;
1114
using Range = FSharp.Compiler.Text.Range;
1215

1316
namespace JetBrains.ReSharper.Plugins.FSharp.TypeProviders.Host
1417
{
15-
public interface ITypeProvidersLoader
18+
public interface ITypeProvidersLoader : IDisposable
1619
{
1720
IEnumerable<ITypeProvider> InstantiateTypeProvidersOfAssembly(
1821
InstantiateTypeProvidersOfAssemblyParameters parameters);
1922
}
2023

2124
public class TypeProvidersLoader : ITypeProvidersLoader
2225
{
26+
private readonly ILogger myLogger;
27+
private readonly Dictionary<string, string> myShadowCopyMapping = new Dictionary<string, string>();
28+
29+
public TypeProvidersLoader(ILogger logger)
30+
{
31+
myLogger = logger;
32+
}
33+
2334
private readonly FSharpFunc<TypeProviderError, Unit> myLogError =
2435
FSharpFunc<TypeProviderError, Unit>.FromConverter(e =>
2536
throw new TypeProvidersInstantiationException(e.ContextualErrorMessage, e.Number));
2637

38+
private string GetAssemblyShadowCopy(string designTimeAssembly)
39+
{
40+
if (!myShadowCopyMapping.TryGetValue(designTimeAssembly, out var shadowCopy))
41+
{
42+
shadowCopy = Path.ChangeExtension(Path.GetTempFileName(), "dll");
43+
File.Copy(designTimeAssembly, shadowCopy);
44+
myLogger.Log(LoggingLevel.INFO, $"Shadow copying assembly {designTimeAssembly} to {shadowCopy}");
45+
myShadowCopyMapping.Add(designTimeAssembly, shadowCopy);
46+
}
47+
48+
return shadowCopy;
49+
}
50+
2751
public IEnumerable<ITypeProvider> InstantiateTypeProvidersOfAssembly(
2852
InstantiateTypeProvidersOfAssemblyParameters parameters)
2953
{
@@ -32,11 +56,23 @@ public IEnumerable<ITypeProvider> InstantiateTypeProvidersOfAssembly(
3256
var systemRuntimeAssemblyVersion = Version.Parse(parameters.SystemRuntimeAssemblyVersion);
3357
var compilerToolsPath = ListModule.OfSeq(parameters.CompilerToolsPath);
3458

59+
// todo: comment
60+
var designTimeAssembly = parameters.ShadowCopyDesignTimeAssembly
61+
? GetAssemblyShadowCopy(parameters.RunTimeAssemblyFileName)
62+
: parameters.DesignTimeAssemblyNameString;
63+
3564
var typeProviders = ExtensionTyping.Shim.ExtensionTypingProvider.InstantiateTypeProvidersOfAssembly(
36-
parameters.RunTimeAssemblyFileName, parameters.DesignTimeAssemblyNameString,
65+
parameters.RunTimeAssemblyFileName, designTimeAssembly,
3766
resolutionEnvironment, parameters.IsInvalidationSupported, parameters.IsInteractive, systemRuntimeContainsType,
3867
systemRuntimeAssemblyVersion, compilerToolsPath, myLogError, Range.Zero);
3968
return typeProviders;
4069
}
70+
71+
public void Dispose()
72+
{
73+
foreach (var shadowCopy in myShadowCopyMapping.Values)
74+
if (File.Exists(shadowCopy))
75+
File.Delete(shadowCopy);
76+
}
4177
}
4278
}

ReSharper.FSharp/test/src/FSharp.Tests.Host/FSharpTestHost.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type FSharpTestHost(lifetime: Lifetime, solution: ISolution, checkerService: Fcs
5454
solution.GetComponent<IProxyExtensionTypingProvider>().DumpTypeProvidersProcess()
5555

5656
do
57-
let fsTestHost = solution.RdFSharpModel().FsharpTestHost
57+
let fsTestHost = solution.RdFSharpModel().FSharpTestHost
5858

5959
// We want to get events published by background checker.
6060
checkerService.Checker.ImplicitlyStartBackgroundWork <- true

0 commit comments

Comments
 (0)