private static TreeAndVersion MakeNewTreeAndVersion(SyntaxTree oldTree, SourceText oldText, VersionStamp oldVersion, SyntaxTree newTree, SourceText newText, VersionStamp newVersion) { var topLevelChanged = TopLevelChanged(oldTree, oldText, newTree, newText); var version = topLevelChanged ? newVersion : oldVersion; return(TreeAndVersion.Create(newTree, version)); }
// use static method so we don't capture references to this private static Tuple <AsyncLazy <TextAndVersion>, AsyncLazy <TreeAndVersion> > CreateRecoverableTextAndTree( SyntaxNode newRoot, VersionStamp textVersion, VersionStamp treeVersion, DocumentInfo info, ParseOptions options, ISyntaxTreeFactoryService factory, PreservationMode mode) { string filePath = info.FilePath; Encoding encoding = info.DefaultEncoding; AsyncLazy <TreeAndVersion> lazyTree = null; // this captures the lazyTree local var lazyText = new AsyncLazy <TextAndVersion>( c => GetTextAndVersionAsync(lazyTree, textVersion, encoding, filePath, c), c => GetTextAndVersion(lazyTree, textVersion, encoding, filePath, c), cacheResult: false); // this should be only called when we do forking, since there is no cheap way to figure out what has been changed, // we will always consider top level being changed by giving new version here. if (mode == PreservationMode.PreserveIdentity) { lazyTree = new AsyncLazy <TreeAndVersion>( TreeAndVersion.Create(factory.CreateSyntaxTree(GetSyntaxTreeFilePath(info), options, newRoot, encoding), treeVersion)); } else { lazyTree = new AsyncLazy <TreeAndVersion>( TreeAndVersion.Create(factory.CreateRecoverableTree(GetSyntaxTreeFilePath(info), options, lazyText, newRoot, reparse: false), treeVersion)); } return(Tuple.Create(lazyText, lazyTree)); }
private static TreeAndVersion CreateTreeAndVersion( ValueSource <TextAndVersion> newTextSource, ProjectId cacheKey, string filePath, ParseOptions options, AnalyzerConfigSet analyzerConfigSet, HostLanguageServices languageServices, PreservationMode mode, TextAndVersion textAndVersion, CancellationToken cancellationToken) { var text = textAndVersion.Text; var treeFactory = languageServices.GetService <ISyntaxTreeFactoryService>(); var treeDiagnosticOptions = filePath != null?analyzerConfigSet.GetOptionsForSourcePath(filePath).TreeOptions : null; var tree = treeFactory.ParseSyntaxTree(filePath, options, text, treeDiagnosticOptions, cancellationToken); var root = tree.GetRoot(cancellationToken); if (mode == PreservationMode.PreserveValue && treeFactory.CanCreateRecoverableTree(root)) { tree = treeFactory.CreateRecoverableTree(cacheKey, tree.FilePath, tree.Options, newTextSource, text.Encoding, root); } Contract.ThrowIfNull(tree); CheckTree(tree, text); // text version for this document should be unique. use it as a starting point. return(TreeAndVersion.Create(tree, textAndVersion.Version)); }
private static async Task <TreeAndVersion> FullyParseTreeAsync( ValueSource <TextAndVersion> newTextSource, ProjectId cacheKey, string filePath, ParseOptions options, HostLanguageServices languageServices, SolutionServices solutionServices, PreservationMode mode, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Workspace_Document_State_FullyParseSyntaxTree, s_fullParseLog, filePath, mode, cancellationToken)) { var textAndVersion = await newTextSource.GetValueAsync(cancellationToken).ConfigureAwait(false); var text = textAndVersion.Text; var treeFactory = languageServices.GetService <ISyntaxTreeFactoryService>(); var tree = treeFactory.ParseSyntaxTree(filePath, options, text, cancellationToken); var root = tree.GetRoot(cancellationToken); if (mode == PreservationMode.PreserveValue && treeFactory.CanCreateRecoverableTree(root)) { tree = treeFactory.CreateRecoverableTree(cacheKey, tree.FilePath, tree.Options, newTextSource, text.Encoding, root); } Contract.ThrowIfNull(tree); // text version for this document should be unique. use it as a starting point. return(TreeAndVersion.Create(tree, textAndVersion.Version)); } }
private static async Task <TreeAndVersion> FullyParseTreeAsync( ValueSource <TextAndVersion> newTextSource, string filePath, ParseOptions options, HostLanguageServices languageServices, PreservationMode mode, CancellationToken cancellationToken) { using (Logger.LogBlock(FeatureId.DocumentState, FunctionId.DocumentState_FullyParseSyntaxTree, cancellationToken)) { var textAndVersion = await newTextSource.GetValueAsync(cancellationToken).ConfigureAwait(false); var text = textAndVersion.Text; var treeFactory = languageServices.GetService <ISyntaxTreeFactoryService>(); var tree = treeFactory.ParseSyntaxTree(filePath, options, text, cancellationToken); if (mode == PreservationMode.PreserveValue) { var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); // get a recoverable tree that reparses from the source text if it gets used after being kicked out of memory tree = treeFactory.CreateRecoverableTree(tree.FilePath, tree.Options, newTextSource, root, reparse: true); } Contract.ThrowIfNull(tree); // text version for this document should be unique. use it as a starting point. return(TreeAndVersion.Create(tree, textAndVersion.Version)); } }
// use static method so we don't capture references to this private static Tuple <AsyncLazy <TextAndVersion>, TreeAndVersion> CreateRecoverableTextAndTree( SyntaxNode newRoot, VersionStamp textVersion, VersionStamp treeVersion, DocumentInfo info, ParseOptions options, ISyntaxTreeFactoryService factory, PreservationMode mode, SolutionServices solutionServices) { string filePath = info.FilePath; TreeAndVersion lazyTree = null; // Since this text will be created from a tree, it doesn't have an explicit encoding. // We'll check for this case when writing out the file, and look at the original file's // encoding. Encoding encoding = null; // this captures the lazyTree local var lazyText = new AsyncLazy <TextAndVersion>( c => GetTextAndVersionAsync(lazyTree, textVersion, encoding, filePath, c), c => GetTextAndVersion(lazyTree, textVersion, encoding, filePath, c), cacheResult: false); lazyTree = TreeAndVersion.Create( (mode == PreservationMode.PreserveIdentity) || !solutionServices.SupportsCachingRecoverableObjects ? factory.CreateSyntaxTree(GetSyntaxTreeFilePath(info), options, newRoot, encoding) : factory.CreateRecoverableTree(info.Id.ProjectId, GetSyntaxTreeFilePath(info), options, lazyText, newRoot), treeVersion); return(Tuple.Create(lazyText, lazyTree)); }
public static SourceGeneratedDocumentState Create( string hintName, SourceText generatedSourceText, SyntaxTree generatedSyntaxTree, DocumentId documentId, ISourceGenerator sourceGenerator, HostLanguageServices languageServices, SolutionServices solutionServices, CancellationToken cancellationToken) { var options = generatedSyntaxTree.Options; var filePath = generatedSyntaxTree.FilePath; var textAndVersion = TextAndVersion.Create(generatedSourceText, VersionStamp.Create()); ValueSource <TextAndVersion> textSource = new ConstantValueSource <TextAndVersion>(textAndVersion); var root = generatedSyntaxTree.GetRoot(cancellationToken); Contract.ThrowIfNull(languageServices.SyntaxTreeFactory, "We should not have a generated syntax tree for a language that doesn't support trees."); if (languageServices.SyntaxTreeFactory.CanCreateRecoverableTree(root)) { // We will only create recoverable text if we can create a recoverable tree; if we created a // recoverable text but not a new tree, it would mean tree.GetText() could still potentially return // the non-recoverable text, but asking the document directly for it's text would give a recoverable // text with a different object identity. textSource = CreateRecoverableText(textAndVersion, solutionServices); generatedSyntaxTree = languageServices.SyntaxTreeFactory.CreateRecoverableTree( documentId.ProjectId, filePath: generatedSyntaxTree.FilePath, options, textSource, generatedSourceText.Encoding, root); } var treeAndVersion = TreeAndVersion.Create(generatedSyntaxTree, textAndVersion.Version); return(new SourceGeneratedDocumentState( languageServices, solutionServices, documentServiceProvider: null, new DocumentInfo.DocumentAttributes( documentId, name: hintName, folders: SpecializedCollections.EmptyReadOnlyList <string>(), options.Kind, filePath: filePath, isGenerated: true, designTimeOnly: false), options, sourceText: null, // don't strongly hold the text textSource, treeAndVersion, sourceGenerator, hintName)); }
private static Tuple <ValueSource <TextAndVersion>, TreeAndVersion> CreateRecoverableTextAndTree( SyntaxNode newRoot, string filePath, VersionStamp textVersion, VersionStamp treeVersion, Encoding?encoding, DocumentInfo.DocumentAttributes attributes, ParseOptions options, ImmutableDictionary <string, ReportDiagnostic>?treeDiagnosticReportingOptions, ISyntaxTreeFactoryService factory, PreservationMode mode) { SyntaxTree tree; ValueSource <TextAndVersion> lazyTextAndVersion; if ((mode == PreservationMode.PreserveIdentity) || !factory.CanCreateRecoverableTree(newRoot)) { tree = factory.CreateSyntaxTree(filePath, options, encoding, newRoot, treeDiagnosticReportingOptions); // its okay to use a strong cached AsyncLazy here because the compiler layer SyntaxTree will also keep the text alive once its built. lazyTextAndVersion = new TreeTextSource( new AsyncLazy <SourceText>( c => tree.GetTextAsync(c), c => tree.GetText(c), cacheResult: true), textVersion, filePath); } else { // There is a strange circularity here: the creation of lazyTextAndVersion reads this local, but will see it as non-null since it // only uses it through a lambda that won't have ran. The assignment exists to placate the definite-assignment analysis (which is // right to be suspicious of this). tree = null !; // uses CachedWeakValueSource so the document and tree will return the same SourceText instance across multiple accesses as long // as the text is referenced elsewhere. lazyTextAndVersion = new TreeTextSource( new CachedWeakValueSource <SourceText>( new AsyncLazy <SourceText>( c => BuildRecoverableTreeTextAsync(tree, encoding, c), c => BuildRecoverableTreeText(tree, encoding, c), cacheResult: false)), textVersion, filePath); tree = factory.CreateRecoverableTree(attributes.Id.ProjectId, filePath, options, lazyTextAndVersion, encoding, newRoot, treeDiagnosticReportingOptions); } return(Tuple.Create(lazyTextAndVersion, TreeAndVersion.Create(tree, treeVersion))); }
// use static method so we don't capture references to this private static Tuple <ValueSource <TextAndVersion>, TreeAndVersion> CreateRecoverableTextAndTree( SyntaxNode newRoot, string filePath, VersionStamp textVersion, VersionStamp treeVersion, Encoding encoding, DocumentInfo.DocumentAttributes attributes, ParseOptions options, ImmutableDictionary <string, ReportDiagnostic> treeDiagnosticReportingOptionsOpt, ISyntaxTreeFactoryService factory, PreservationMode mode) { SyntaxTree tree = null; ValueSource <TextAndVersion> lazyTextAndVersion = null; if ((mode == PreservationMode.PreserveIdentity) || !factory.CanCreateRecoverableTree(newRoot)) { // its okay to use a strong cached AsyncLazy here because the compiler layer SyntaxTree will also keep the text alive once its built. lazyTextAndVersion = new TreeTextSource( new AsyncLazy <SourceText>( c => tree.GetTextAsync(c), c => tree.GetText(c), cacheResult: true), textVersion, filePath); tree = factory.CreateSyntaxTree(filePath, options, encoding, newRoot, treeDiagnosticReportingOptionsOpt); } else { // uses CachedWeakValueSource so the document and tree will return the same SourceText instance across multiple accesses as long // as the text is referenced elsewhere. lazyTextAndVersion = new TreeTextSource( new CachedWeakValueSource <SourceText>( new AsyncLazy <SourceText>( c => BuildRecoverableTreeTextAsync(tree, encoding, c), c => BuildRecoverableTreeText(tree, encoding, c), cacheResult: false)), textVersion, filePath); tree = factory.CreateRecoverableTree(attributes.Id.ProjectId, filePath, options, lazyTextAndVersion, encoding, newRoot, treeDiagnosticReportingOptionsOpt); } return(Tuple.Create(lazyTextAndVersion, TreeAndVersion.Create(tree, treeVersion))); }
// use static method so we don't capture references to this private static Tuple <AsyncLazy <TextAndVersion>, TreeAndVersion> CreateRecoverableTextAndTree( SyntaxNode newRoot, VersionStamp textVersion, VersionStamp treeVersion, Encoding encoding, DocumentInfo info, ParseOptions options, ISyntaxTreeFactoryService factory, PreservationMode mode, SolutionServices solutionServices) { string filePath = info.FilePath; TreeAndVersion lazyTree = null; // this captures the lazyTree local var lazyText = new AsyncLazy <TextAndVersion>( c => GetTextAndVersionAsync(lazyTree, textVersion, encoding, filePath, c), c => GetTextAndVersion(lazyTree, textVersion, encoding, filePath, c), cacheResult: false); lazyTree = TreeAndVersion.Create( (mode == PreservationMode.PreserveIdentity) || !solutionServices.SupportsCachingRecoverableObjects ? factory.CreateSyntaxTree(GetSyntaxTreeFilePath(info), options, encoding, newRoot) : factory.CreateRecoverableTree(info.Id.ProjectId, GetSyntaxTreeFilePath(info), options, lazyText, encoding, newRoot), treeVersion); return(Tuple.Create(lazyText, lazyTree)); }