diff --git a/docs/builder-caches.md b/docs/builder-caches.md new file mode 100644 index 00000000000..90d7e2e471d --- /dev/null +++ b/docs/builder-caches.md @@ -0,0 +1,13 @@ +--- +title: IncrementalBuilder caches +category: Language Service Internals +categoryindex: 300 +index: 1300 +--- +# IncrementalBuilder SyntaxTree cache + +Incremental builder keeps in a cache at most one `ParsedInput` for each file it parses. +This behavior can be toggled with `useSyntaxTreeCache` parameter. + +Memory impact of this feature can be in range of tens of MB for larger solutions. This can be inspected in memory profilng tools by searching for `ParsedInput` instances. +When partial checking is enabled, implementation files backed by signature will not be parsed or cached, as expected. diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 57562813eb9..bfc2d69c759 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -7,7 +7,6 @@ open System.Collections.Generic open System.Collections.Immutable open System.Diagnostics open System.IO -open System.IO.Compression open System.Threading open Internal.Utilities.Library open Internal.Utilities.Collections @@ -18,7 +17,6 @@ open FSharp.Compiler.CheckBasics open FSharp.Compiler.CheckDeclarations open FSharp.Compiler.CompilerConfig open FSharp.Compiler.CompilerDiagnostics -open FSharp.Compiler.CompilerGlobalState open FSharp.Compiler.CompilerImports open FSharp.Compiler.CompilerOptions open FSharp.Compiler.CreateILModule @@ -30,7 +28,6 @@ open FSharp.Compiler.IO open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.NameResolution open FSharp.Compiler.ParseAndCheckInputs -open FSharp.Compiler.Syntax.PrettyNaming open FSharp.Compiler.ScriptClosure open FSharp.Compiler.Syntax open FSharp.Compiler.TcGlobals @@ -41,14 +38,13 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.BuildGraph - [] module internal IncrementalBuild = let mutable injectCancellationFault = false let LocallyInjectCancellationFault() = injectCancellationFault <- true - { new IDisposable with member _.Dispose() = injectCancellationFault <- false } + { new IDisposable with member _.Dispose() = injectCancellationFault <- false } // Record the most recent IncrementalBuilder events, so we can more easily unit test/debug the // 'incremental' behavior of the product. @@ -97,9 +93,16 @@ module IncrementalBuilderEventTesting = module Tc = CheckExpressions +type internal FSharpFile = { + Range: range + Source: FSharpSource + Flags: bool * bool + } + // This module is only here to contain the SyntaxTree type as to avoid ambiguity with the module FSharp.Compiler.Syntax. [] module IncrementalBuildSyntaxTree = + open System.Runtime.CompilerServices /// Information needed to lazily parse a file to get a ParsedInput. Internally uses a weak cache. [] @@ -107,78 +110,82 @@ module IncrementalBuildSyntaxTree = tcConfig: TcConfig, fileParsed: Event, lexResourceManager, - sourceRange: range, - source: FSharpSource, - isLastCompiland + file: FSharpFile, + useCache ) = - let fileName = source.FilePath - let mutable weakCache: WeakReference<_> option = None - - let parse(sigNameOpt: QualifiedNameOfFile option) = + static let cache = ConditionalWeakTable() + + let fileName = file.Source.FilePath + let sourceRange = file.Range + let source = file.Source + let isLastCompiland = file.Flags + + let isImplFile = FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) + + let parsedImplFileStub sigName = + ParsedInput.ImplFile( + ParsedImplFileInput( + fileName, + false, + sigName, + [], + [], + [], + isLastCompiland, + { ConditionalDirectives = []; CodeComments = [] }, + Set.empty + ) + ), sourceRange, fileName, [||] + let parse _ = let diagnosticsLogger = CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions) // Return the disposable object that cleans up use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse) - - try - IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) - let canSkip = sigNameOpt.IsSome && FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) - use act = - Activity.start "IncrementalBuildSyntaxTree.parse" - [| - Activity.Tags.fileName, source.FilePath - "buildPhase", BuildPhase.Parse.ToString() - "canSkip", canSkip.ToString() - |] - let input = - if canSkip then - ParsedInput.ImplFile( - ParsedImplFileInput( - fileName, - false, - sigNameOpt.Value, - [], - [], - [], - isLastCompiland, - { ConditionalDirectives = []; CodeComments = [] }, - Set.empty - ) - ) - else - use text = source.GetTextContainer() - match text with - | TextContainer.Stream(stream) -> - ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) - | TextContainer.SourceText(sourceText) -> - ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText) - | TextContainer.OnDisk -> - ParseOneInputFile(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, true) + try + use text = source.GetTextContainer() + let input = + match text with + | TextContainer.Stream(stream) -> + ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) + | TextContainer.SourceText(sourceText) -> + ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText) + | TextContainer.OnDisk -> + ParseOneInputFile(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, true) fileParsed.Trigger fileName - let res = input, sourceRange, fileName, diagnosticsLogger.GetDiagnostics() - // If we do not skip parsing the file, then we can cache the real result. - if not canSkip then - weakCache <- Some(WeakReference<_>(res)) - res + input, sourceRange, fileName, diagnosticsLogger.GetDiagnostics() + with exn -> let msg = sprintf "unexpected failure in SyntaxTree.parse\nerror = %s" (exn.ToString()) System.Diagnostics.Debug.Assert(false, msg) failwith msg - /// Parse the given file and return the given input. - member _.Parse sigNameOpt = - match weakCache with - | Some weakCache -> - match weakCache.TryGetTarget() with - | true, res -> res - | _ -> parse sigNameOpt - | _ -> parse sigNameOpt + let parseOrSkip sigNameOpt = + IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) + use _ = + Activity.start "IncrementalBuildSyntaxTree.parseOrSkip" + [| + Activity.Tags.fileName, fileName + "buildPhase", BuildPhase.Parse.ToString() + "canSkip", (isImplFile && sigNameOpt |> Option.isSome).ToString() + |] + + match sigNameOpt with + | Some sigName when isImplFile -> parsedImplFileStub sigName + | _ when useCache -> + match cache.TryGetValue file with + | true, result -> + Activity.addEvent Activity.Events.cacheHit + result + | _ -> cache.GetValue(file, parse) + | _ -> parse file - member _.Invalidate() = - SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, source, isLastCompiland) + /// Parse the given file and return the given input. + member _.Parse(sigNameOpt) = parseOrSkip sigNameOpt + + static member Invalidate(source) = cache.Remove(source) |> ignore member _.FileName = fileName @@ -352,11 +359,6 @@ type BoundModel private (tcConfig: TcConfig, // If partial checking is enabled and we have a backing sig file, then use the partial state. The partial state contains the sig state. if tcInfoNode.HasFull && enablePartialTypeChecking && hasSig then - // Always invalidate the syntax tree cache. - let newSyntaxTreeOpt = - syntaxTreeOpt - |> Option.map (fun x -> x.Invalidate()) - let newTcInfoStateOpt = match tcInfoNode with | TcInfoNode(_, fullGraphNode) -> @@ -374,7 +376,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked, fileChecked, prevTcInfo, - newSyntaxTreeOpt, + syntaxTreeOpt, newTcInfoStateOpt) else this @@ -736,11 +738,6 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, generate [] module IncrementalBuilderHelpers = - /// Get the timestamp of the given file name. - let StampFileNameTask (cache: TimeStampCache) (_m: range, source: FSharpSource, _isLastCompiland) notifiedTime = - notifiedTime - |> Option.defaultWith (fun () -> cache.GetFileTimeStamp source.FilePath) - /// Timestamps of referenced assemblies are taken from the file's timestamp. let StampReferencedAssemblyTask (cache: TimeStampCache) (_ref, timeStamper) = timeStamper cache @@ -949,8 +946,7 @@ module IncrementalBuilderHelpers = return ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, finalBoundModelWithErrors } - let GetSyntaxTree tcConfig fileParsed lexResourceManager (sourceRange: range, source, isLastCompiland) = - SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, source, isLastCompiland) + let GetSyntaxTree tcConfig fileParsed lexResourceManager file useCache = SyntaxTree(tcConfig, fileParsed, lexResourceManager, file, useCache) [] type IncrementalBuilderInitialState = @@ -962,7 +958,7 @@ type IncrementalBuilderInitialState = outfile: string assemblyName: string lexResourceManager: Lexhelp.LexResourceManager - fileNames: ImmutableArray + fileNames: ImmutableArray enablePartialTypeChecking: bool beforeFileChecked: Event fileChecked: Event @@ -975,26 +971,30 @@ type IncrementalBuilderInitialState = defaultTimeStamp: DateTime mutable isImportsInvalidated: bool useChangeNotifications: bool + useSyntaxTreeCache: bool } - static member Create( - initialBoundModel: BoundModel, - tcGlobals, - nonFrameworkAssemblyInputs, - tcConfig: TcConfig, - outfile, - assemblyName, - lexResourceManager, - sourceFiles, - enablePartialTypeChecking, - beforeFileChecked: Event, - fileChecked: Event, + static member Create + ( + initialBoundModel: BoundModel, + tcGlobals, + nonFrameworkAssemblyInputs, + tcConfig: TcConfig, + outfile, + assemblyName, + lexResourceManager, + sourceFiles, + enablePartialTypeChecking, + beforeFileChecked: Event, + fileChecked: Event, #if !NO_TYPEPROVIDERS - importsInvalidatedByTypeProvider: Event, + importsInvalidatedByTypeProvider: Event, #endif - allDependencies, - defaultTimeStamp: DateTime, - useChangeNotifications: bool) = + allDependencies, + defaultTimeStamp: DateTime, + useChangeNotifications: bool, + useSyntaxTreeCache + ) = let initialState = { @@ -1018,6 +1018,7 @@ type IncrementalBuilderInitialState = defaultTimeStamp = defaultTimeStamp isImportsInvalidated = false useChangeNotifications = useChangeNotifications + useSyntaxTreeCache = useSyntaxTreeCache } #if !NO_TYPEPROVIDERS importsInvalidatedByTypeProvider.Publish.Add(fun () -> initialState.isImportsInvalidated <- true) @@ -1043,12 +1044,12 @@ type IncrementalBuilderState = module IncrementalBuilderStateHelpers = let createBoundModelGraphNode (initialState: IncrementalBuilderInitialState) initialBoundModel (boundModels: ImmutableArray>.Builder) i = - let fileInfo = initialState.fileNames[i] + let file = initialState.fileNames[i] let prevBoundModelGraphNode = match i with | 0 (* first file *) -> initialBoundModel | _ -> boundModels[i - 1] - let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager fileInfo + let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager file initialState.useSyntaxTreeCache GraphNode(node { let! prevBoundModel = prevBoundModelGraphNode.GetOrComputeValue() return! TypeCheckTask initialState.enablePartialTypeChecking prevBoundModel syntaxTree @@ -1075,19 +1076,30 @@ module IncrementalBuilderStateHelpers = return result }) - and computeStampedFileName (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) slot fileInfo = - let currentStamp = state.stampedFileNames[slot] - let notifiedStamp = if initialState.useChangeNotifications then Some state.notifiedStampedFileNames[slot] else None - let stamp = StampFileNameTask cache fileInfo notifiedStamp + and computeStampedFileNames (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) = + + let getStamp slot = + if initialState.useChangeNotifications then + state.notifiedStampedFileNames[slot] + else + cache.GetFileTimeStamp initialState.fileNames[slot].Source.FilePath + + let modified = + [ for i, file in initialState.fileNames |> Seq.indexed do + let stamp = getStamp i + if state.stampedFileNames[i] <> stamp then + i, stamp, file ] - if currentStamp <> stamp then + for _, _, f in modified do SyntaxTree.Invalidate f + + let computeStampedFileName state (slot, stamp, _) = match state.boundModels[slot].TryPeekValue() with // This prevents an implementation file that has a backing signature file from invalidating the rest of the build. | ValueSome(boundModel) when initialState.enablePartialTypeChecking && boundModel.BackingSignature.IsSome -> let newBoundModel = boundModel.ClearTcInfoExtras() { state with - boundModels = state.boundModels.RemoveAt(slot).Insert(slot, GraphNode(node.Return newBoundModel)) - stampedFileNames = state.stampedFileNames.SetItem(slot, StampFileNameTask cache fileInfo notifiedStamp) + boundModels = state.boundModels.SetItem(slot, GraphNode(node.Return newBoundModel)) + stampedFileNames = state.stampedFileNames.SetItem(slot, stamp) } | _ -> @@ -1096,12 +1108,11 @@ module IncrementalBuilderStateHelpers = let boundModels = state.boundModels.ToBuilder() // Invalidate the file and all files below it. - for j = 0 to stampedFileNames.Count - slot - 1 do - let notifiedStamp = if initialState.useChangeNotifications then Some state.notifiedStampedFileNames.[slot + j] else None - let stamp = StampFileNameTask cache initialState.fileNames[slot + j] notifiedStamp - stampedFileNames[slot + j] <- stamp - logicalStampedFileNames[slot + j] <- stamp - boundModels[slot + j] <- createBoundModelGraphNode initialState state.initialBoundModel boundModels (slot + j) + for j = slot to stampedFileNames.Count - 1 do + let stamp = getStamp j + stampedFileNames[j] <- stamp + logicalStampedFileNames[j] <- stamp + boundModels[j] <- createBoundModelGraphNode initialState state.initialBoundModel boundModels j { state with // Something changed, the finalized view of the project must be invalidated. @@ -1111,17 +1122,9 @@ module IncrementalBuilderStateHelpers = logicalStampedFileNames = logicalStampedFileNames.ToImmutable() boundModels = boundModels.ToImmutable() } - else - state - and computeStampedFileNames (initialState: IncrementalBuilderInitialState) state (cache: TimeStampCache) = - let mutable i = 0 - (state, initialState.fileNames) - ||> ImmutableArray.fold (fun state fileInfo -> - let newState = computeStampedFileName initialState state cache i fileInfo - i <- i + 1 - newState - ) + (state, modified) + ||> List.fold computeStampedFileName and computeStampedReferencedAssemblies (initialState: IncrementalBuilderInitialState) state canTriggerInvalidation (cache: TimeStampCache) = let stampedReferencedAssemblies = state.stampedReferencedAssemblies.ToBuilder() @@ -1406,10 +1409,10 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member _.TryGetSlotOfFileName(fileName: string) = // Get the slot of the given file and force it to build. - let CompareFileNames (_, f2: FSharpSource, _) = + let CompareFileNames f = let result = - String.Compare(fileName, f2.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 - || String.Compare(FileSystem.GetFullPathShim fileName, FileSystem.GetFullPathShim f2.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 + String.Compare(fileName, f.Source.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 + || String.Compare(FileSystem.GetFullPathShim fileName, FileSystem.GetFullPathShim f.Source.FilePath, StringComparison.CurrentCultureIgnoreCase)=0 result match fileNames |> ImmutableArray.tryFindIndex CompareFileNames with | Some slot -> Some slot @@ -1427,9 +1430,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member builder.GetParseResultsForFile fileName = let slotOfFile = builder.GetSlotOfFileName fileName - let fileInfo = fileNames[slotOfFile] - // re-parse on demand instead of retaining - let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager fileInfo + let file = initialState.fileNames[slotOfFile] + let syntaxTree = GetSyntaxTree initialState.tcConfig initialState.fileParsed initialState.lexResourceManager file initialState.useSyntaxTreeCache syntaxTree.Parse None member builder.NotifyFileChanged(fileName, timeStamp) = @@ -1441,7 +1443,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc setCurrentState newState cache ct } - member _.SourceFiles = fileNames |> Seq.map (fun (_, f, _) -> f.FilePath) |> List.ofSeq + member _.SourceFiles = fileNames |> Seq.map (fun f -> f.Source.FilePath) |> List.ofSeq /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also /// creates an incremental builder used by the command line compiler. @@ -1467,7 +1469,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) = let useSimpleResolutionSwitch = "--simpleresolution" @@ -1678,16 +1681,16 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let getFSharpSource fileName = getSource |> Option.map(fun getSource -> - let getTimeStamp() = DateTime.UtcNow + let timeStamp = DateTime.UtcNow + let getTimeStamp = fun () -> timeStamp let getSourceText() = getSource fileName FSharpSource.Create(fileName, getTimeStamp, getSourceText)) |> Option.defaultWith(fun () -> FSharpSource.CreateFromFile(fileName)) let sourceFiles = sourceFiles - |> List.map (fun (m, fileName, isLastCompiland) -> - (m, getFSharpSource(fileName), isLastCompiland) - ) + |> List.map (fun (m, fileName, isLastCompiland) -> + { Range = m; Source = getFSharpSource fileName; Flags = isLastCompiland } ) let initialState = IncrementalBuilderInitialState.Create( @@ -1707,7 +1710,9 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc #endif allDependencies, defaultTimeStamp, - useChangeNotifications) + useChangeNotifications, + useSyntaxTreeCache + ) let builder = IncrementalBuilder(initialState, IncrementalBuilderState.Create(initialState)) return Some builder diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi index ee9b06380eb..a1c5fa70624 100644 --- a/src/Compiler/Service/IncrementalBuild.fsi +++ b/src/Compiler/Service/IncrementalBuild.fsi @@ -269,7 +269,8 @@ type internal IncrementalBuilder = parallelReferenceResolution: ParallelReferenceResolution * captureIdentifiersWhenParsing: bool * getSource: (string -> ISourceText option) option * - useChangeNotifications: bool -> + useChangeNotifications: bool * + useSyntaxTreeCache: bool -> NodeCode /// Generalized Incremental Builder. This is exposed only for unit testing purposes. diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 65537dd67b8..8b68495389b 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -195,7 +195,8 @@ type BackgroundCompiler parallelReferenceResolution, captureIdentifiersWhenParsing, getSource: (string -> ISourceText option) option, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) as self = let beforeFileChecked = Event() @@ -329,7 +330,8 @@ type BackgroundCompiler parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) match builderOpt with @@ -636,9 +638,6 @@ type BackgroundCompiler ) = node { - if useChangeNotifications then - do! builder.NotifyFileChanged(fileName, DateTime.UtcNow) - match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with | Some (_, results) -> return FSharpCheckFileAnswer.Succeeded results | _ -> @@ -1263,7 +1262,8 @@ type FSharpChecker parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) = let backgroundCompiler = @@ -1280,7 +1280,8 @@ type FSharpChecker parallelReferenceResolution, captureIdentifiersWhenParsing, getSource, - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) static let globalInstance = lazy FSharpChecker.Create() @@ -1324,7 +1325,8 @@ type FSharpChecker ?enablePartialTypeChecking, ?parallelReferenceResolution: bool, ?captureIdentifiersWhenParsing: bool, - ?documentSource: DocumentSource + ?documentSource: DocumentSource, + ?useSyntaxTreeCache: bool ) = use _ = Activity.startNoTags "FSharpChecker.Create" @@ -1352,6 +1354,8 @@ type FSharpChecker | Some (DocumentSource.Custom _) -> true | _ -> false + let useSyntaxTreeCache = defaultArg useSyntaxTreeCache true + if keepAssemblyContents && enablePartialTypeChecking then invalidArg "enablePartialTypeChecking" "'keepAssemblyContents' and 'enablePartialTypeChecking' cannot be both enabled." @@ -1372,7 +1376,8 @@ type FSharpChecker (match documentSource with | Some (DocumentSource.Custom f) -> Some f | _ -> None), - useChangeNotifications + useChangeNotifications, + useSyntaxTreeCache ) member _.ReferenceResolver = legacyReferenceResolver diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index 52a355c9162..5d482b3cbed 100644 --- a/src/Compiler/Service/service.fsi +++ b/src/Compiler/Service/service.fsi @@ -41,6 +41,7 @@ type public FSharpChecker = /// Indicates whether to resolve references in parallel. /// When set to true we create a set of all identifiers for each parsed file which can be used to speed up finding references. /// Default: FileSystem. You can use Custom source to provide a function that will return the source for a given file path instead of reading it from the file system. Note that with this option the FSharpChecker will also not monitor the file system for file changes. It will expect to be notified of changes via the NotifyFileChanged method. + /// Default: true. Indicates whether to keep parsing results in a cache. static member Create: ?projectCacheSize: int * ?keepAssemblyContents: bool * @@ -53,7 +54,8 @@ type public FSharpChecker = ?enablePartialTypeChecking: bool * ?parallelReferenceResolution: bool * ?captureIdentifiersWhenParsing: bool * - [] ?documentSource: DocumentSource -> + [] ?documentSource: DocumentSource * + [] ?useSyntaxTreeCache: bool -> FSharpChecker /// @@ -383,7 +385,6 @@ type public FSharpChecker = member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients: unit -> unit /// Notify the checker that given file has changed. This needs to be used when checker is created with documentSource = Custom. - /// Although it is not mandatory when the changed file is the next thing requested to be checked. [] member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs index a5f8000cfa0..6305ce77e08 100644 --- a/src/Compiler/Utilities/Activity.fs +++ b/src/Compiler/Utilities/Activity.fs @@ -10,6 +10,8 @@ open System.Text [] module internal Activity = + let FscSourceName = "fsc" + module Tags = let fileName = "fileName" let project = "project" @@ -40,7 +42,10 @@ module internal Activity = outputDllFile |] - let private activitySourceName = "fsc" + module Events = + let cacheHit = "cacheHit" + + let private activitySourceName = FscSourceName let private profiledSourceName = "fsc_with_env_stats" type System.Diagnostics.Activity with @@ -75,6 +80,10 @@ module internal Activity = let startNoTags (name: string) : IDisposable = activitySource.StartActivity(name) + let addEvent name = + if Activity.Current <> null && Activity.Current.Source = activitySource then + Activity.Current.AddEvent(ActivityEvent(name)) |> ignore + module Profiling = module Tags = diff --git a/src/Compiler/Utilities/Activity.fsi b/src/Compiler/Utilities/Activity.fsi index 0f9647a4ecc..96d3844ea4f 100644 --- a/src/Compiler/Utilities/Activity.fsi +++ b/src/Compiler/Utilities/Activity.fsi @@ -9,6 +9,8 @@ open System [] module internal Activity = + val FscSourceName: string + module Tags = val fileName: string val qualifiedNameOfFile: string @@ -17,10 +19,15 @@ module internal Activity = val length: string val cache: string + module Events = + val cacheHit: string + val startNoTags: name: string -> IDisposable val start: name: string -> tags: (string * string) seq -> IDisposable + val addEvent: name: string -> unit + module Profiling = val startAndMeasureEnvironmentStats: name: string -> IDisposable val addConsoleListener: unit -> IDisposable diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs index 6b5775f23e7..ce7820ddf4e 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs @@ -2,6 +2,7 @@ open System open System.IO +open System.Diagnostics open Xunit @@ -10,6 +11,22 @@ open FSharp.Test.ProjectGeneration.Internal open FSharp.Compiler.Text open FSharp.Compiler.CodeAnalysis +module FcsDiagnostics = FSharp.Compiler.Diagnostics.Activity + +let expectCacheHits n = + let events = ResizeArray() + let listener = + new ActivityListener( + ShouldListenTo = (fun s -> s.Name = FcsDiagnostics.FscSourceName), + Sample = (fun _ -> ActivitySamplingResult.AllData), + ActivityStopped = (fun a -> events.AddRange a.Events) + ) + ActivitySource.AddActivityListener listener + { new IDisposable with + member this.Dispose() = + listener.Dispose() + Assert.Equal(n, events |> Seq.filter (fun e -> e.Name = FcsDiagnostics.Events.cacheHit) |> Seq.length) } + let makeTestProject () = SyntheticProject.Create( sourceFile "First" [], @@ -132,3 +149,62 @@ let ``Using getSource and notifications instead of filesystem`` () = checkFile middle expectSignatureChanged checkFile last expectSignatureChanged } + +[] +let ``Using getSource and notifications instead of filesystem with parse caching`` () = + + let size = 20 + + let project = + { SyntheticProject.Create() with + SourceFiles = [ + sourceFile $"File%03d{0}" [] + for i in 1..size do + sourceFile $"File%03d{i}" [$"File%03d{i-1}"] + ] + } + + let first = "File001" + let middle = $"File%03d{size / 2}" + let last = $"File%03d{size}" + + use _ = expectCacheHits 28 + ProjectWorkflowBuilder(project, useGetSource = true, useChangeNotifications = true, useSyntaxTreeCache = true) { + updateFile first updatePublicSurface + checkFile first expectSignatureChanged + checkFile last expectSignatureChanged + updateFile middle updatePublicSurface + checkFile last expectSignatureChanged + addFileAbove middle (sourceFile "addedFile" [first]) + updateFile middle (addDependency "addedFile") + checkFile middle expectSignatureChanged + checkFile last expectSignatureChanged + } + +[] +let ``Edit file, check it, then check dependent file with parse caching`` () = + use _ = expectCacheHits 1 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) { + updateFile "First" breakDependentFiles + checkFile "First" expectSignatureChanged + saveFile "First" + checkFile "Second" expectErrors + } + +[] +let ``Edit file, don't check it, check dependent file with parse caching `` () = + use _ = expectCacheHits 1 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = true) { + updateFile "First" breakDependentFiles + saveFile "First" + checkFile "Second" expectErrors + } + +[] +let ``Parse cache not used when not enabled`` () = + use _ = expectCacheHits 0 + ProjectWorkflowBuilder(makeTestProject(), useSyntaxTreeCache = false) { + updateFile "First" breakDependentFiles + saveFile "First" + checkFile "Second" expectErrors + } \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 615dddacdf9..98973518922 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols. FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString() FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles() -FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], 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.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], 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.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance() FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 615dddacdf9..98973518922 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2031,7 +2031,7 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols. FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString() FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles() -FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], 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.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], 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.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance() FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index cf5fae95066..7d789d00f4a 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -502,7 +502,8 @@ type ProjectWorkflowBuilder ?initialContext, ?checker: FSharpChecker, ?useGetSource, - ?useChangeNotifications + ?useChangeNotifications, + ?useSyntaxTreeCache ) = let useGetSource = defaultArg useGetSource false @@ -533,7 +534,8 @@ type ProjectWorkflowBuilder enableBackgroundItemKeyStoreAndSemanticClassification = true, enablePartialTypeChecking = true, captureIdentifiersWhenParsing = true, - documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem) + documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem), + useSyntaxTreeCache = defaultArg useSyntaxTreeCache false )) let mapProjectAsync f workflow = diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index af946778b69..da310df50bf 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -207,7 +207,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) Advanced diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 821a0ab8aad..fc45d4d7206 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -122,6 +122,9 @@ type internal FSharpWorkspaceServiceFactory let enableLiveBuffers = getOption (fun options -> options.Advanced.IsLiveBuffersEnabled) false + let useSyntaxTreeCache = + getOption (fun options -> options.LanguageServicePerformance.UseSyntaxTreeCache) LanguageServicePerformanceOptions.Default.UseSyntaxTreeCache + let checker = FSharpChecker.Create( projectCacheSize = 5000, // We do not care how big the cache is. VS will actually tell FCS to clear caches, so this is fine. @@ -133,7 +136,8 @@ type internal FSharpWorkspaceServiceFactory enablePartialTypeChecking = true, parallelReferenceResolution = enableParallelReferenceResolution, captureIdentifiersWhenParsing = true, - documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem)) + documentSource = (if enableLiveBuffers then DocumentSource.Custom getSource else DocumentSource.FileSystem), + useSyntaxTreeCache = useSyntaxTreeCache) if enableLiveBuffers then workspace.WorkspaceChanged.Add(fun args -> diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs index 78f751999eb..6edfcc6cc1d 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs @@ -64,13 +64,15 @@ type LanguageServicePerformanceOptions = AllowStaleCompletionResults: bool TimeUntilStaleCompletion: int EnableParallelReferenceResolution: bool - EnableFastFindReferences: bool } + EnableFastFindReferences: bool + UseSyntaxTreeCache: bool } static member Default = { EnableInMemoryCrossProjectReferences = true AllowStaleCompletionResults = true TimeUntilStaleCompletion = 2000 // In ms, so this is 2 seconds EnableParallelReferenceResolution = false - EnableFastFindReferences = FSharpExperimentalFeaturesEnabledAutomatically } + EnableFastFindReferences = FSharpExperimentalFeaturesEnabledAutomatically + UseSyntaxTreeCache = FSharpExperimentalFeaturesEnabledAutomatically } [] type AdvancedOptions = diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 271152415d1..919b27ecb3e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index a264f044ed3..f43d8d69260 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 5c4e44f80c5..c63cb934417 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index ba1cbf9f0bf..eb7ecbe01b5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 3a287f0f36a..a67aed36350 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 6b5448db356..faf7498c3b5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 20cac30b405..d4d2cbceedb 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index aed9ab9c6f9..ed6fde565ff 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index b86e03bc023..77b968844e4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 4b491e1f465..a6d553a4876 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 75838b42f8c..7e5d5661fc2 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index d664fbf723c..fdc3d9f27be 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 0ab59331fa4..5c6f726e41c 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -159,7 +159,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) F# Project and Caching Performance Options; Enable in-memory cross project references; IntelliSense Performance Options; @@ -168,7 +168,7 @@ Time until stale results are used (in milliseconds); Parallelization (requires restart); Enable parallel type checking with signature files; Enable parallel reference resolution; -Enable fast find references & rename (experimental) +Enable fast find references & rename (experimental);Cache parsing results (experimental) diff --git a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml index b61f20c47f2..0a14570aaaf 100644 --- a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml +++ b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml @@ -23,6 +23,9 @@ IsChecked="{Binding EnableInMemoryCrossProjectReferences}" Content="{x:Static local:Strings.Enable_in_memory_cross_project_references}" ToolTip="{x:Static local:Strings.Tooltip_in_memory_cross_project_references}"/> + diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs index 8e3e92323e1..f983f08de3b 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs +++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs @@ -446,5 +446,14 @@ public static string Unused_opens_code_fix { return ResourceManager.GetString("Unused_opens_code_fix", resourceCulture); } } + + /// + /// Looks up a localized string similar to Cache parsing results (experimental). + /// + public static string Use_syntax_tree_cache { + get { + return ResourceManager.GetString("Use_syntax_tree_cache", resourceCulture); + } + } } } diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx index e97f18d0ecc..06637b5c147 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.resx +++ b/vsintegration/src/FSharp.UIResources/Strings.resx @@ -246,4 +246,7 @@ Live Buffers (experimental) + + Cache parsing results (experimental) + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf index 9289f9407c7..d4e489701e2 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf @@ -217,6 +217,11 @@ Navrhovat názvy pro nerozpoznané identifikátory + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf index d14b590f5b3..5f8ed3d9709 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf @@ -217,6 +217,11 @@ Namen für nicht aufgelöste Bezeichner vorschlagen + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf index 5c807e55d08..648984fccbb 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf @@ -217,6 +217,11 @@ Sugerir nombres para los identificadores no resueltos + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf index 04b999dbe0a..dc13ed2a628 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf @@ -217,6 +217,11 @@ Suggérer des noms pour les identificateurs non résolus + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf index 7351f82dc40..412ccfeb5f9 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf @@ -217,6 +217,11 @@ Suggerisci nomi per gli identificatori non risolti + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf index 597fd8aec1b..7247dbae375 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf @@ -217,6 +217,11 @@ 未解決の識別子の名前を提案します + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf index ad8d15851cb..55ebb99e142 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf @@ -217,6 +217,11 @@ 확인되지 않은 식별자의 이름 제안 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf index 2fd2a1d7aa7..c9cfedb1971 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf @@ -217,6 +217,11 @@ Sugeruj nazwy w przypadku nierozpoznanych identyfikatorów + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf index c3b72a1253d..038963cf9ba 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf @@ -217,6 +217,11 @@ Sugerir nomes para identificadores não resolvidos + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf index 8bb9fff9020..25a44c54b32 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf @@ -217,6 +217,11 @@ Предлагать имена для неразрешенных идентификаторов + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf index 9134516abd9..0e1f4691b91 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf @@ -217,6 +217,11 @@ Çözümlenmemiş tanımlayıcılar için ad öner + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf index cec0e2d1149..9a5851273c4 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf @@ -217,6 +217,11 @@ 为未解析标识符建议名称 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf index 268e69e2275..b4dd37ef316 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf @@ -217,6 +217,11 @@ 為未解析的識別碼建議名稱 + + Cache parsing results (experimental) + Cache parsing results (experimental) + + \ No newline at end of file