diff --git a/docs/builder-caches.md b/docs/builder-caches.md new file mode 100644 index 0000000000000000000000000000000000000000..90d7e2e471d80d4c20c9ee51246fba5d11d1c616 --- /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 57562813eb994874b391fb2e44760e0064cd5725..bfc2d69c75923bc57dc749a8f17a64573cbb169a 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 ee9b06380eb800ecfeba896e4bb4c8119197a6f2..a1c5fa7062498680e3e4147a1acd71bbfe5ff7ff 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 65537dd67b80a94d0be62220ebdd051f5d1bc5bd..8b68495389ba1680aadd50764a4b19882480c709 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 52a355c9162ce04ec8a943a6a0f66ed68978c7f1..5d482b3cbed85675d5a3509ca0d0de988d747e83 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 a5f8000cfa0a69058497294c108fc656bad11ed6..6305ce77e08ebc76f783b55f27ac27a6245f4fb7 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 0f9647a4ecc1f6cc9289739a678dcad28339bb67..96d3844ea4fd34b05e6c3c38d96f5d451f33c5af 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 6b5775f23e7ae32645d1c7b4a45db90e67b340a0..ce7820ddf4e31c697004d196de96635b96498db9 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 615dddacdf9a7b3127975519dd1ba26174351215..9897351892263b560d48d3c0d57dd274c88120a0 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 615dddacdf9a7b3127975519dd1ba26174351215..9897351892263b560d48d3c0d57dd274c88120a0 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 cf5fae950661f55df67954fc3bf53d1aba4c3065..7d789d00f4ab1de4f2910cf83e59361852647881 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 af946778b69e252b7b3f7cacadd2b96dc96be40e..da310df50bf2edad2fd6dc3392c396c35c042835 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 821a0ab8aad30246816aa849676101d37a5a0e10..fc45d4d7206a0fb055cbdf22c8c376d6d6beb884 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 78f751999ebe44d16bcc1807eceb6d0db5a54fa9..6edfcc6cc1df977f8b13f5f0d4e5bbe3772dc3eb 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 271152415d14f0bb57aa0868c4148e616a082788..919b27ecb3eaf7bd4331c3273bda3323c8a13528 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 a264f044ed35f4d1b6ad2c09fc40f4d05c49842d..f43d8d69260bc61d245803bfe7280f026599840f 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 5c4e44f80c5fdae00dfd3d9bd3f1088505e2a207..c63cb9344174a85489bfe071f051f943b18fcf76 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 ba1cbf9f0bfc075898997ea64db69897cfab26d7..eb7ecbe01b52ada1014ed2c32e724a5bf1dfb959 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 3a287f0f36a5273d559299dd819dcd8a5877a716..a67aed36350ed664d0324bb59f740493d0943d1f 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 6b5448db35660784b4a2310737cdd05d69ed2abd..faf7498c3b58ecacc0c7fe8f09c051d30b100233 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 20cac30b405c511ca2d3fc60b0b8a32a3647ca51..d4d2cbceedbe64deff4b24e59bd5c1be9c18ec05 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 aed9ab9c6f94ad34706fd9c4ab4cd7bfa3686d65..ed6fde565fff2efaf334941fed7749bea16f150f 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 b86e03bc023364702979b63ddbe7ff6015ee40b0..77b968844e40bb77568a7e898966f0f4ed791e04 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 4b491e1f465847021f10eb7381ce42f4cae2f82a..a6d553a48766d00f050378ab671ad80ed4621bba 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 75838b42f8c6facaf7f817138cf7f8316753e1ca..7e5d5661fc261c7122ff29e8365fc8eca462928d 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 d664fbf723cf18e8621011a323b594ae15c66799..fdc3d9f27be70db9e381b49ac8f6239e74422a96 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 0ab59331fa47f204881cc28a521585f074c9b55d..5c6f726e41c0b6c54dfb0092df7819bd33f0fb19 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 b61f20c47f2d532204a243485c776c181551194c..0a14570aaaf4af7a86f697fa8f201bd10f7ca14a 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 8e3e92323e19101d01cd51f625278bb7b5dfc409..f983f08de3b8a3930ff6c09548f0c0371a728993 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs +++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs @@ -446,5 +446,14 @@ public class Strings { 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 e97f18d0eccb3e7e475b9e11b90fc0d64f94bb3a..06637b5c1474eeb3d0baef176dae18db6be68ff3 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 9289f9407c7d5e3ce1e51d8109031c417e1750d3..d4e489701e2e3f66463689efab2bdbb4a9a32c1f 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 d14b590f5b3649ff17b21b14060f800d0f6346ef..5f8ed3d9709623f36d9e69e8a0c95da89099d88e 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 5c807e55d08bc439bc713fd0f1b9c9f56410e3be..648984fccbb7239a624fce32e13e475711cf61c5 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 04b999dbe0a427021537cf2ed09a63a9ae46ceb5..dc13ed2a6281276de95003196ba5a2d7c90ae917 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 7351f82dc40c71f1d40c1b9fd70e1d887e5ec03f..412ccfeb5f9a9cc923853ada64a178eaba7c0028 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 597fd8aec1be0f9c0b1cc9e0716b6cffade4d1db..7247dbae375a4bb26b8d76a03c300d83f7ef2c0b 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 ad8d15851cb5475cb2251ba22795d3573a8416cd..55ebb99e14248d368ffd693c8678aa617a15bee4 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 2fd2a1d7aa7a7c2f025fe7817dc5dd9be4610f4d..c9cfedb197192ec742443c1541f988ab050e82d2 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 c3b72a1253d621dbc1de6d43d85100863d01f2ce..038963cf9ba4cf2c4e8f9ae13f3bf19311ad4bce 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 8bb9fff90203be66818d5f1f9b30fe4efe5e95e6..25a44c54b32b0a6198d499b87c26dabb79399a59 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 9134516abd919209f48a2dda2e39716deed91be3..0e1f4691b9146d2026328dd100e7a85df22159d4 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 cec0e2d1149d440c9be10371f356c5eff96e75e9..9a5851273c4c3be320528c587fe166c60b225168 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 268e69e2275d3a6251554a3d3f818ef599cca925..b4dd37ef316d3334a767aba97e2f5a61d6d5be6e 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