Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ReSharper.FSharp/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,14 @@
<PsiFeaturesTestSubplatform>$(Subplatform).Psi.Features_test_Framework.Props</PsiFeaturesTestSubplatform>
<RdBackendCommonSubplatform>$(Subplatform).Rider_RdBackend.Common.Props</RdBackendCommonSubplatform>
<RiderBackendSubplatform>$(Subplatform).Rider_Rider.Backend.Props</RiderBackendSubplatform>
<UseLocalFSharpCompilerService>true</UseLocalFSharpCompilerService>
<LocalFSharpRepository>$(MSBuildThisFileDirectory)../../fsharp</LocalFSharpRepository>
</PropertyGroup>

<ItemGroup>
<PackageReference Condition="'$(UseLocalFSharpCompilerService)' == 'false'" Include="JetBrains.FSharp.Compiler.Service" />
<ProjectReference Condition="'$(UseLocalFSharpCompilerService)' == 'true'" Include="$(LocalFSharpRepository)/src/Compiler/FSharp.Compiler.Service.fsproj" />
<ProjectReference Condition="'$(UseLocalFSharpCompilerService)' == 'true'" Include="$(LocalFSharpRepository)/src/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj" />
<ProjectReference Condition="'$(UseLocalFSharpCompilerService)' == 'true'" Include="$(LocalFSharpRepository)/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Nuget.fsproj" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion ReSharper.FSharp/TypeProviders.Host.targets
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<ItemGroup>
<PackageReference Include="FSharp.Core" />
<PackageReference Include="JetBrains.FSharp.Compiler.Service" />
<PackageReference Condition="'$(UseLocalFSharpCompilerService)' == 'false'" Include="JetBrains.FSharp.Compiler.Service" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
<ItemGroup>
<PackageReference Include="FSharp.Core" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="JetBrains.FSharp.Compiler.Service" />
<PackageReference Include="JetBrains.Lifetimes" />
<PackageReference Include="JetBrains.RdFramework" />
<PackageReference Include="System.Diagnostics.Debug" />
Expand All @@ -46,4 +45,4 @@
<Import Project="ManagedProject.Generated.Targets" Condition="$(InternalBuild)" />
<Import Project="Sdk.targets" Sdk="JetBrains.Toolset.MainSolution.Sdk" Version="20200625.1.1.2" Condition="$(InternalBuild)" />
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="!$(InternalBuild)" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
<ItemGroup>
<PackageReference Include="FSharp.Core" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="JetBrains.FSharp.Compiler.Service" />
<PackageReference Include="JetBrains.Lifetimes" />
<PackageReference Include="JetBrains.RdFramework" />
</ItemGroup>
Expand All @@ -39,4 +38,4 @@
<Import Project="ManagedProject.Generated.Targets" Condition="$(InternalBuild)" />
<Import Project="Sdk.targets" Sdk="JetBrains.Toolset.MainSolution.Sdk" Version="20200625.1.1.2" Condition="$(InternalBuild)" />
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="!$(InternalBuild)" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
<ItemGroup>
<PackageReference Include="FSharp.Core" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="JetBrains.FSharp.Compiler.Service" />
<PackageReference Include="JetBrains.HabitatDetector" />
<PackageReference Include="JetBrains.Lifetimes" />
<PackageReference Include="JetBrains.RdFramework" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[<AutoOpen>]
module JetBrains.ReSharper.Plugins.FSharp.Checker.FSharpCheckerExtensions

#nowarn "57"

open System.Threading
open System.Threading.Tasks
open FSharp.Compiler.CodeAnalysis
Expand All @@ -19,13 +21,11 @@ type CheckResults =
| StillRunning of Task<(FSharpParseFileResults * FSharpCheckFileResults) option>

type FSharpChecker with
member internal x.ParseAndCheckDocument(path, source: ISourceText, options, allowStale: bool, opName) =
let version = source.GetHashCode()

member internal x.ParseAndCheckDocument(path, projectSnapshot: FSharpProjectSnapshot, allowStale: bool, opName) =
let parseAndCheckFile =
async {
let! parseResults, checkFileAnswer =
x.ParseAndCheckFileInProject(path, version, source, options, userOpName = opName)
x.ParseAndCheckFileInProject(path, projectSnapshot, userOpName = opName)

return
match checkFileAnswer with
Expand Down Expand Up @@ -61,26 +61,26 @@ type FSharpChecker with
| _ -> None

async {
match x.TryGetRecentCheckResultsForFile(path, options, source) with
match x.TryGetRecentCheckResultsForFile(path, projectSnapshot) with
| None ->
// No stale results available, wait for fresh results
return! parseAndCheckFile

| Some (parseResults, checkFileResults, cachedVersion) when allowStale && cachedVersion = int64 version ->
| Some (parseResults, checkFileResults) when allowStale ->
// Avoid queueing on the reactor thread by using the recent results
return Some (parseResults, checkFileResults)

| Some (staleParseResults, staleCheckFileResults, _) ->

| Some (staleParseResults, staleCheckFileResults) ->
match! tryGetFreshResultsWithTimeout() with
| Ready x ->
// Fresh results were ready quickly enough
return x

| StillRunning _ when allowStale ->
// Still waiting for fresh results - just use the stale ones for now
return Some (staleParseResults, staleCheckFileResults)

| StillRunning worker ->
return! Async.AwaitTask worker
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace rec JetBrains.ReSharper.Plugins.FSharp.Checker

#nowarn "57"

open System
open System.Collections.Generic
open System.IO
Expand Down Expand Up @@ -38,7 +40,7 @@ module FcsCheckerService =

type FcsProject =
{ OutputPath: VirtualFileSystemPath
ProjectOptions: FSharpProjectOptions
ProjectSnapshot: FSharpProjectSnapshot
ParsingOptions: FSharpParsingOptions
FileIndices: IDictionary<VirtualFileSystemPath, int>
ImplementationFilesWithSignatures: ISet<VirtualFileSystemPath>
Expand All @@ -53,22 +55,27 @@ type FcsProject =
tryGetValue path x.FileIndices |> Option.defaultValue -1

member x.TestDump(writer: TextWriter) =
let projectOptions = x.ProjectOptions

writer.WriteLine($"Project file: {projectOptions.ProjectFileName}")
writer.WriteLine($"Stamp: {projectOptions.Stamp}")
writer.WriteLine($"Load time: {projectOptions.LoadTime}")
let projectSnapshot = x.ProjectSnapshot
let (ProjectSnapshot.FSharpProjectIdentifier(projectFileName, _)) = projectSnapshot.Identifier

writer.WriteLine($"Project file: {projectFileName}")
writer.WriteLine($"Stamp: {projectSnapshot.Stamp}")
writer.WriteLine($"Load time: {projectSnapshot.LoadTime}")

writer.WriteLine("Source files:")
for sourceFile in projectOptions.SourceFiles do
for sourceFile in projectSnapshot.SourceFiles do
writer.WriteLine($" {sourceFile}")

writer.WriteLine("Other options:")
for option in projectOptions.OtherOptions do
for option in projectSnapshot.OtherOptions do
writer.WriteLine($" {option}")


writer.WriteLine("References on disk:")
for r in projectSnapshot.ReferencesOnDisk do
writer.WriteLine($" %s{r.Path}")

writer.WriteLine("Referenced projects:")
for referencedProject in projectOptions.ReferencedProjects do
for referencedProject in projectSnapshot.ReferencedProjects do
writer.WriteLine($" {referencedProject.OutputFile}")

writer.WriteLine()
Expand All @@ -88,25 +95,29 @@ 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<FSharpOptions> settingsStore name
settingsStoreLive.GetValueProperty(lifetime, setting, null)
let getSettingProperty name =
let setting = SettingsUtil.getEntry<FSharpOptions> settingsStore name
settingsStoreLive.GetValueProperty(lifetime, setting, null)

// Hard coded for now.
let useTransparentCompiler = true
// (getSettingProperty "UseTransparentCompiler").Value

let checker =
Environment.SetEnvironmentVariable("FCS_CheckFileInProjectCacheSize", "20")
let skipImpl = getSettingProperty "SkipImplementationAnalysis"
let analyzerProjectReferencesInParallel = getSettingProperty "ParallelProjectReferencesAnalysis"

lazy
let checker =
FSharpChecker.Create(projectCacheSize = 200,
keepAllBackgroundResolutions = false,
keepAllBackgroundSymbolUses = false,
enablePartialTypeChecking = skipImpl.Value,
parallelReferenceResolution = analyzerProjectReferencesInParallel.Value)
parallelReferenceResolution = analyzerProjectReferencesInParallel.Value,
useTransparentCompiler = useTransparentCompiler)

checker

Expand Down Expand Up @@ -156,26 +167,31 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
| Some(parseResults, checkResults) -> Some({ ParseResults = parseResults; CheckResults = checkResults })
| _ ->



ProhibitTypeCheckCookie.AssertTypeCheckIsAllowed()
locks.AssertReadAccessAllowed()
x.AssertFcsAccessThread()

let psiModule = sourceFile.PsiModule
// check if is active ...
if useTransparentCompiler then ()
match x.FcsProjectProvider.GetFcsProject(psiModule) with
| None -> None
| Some fcsProject ->

let options = fcsProject.ProjectOptions
if not (fcsProject.IsKnownFile(sourceFile)) && not options.UseScriptResolutionRules then None else
let snapshot = fcsProject.ProjectSnapshot
if not (fcsProject.IsKnownFile(sourceFile)) && not snapshot.UseScriptResolutionRules then None else

x.FcsProjectProvider.PrepareAssemblyShim(psiModule)

// TODO: should this be the non virtual path?
let path = sourceFile.GetLocation().FullPath
let source = FcsCheckerService.getSourceText sourceFile.Document
logger.Trace("ParseAndCheckFile: start {0}, {1}", path, opName)

// todo: don't cancel the computation when file didn't change
match x.Checker.ParseAndCheckDocument(path, source, options, allowStaleResults, opName).RunAsTask() with
match x.Checker.ParseAndCheckDocument(path, snapshot, allowStaleResults, opName).RunAsTask() with
| Some (parseResults, checkResults) ->
logger.Trace("ParseAndCheckFile: finish {0}, {1}", path, opName)
Some { ParseResults = parseResults; CheckResults = checkResults }
Expand All @@ -190,37 +206,38 @@ type FcsCheckerService(lifetime: Lifetime, logger: ILogger, onSolutionCloseNotif
new PinTypeCheckResultsCookie(sourceFile, parseAndCheckResults.ParseResults, parseAndCheckResults.CheckResults, prohibitTypeCheck) :> IDisposable
| _ -> { new IDisposable with member this.Dispose() = () }

member x.TryGetStaleCheckResults([<NotNull>] file: IPsiSourceFile, opName) =
match x.FcsProjectProvider.GetProjectOptions(file) with
member x.TryGetStaleCheckResults([<NotNull>] file: IPsiSourceFile, opName) : FSharpCheckFileResults option =
match x.FcsProjectProvider.GetProjectSnapshot(file) with
| None -> None
| Some options ->
| Some snapshot ->

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

match x.Checker.TryGetRecentCheckResultsForFile(path, options) with
| Some (_, checkResults, _) ->
match x.Checker.TryGetRecentCheckResultsForFile(path, snapshot) with
| Some (_, checkResults) ->
logger.Trace("TryGetStaleCheckResults: finish {0}, {1}", path, opName)
Some checkResults

| _ ->
logger.Trace("TryGetStaleCheckResults: fail {0}, {1}", path, opName)
None

member x.GetCachedScriptOptions(path) =
member x.GetCachedScriptSnapshot(path) =
if checker.IsValueCreated then
checker.Value.GetCachedScriptOptions(path)
checker.Value.GetCachedScriptSnapshot(path)
else None

member x.InvalidateFcsProject(projectOptions: FSharpProjectOptions, invalidationType: FcsProjectInvalidationType) =
member x.InvalidateFcsProject(projectSnapshot: FSharpProjectSnapshot, invalidationType: FcsProjectInvalidationType) =
if checker.IsValueCreated then
match invalidationType with
| FcsProjectInvalidationType.Invalidate ->
logger.Trace("Remove FcsProject in FCS: {0}", projectOptions.ProjectFileName)
checker.Value.ClearCache(Seq.singleton projectOptions)
logger.Trace("Remove FcsProject in FCS: {0}", projectSnapshot.ProjectFileName)
checker.Value.ClearCache(Seq.singleton projectSnapshot.Identifier)
| FcsProjectInvalidationType.Remove ->
logger.Trace("Invalidate FcsProject in FCS: {0}", projectOptions.ProjectFileName)
checker.Value.InvalidateConfiguration(projectOptions)
logger.Trace("Invalidate FcsProject in FCS: {0}", projectSnapshot.ProjectFileName)
// See: https://github.com/dotnet/fsharp/pull/16718
checker.Value.InvalidateConfiguration(projectSnapshot)

/// 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) =
Expand Down Expand Up @@ -263,8 +280,8 @@ type IFcsProjectProvider =
abstract GetFcsProject: psiModule: IPsiModule -> FcsProject option
abstract GetPsiModule: outputPath: VirtualFileSystemPath -> IPsiModule option

abstract GetProjectOptions: sourceFile: IPsiSourceFile -> FSharpProjectOptions option
abstract GetProjectOptions: psiModule: IPsiModule -> FSharpProjectOptions option
abstract GetProjectSnapshot: sourceFile: IPsiSourceFile -> FSharpProjectSnapshot option
abstract GetProjectSnapshot: psiModule: IPsiModule -> FSharpProjectSnapshot option

abstract GetFileIndex: IPsiSourceFile -> int
abstract GetParsingOptions: sourceFile: IPsiSourceFile -> FSharpParsingOptions
Expand All @@ -289,9 +306,10 @@ type IFcsProjectProvider =

type IScriptFcsProjectProvider =
abstract GetFcsProject: IPsiSourceFile -> FcsProject option
abstract GetScriptOptions: IPsiSourceFile -> FSharpProjectOptions option
abstract GetScriptOptions: VirtualFileSystemPath * string -> FSharpProjectOptions option
abstract OptionsUpdated: Signal<VirtualFileSystemPath * FSharpProjectOptions>
abstract GetScriptSnapshot: IPsiSourceFile -> FSharpProjectSnapshot option
// TODO: unused?
// abstract GetScriptOptions: VirtualFileSystemPath * string -> FSharpProjectOptions option
abstract SnapshotUpdated: Signal<VirtualFileSystemPath * FSharpProjectSnapshot>
abstract SyncUpdate: bool


Expand Down
Loading