Skip to content

Commit 927a802

Browse files
committed
More WIP, try and use snapshot for script stuff.
1 parent dcdf888 commit 927a802

File tree

5 files changed

+103
-74
lines changed

5 files changed

+103
-74
lines changed

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -202,25 +202,27 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
202202
| _ -> { new IDisposable with member this.Dispose() = () }
203203

204204
member x.TryGetStaleCheckResults([<NotNull>] file: IPsiSourceFile, opName) =
205-
match x.FcsProjectProvider.GetProjectOptions(file) with
205+
match x.FcsProjectProvider.GetProjectSnapshot(file) with
206206
| None -> None
207-
| Some options ->
207+
| Some snapshot ->
208208

209209
let path = file.GetLocation().FullPath
210210
logger.Trace("TryGetStaleCheckResults: start {0}, {1}", path, opName)
211211

212-
match x.Checker.TryGetRecentCheckResultsForFile(path, options) with
213-
| Some (_, checkResults, _) ->
214-
logger.Trace("TryGetStaleCheckResults: finish {0}, {1}", path, opName)
215-
Some checkResults
216-
217-
| _ ->
218-
logger.Trace("TryGetStaleCheckResults: fail {0}, {1}", path, opName)
219-
None
212+
// TODO: TryGetRecentCheckResultsForFile for Snapshot
213+
Unchecked.defaultof<FSharpProjectSnapshot option>
214+
// match x.Checker.TryGetRecentCheckResultsForFile(path, snapshot) with
215+
// | Some (_, checkResults, _) ->
216+
// logger.Trace("TryGetStaleCheckResults: finish {0}, {1}", path, opName)
217+
// Some checkResults
218+
//
219+
// | _ ->
220+
// logger.Trace("TryGetStaleCheckResults: fail {0}, {1}", path, opName)
221+
// None
220222

221-
member x.GetCachedScriptOptions(path) =
223+
member x.GetCachedScriptSnapshot(path) =
222224
if checker.IsValueCreated then
223-
checker.Value.GetCachedScriptOptions(path)
225+
checker.Value.GetCachedScriptSnapshot(path)
224226
else None
225227

226228
member x.InvalidateFcsProject(projectSnapshot: FSharpProjectSnapshot, invalidationType: FcsProjectInvalidationType) =
@@ -275,8 +277,8 @@ type IFcsProjectProvider =
275277
abstract GetFcsProject: psiModule: IPsiModule -> FcsProject option
276278
abstract GetPsiModule: outputPath: VirtualFileSystemPath -> IPsiModule option
277279

278-
abstract GetProjectOptions: sourceFile: IPsiSourceFile -> FSharpProjectOptions option
279-
abstract GetProjectOptions: psiModule: IPsiModule -> FSharpProjectOptions option
280+
abstract GetProjectSnapshot: sourceFile: IPsiSourceFile -> FSharpProjectSnapshot option
281+
abstract GetProjectSnapshot: psiModule: IPsiModule -> FSharpProjectSnapshot option
280282

281283
abstract GetFileIndex: IPsiSourceFile -> int
282284
abstract GetParsingOptions: sourceFile: IPsiSourceFile -> FSharpParsingOptions
@@ -304,7 +306,7 @@ type IScriptFcsProjectProvider =
304306
abstract GetScriptSnapshot: IPsiSourceFile -> FSharpProjectSnapshot option
305307
// TODO: unused?
306308
// abstract GetScriptOptions: VirtualFileSystemPath * string -> FSharpProjectOptions option
307-
abstract OptionsUpdated: Signal<VirtualFileSystemPath * FSharpProjectOptions>
309+
abstract SnapshotUpdated: Signal<VirtualFileSystemPath * FSharpProjectSnapshot>
308310
abstract SyncUpdate: bool
309311

310312

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,6 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
319319
| None -> None
320320
| Some projectSnapshot ->
321321

322-
// let snapshot = FSharpProjectSnapshot.FromOptions projectOptions
323-
324322
let parsingOptions =
325323
{ FSharpParsingOptions.Default with
326324
SourceFiles = [| sourceFile.GetLocation().FullPath |]

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

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
namespace JetBrains.ReSharper.Plugins.FSharp.Checker
22

3+
#nowarn "57"
4+
35
open System
46
open System.Collections.Generic
7+
open System.Threading.Tasks
58
open FSharp.Compiler.CodeAnalysis
69
open FSharp.Compiler.Text
710
open JetBrains.DataFlow
@@ -24,13 +27,13 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
2427

2528
let scriptFcsProjects = Dictionary<VirtualFileSystemPath, FcsProject option>()
2629

27-
let mutable defaultOptions: FSharpProjectOptions option option = None
30+
let mutable defaultSnapshot: FSharpProjectSnapshot option option = None
2831

2932
let currentRequests = HashSet<VirtualFileSystemPath>()
3033
let dirtyPaths = HashSet<VirtualFileSystemPath>()
3134

32-
let optionsUpdated =
33-
new Signal<VirtualFileSystemPath * FSharpProjectOptions>("ScriptFcsProjectProvider.optionsUpdated")
35+
let snapshotUpdated =
36+
new Signal<VirtualFileSystemPath * FSharpProjectSnapshot>("ScriptFcsProjectProvider.optionsUpdated")
3437

3538
let isHeadless =
3639
let var = Environment.GetEnvironmentVariable("JET_HEADLESS_MODE") |> Option.ofObj |> Option.defaultValue "false"
@@ -63,60 +66,84 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
6366
IPropertyEx.FlowInto(languageVersion, lifetime, flags, getOtherFlags)
6467
flags
6568

66-
let getOptionsImpl (path: VirtualFileSystemPath) source =
69+
let getSnapshotImpl (path: VirtualFileSystemPath) source : FSharpProjectSnapshot option =
6770
let path = path.FullPath
6871
let source = SourceText.ofString source
6972
let targetNetFramework = not PlatformUtil.IsRunningOnCore && scriptSettings.TargetNetFramework.Value
7073

7174
let toolset = toolset.GetDotNetCoreToolset()
72-
let getScriptOptionsAsync =
75+
let getScriptSnapshotAsync: Async<FSharpProjectSnapshot * FSharp.Compiler.Diagnostics.FSharpDiagnostic list> =
7376
if isNotNull toolset && isNotNull toolset.Sdk then
7477
let sdkRootFolder = toolset.Cli.NotNull("cli").SdkRootFolder.NotNull("sdkRootFolder")
7578
let sdkFolderPath = sdkRootFolder / toolset.Sdk.NotNull("sdk").FolderName.NotNull("sdkFolderName")
76-
checkerService.Checker.GetProjectOptionsFromScript(path, source,
77-
otherFlags = otherFlags.Value.Value,
78-
assumeDotNetFramework = targetNetFramework,
79-
sdkDirOverride = sdkFolderPath.FullPath)
79+
// TODO: GetProjectOptionsFromScript does not exists for Snapshot
80+
Unchecked.defaultof<Async<FSharpProjectSnapshot * FSharp.Compiler.Diagnostics.FSharpDiagnostic list>>
81+
// checkerService.Checker.GetProjectOptionsFromScript(path, source,
82+
// otherFlags = otherFlags.Value.Value,
83+
// assumeDotNetFramework = targetNetFramework,
84+
// sdkDirOverride = sdkFolderPath.FullPath)
8085
else
81-
checkerService.Checker.GetProjectOptionsFromScript(path, source,
82-
otherFlags = otherFlags.Value.Value,
83-
assumeDotNetFramework = targetNetFramework)
86+
Unchecked.defaultof<Async<FSharpProjectSnapshot * FSharp.Compiler.Diagnostics.FSharpDiagnostic list>>
87+
// checkerService.Checker.GetProjectOptionsFromScript(path, source,
88+
// otherFlags = otherFlags.Value.Value,
89+
// assumeDotNetFramework = targetNetFramework)
8490

8591
try
86-
let options, errors = getScriptOptionsAsync.RunAsTask()
92+
let snapshot, errors = getScriptSnapshotAsync.RunAsTask()
8793
if not errors.IsEmpty then
8894
logErrors logger (sprintf "Script options for %s" path) errors
89-
Some options
95+
Some snapshot
9096
with
9197
| OperationCanceled -> reraise()
9298
| exn ->
9399
logger.Warn("Error while getting script options for {0}: {1}", path, exn.Message)
94100
logger.LogExceptionSilently(exn)
95101
None
96102

97-
let getDefaultOptions (path: VirtualFileSystemPath) =
98-
let withPath (options: FSharpProjectOptions option) =
99-
match options with
100-
| Some options -> Some { options with SourceFiles = [| path.FullPath |] }
101-
| _ -> None
102-
103-
match defaultOptions with
103+
let getDefaultSnapshot (path: VirtualFileSystemPath) (source: string): ProjectSnapshot.FSharpProjectSnapshot option =
104+
let withPath (snapshot: FSharpProjectSnapshot option) =
105+
snapshot
106+
|> Option.map (fun snapshot ->
107+
let name = path.Name
108+
let version = string path.Info.ModificationTimeUtc.Ticks
109+
let getSource () = SourceTextNew.ofString source |> Task.FromResult
110+
let sourceFiles =
111+
ProjectSnapshot.FSharpFileSnapshot.Create(name, version, getSource)
112+
|> List.singleton
113+
114+
FSharpProjectSnapshot.Create(
115+
snapshot.ProjectFileName,
116+
snapshot.ProjectId,
117+
sourceFiles,
118+
snapshot.ReferencesOnDisk,
119+
snapshot.OtherOptions,
120+
snapshot.ReferencedProjects,
121+
snapshot.IsIncompleteTypeCheckEnvironment,
122+
snapshot.UseScriptResolutionRules,
123+
snapshot.LoadTime,
124+
snapshot.UnresolvedReferences,
125+
snapshot.OriginalLoadReferences,
126+
snapshot.Stamp
127+
)
128+
)
129+
130+
match defaultSnapshot with
104131
| Some options -> withPath options
105132
| _ ->
106133

107134
lock defaultOptionsLock (fun _ ->
108-
match defaultOptions with
135+
match defaultSnapshot with
109136
| Some options -> withPath options
110137
| _ ->
111138

112-
let newOptions = getOptionsImpl path ""
113-
defaultOptions <- Some newOptions
139+
let newOptions = getSnapshotImpl path ""
140+
defaultSnapshot <- Some newOptions
114141
newOptions
115142
)
116143

117-
let createFcsProject (path: VirtualFileSystemPath) options =
118-
options
119-
|> Option.map (fun options ->
144+
let createFcsProject (path: VirtualFileSystemPath) snapshot =
145+
snapshot
146+
|> Option.map (fun snapshot ->
120147
let parsingOptions =
121148
{ FSharpParsingOptions.Default with
122149
SourceFiles = [| path.FullPath |]
@@ -125,7 +152,7 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
125152
IsExe = true }
126153

127154
{ OutputPath = path
128-
ProjectOptions = options
155+
ProjectSnapshot = snapshot
129156
ParsingOptions = parsingOptions
130157
FileIndices = dict [path, 0]
131158
ImplementationFilesWithSignatures = EmptySet.Instance
@@ -143,11 +170,11 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
143170
currentRequests.Add(path) |> ignore
144171
dirtyPaths.Remove(path) |> ignore
145172
let oldOptions = tryGetValue path scriptFcsProjects |> Option.bind id
146-
let newOptions = getOptionsImpl path source
173+
let newSnapshot = getSnapshotImpl path source
147174

148175
scriptFcsProjects[path] <-
149-
newOptions
150-
|> Option.map (fun options ->
176+
newSnapshot
177+
|> Option.map (fun snapshot ->
151178
let parsingOptions =
152179
{ FSharpParsingOptions.Default with
153180
SourceFiles = [| path.FullPath |]
@@ -158,27 +185,27 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
158185
let indices = Dictionary()
159186

160187
{ OutputPath = path
161-
ProjectOptions = options
188+
ProjectSnapshot = snapshot
162189
ParsingOptions = parsingOptions
163190
FileIndices = indices
164191
ImplementationFilesWithSignatures = EmptySet.Instance
165192
ReferencedModules = EmptySet.Instance }
166193
)
167194

168-
match oldOptions, newOptions with
169-
| Some oldOptions, Some newOptions ->
170-
let areEqualForChecking (options1: FSharpProjectOptions) (options2: FSharpProjectOptions) =
171-
let arrayEq a1 a2 =
172-
Array.length a1 = Array.length a2 && Array.forall2 (=) a1 a2
195+
match oldOptions, newSnapshot with
196+
| Some oldOptions, Some newSnapshot ->
197+
let areEqualForChecking (options1: FSharpProjectSnapshot) (options2: FSharpProjectSnapshot) =
198+
let listEq l1 l2 =
199+
List.length l1 = List.length l2 && List.forall2 (=) l1 l2
173200

174-
arrayEq options1.OtherOptions options2.OtherOptions &&
175-
arrayEq options1.SourceFiles options2.SourceFiles
201+
listEq options1.OtherOptions options2.OtherOptions &&
202+
listEq options1.SourceFiles options2.SourceFiles
176203

177-
if not (areEqualForChecking oldOptions.ProjectOptions newOptions) then
178-
optionsUpdated.Fire((path, newOptions))
204+
if not (areEqualForChecking oldOptions.ProjectSnapshot newSnapshot) then
205+
snapshotUpdated.Fire((path, newSnapshot))
179206

180207
| _, Some newOptions ->
181-
optionsUpdated.Fire((path, newOptions))
208+
snapshotUpdated.Fire((path, newOptions))
182209

183210
| _ -> ()
184211

@@ -203,7 +230,7 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
203230
if isHeadless && allowRetry then
204231
getFcsProject path source false
205232
else
206-
getDefaultOptions path |> createFcsProject path
233+
getDefaultSnapshot path source |> createFcsProject path
207234

208235
let getOptions path source : FSharpProjectSnapshot option =
209236
getFcsProject path source true |> Option.map (fun fcsProject -> fcsProject.ProjectSnapshot)
@@ -223,5 +250,5 @@ type ScriptFcsProjectProvider(lifetime: Lifetime, logger: ILogger, checkerServic
223250
let source = sourceFile.Document.GetText()
224251
getFcsProject path source true
225252

226-
member this.OptionsUpdated = optionsUpdated
253+
member this.SnapshotUpdated = snapshotUpdated
227254
member this.SyncUpdate = isHeadless

ReSharper.FSharp/src/FSharp/FSharp.Common/src/ProjectModel/FSharpScriptPsiModuleFactory.fs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
namespace rec JetBrains.ReSharper.Plugins.FSharp.ProjectModel.Scripts
22

3+
#nowarn "57"
4+
35
open System
46
open System.Collections.Generic
57
open System.IO
@@ -64,16 +66,16 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
6466
let platformInfo = platformInfos |> Seq.maxBy (fun info -> info.TargetFrameworkId.Version)
6567
platformInfo.TargetFrameworkId
6668

67-
let getScriptReferences (scriptPath: VirtualFileSystemPath) scriptOptions =
69+
let getScriptReferences (scriptPath: VirtualFileSystemPath) (scriptSnapshot: FSharpProjectSnapshot) =
6870
let assembliesPaths = HashSet<VirtualFileSystemPath>()
69-
for o in scriptOptions.OtherOptions do
71+
for o in scriptSnapshot.OtherOptions do
7072
if o.StartsWith("-r:", StringComparison.Ordinal) then
7173
let path = VirtualFileSystemPath.TryParse(o.Substring(3), InteractionContext.SolutionContext)
7274
if not path.IsEmpty then assembliesPaths.Add(path) |> ignore
7375

7476
let filesPaths = HashSet<VirtualFileSystemPath>()
75-
for file in scriptOptions.SourceFiles do
76-
let path = VirtualFileSystemPath.TryParse(file, InteractionContext.SolutionContext)
77+
for file in scriptSnapshot.SourceFiles do
78+
let path = VirtualFileSystemPath.TryParse(file.FileName, InteractionContext.SolutionContext)
7779
if not path.IsEmpty && not (path.Equals(scriptPath)) then
7880
filesPaths.Add(path) |> ignore
7981

@@ -148,7 +150,7 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
148150
locks.QueueReadLock(lifetime, "AssemblyGC after removing F# script reference", fun _ ->
149151
solution.GetComponent<AssemblyGC>().ForceGC())
150152

151-
and queueUpdateReferences (path: VirtualFileSystemPath) (newOptions: FSharpProjectOptions) =
153+
and queueUpdateReferences (path: VirtualFileSystemPath) (newSnapshot: FSharpProjectSnapshot) =
152154
locks.QueueReadLock(lifetime, "Request new F# script references", fun _ ->
153155
let oldReferences =
154156
let mutable oldReferences = Unchecked.defaultof<ScriptReferences>
@@ -161,7 +163,7 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
161163

162164
ira.FuncRun <-
163165
fun _ ->
164-
let newReferences = getScriptReferences path newOptions
166+
let newReferences = getScriptReferences path newSnapshot
165167
Interruption.Current.CheckAndThrow()
166168

167169
let getDiff oldPaths newPaths =
@@ -181,7 +183,7 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
181183

182184
ira.FuncCancelled <-
183185
// Reschedule again
184-
fun _ -> queueUpdateReferences path newOptions
186+
fun _ -> queueUpdateReferences path newSnapshot
185187

186188
ira.DoStart() |> ignore
187189
)
@@ -190,7 +192,7 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
190192
changeManager.RegisterChangeProvider(lifetime, this)
191193

192194
if not scriptOptionsProvider.SyncUpdate then
193-
scriptOptionsProvider.OptionsUpdated.Advise(lifetime, fun (path, options) ->
195+
scriptOptionsProvider.SnapshotUpdated.Advise(lifetime, fun (path, options) ->
194196
queueUpdateReferences path options
195197
)
196198

@@ -230,7 +232,7 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
230232
if scriptOptionsProvider.SyncUpdate then
231233
scriptOptionsProvider.GetFcsProject(psiModule.SourceFile)
232234
|> Option.iter (fun fcsProject ->
233-
let references = getScriptReferences path fcsProject.ProjectOptions
235+
let references = getScriptReferences path fcsProject.ProjectSnapshot
234236
updateReferences path references references.Assemblies [] changeBuilder
235237
)
236238

@@ -261,8 +263,8 @@ type FSharpScriptPsiModulesProvider(lifetime: Lifetime, solution: ISolution, cha
261263
scriptsFromProjectFiles.GetValuesSafe(path)
262264
|> Seq.tryFind (fun psiModule -> psiModule.Path = moduleToRemove.Path)
263265
|> Option.iter (fun psiModule ->
264-
match checkerService.GetCachedScriptOptions(path.FullPath) with
265-
| Some options -> checkerService.InvalidateFcsProject(options, FcsProjectInvalidationType.Remove)
266+
match checkerService.GetCachedScriptSnapshot(path.FullPath) with
267+
| Some snapshot -> checkerService.InvalidateFcsProject(snapshot, FcsProjectInvalidationType.Remove)
266268
| None -> ()
267269

268270
scriptsFromProjectFiles.RemoveValue(path, psiModule) |> ignore

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type FSharpTestHost(solution: ISolution, sourceCache: FSharpSourceCache, itemsCo
5252
psiModule.SourceFiles
5353
|> Seq.find (fun sourceFile -> sourceFile.LanguageType.Is<FSharpProjectFileType>())
5454

55-
projectProvider.GetProjectOptions(sourceFile)
55+
projectProvider.GetProjectSnapshot(sourceFile)
5656
|> Option.map (fun options ->
5757
options.OtherOptions
5858
|> Array.choose (fun o -> if o.StartsWith("-r:") then Some (o.Substring("-r:".Length)) else None)
@@ -67,7 +67,7 @@ type FSharpTestHost(solution: ISolution, sourceCache: FSharpSourceCache, itemsCo
6767

6868
let project = projectModelViewHost.GetItemById<IProject>(projectModelId)
6969
let psiModule = psiModules.GetPsiModules(project) |> Seq.exactlyOne
70-
projectProvider.GetProjectOptions(psiModule).Value
70+
projectProvider.GetProjectSnapshot(psiModule).Value
7171

7272
let dumpFcsProjectStamp (projectModelId: int) =
7373
let projectOptions = getProjectOptions projectModelId

0 commit comments

Comments
 (0)