Example #1
0
        // 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 SourceGeneratedDocumentState(
     HostLanguageServices languageServices,
     SolutionServices solutionServices,
     IDocumentServiceProvider?documentServiceProvider,
     DocumentInfo.DocumentAttributes attributes,
     ParseOptions?options,
     SourceText?sourceText,
     ValueSource <TextAndVersion> textSource,
     TreeAndVersion treeAndVersion,
     ISourceGenerator sourceGenerator,
     string hintName
     )
     : base(
         languageServices,
         solutionServices,
         documentServiceProvider,
         attributes,
         options,
         sourceText,
         textSource,
         new ConstantValueSource <TreeAndVersion>(treeAndVersion)
         )
 {
     SourceGenerator = sourceGenerator;
     HintName        = hintName;
 }
Example #3
0
        private static TextAndVersion GetTextAndVersion(
            TreeAndVersion treeAndVersion, VersionStamp version, Encoding encoding, string filePath, CancellationToken cancellationToken)
        {
            var text = treeAndVersion.Tree.GetRoot(cancellationToken).GetText(encoding);

            return(TextAndVersion.Create(text, version, filePath));
        }
Example #4
0
        private static async Task <TextAndVersion> GetTextAndVersionAsync(
            TreeAndVersion treeAndVersion, VersionStamp version, Encoding encoding, string filePath, CancellationToken cancellationToken)
        {
            var root = await treeAndVersion.Tree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            return(TextAndVersion.Create(root.GetText(encoding), version, filePath));
        }
Example #5
0
        // 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));
        }
Example #6
0
        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));
            }
        }
Example #7
0
        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));
        }
Example #8
0
        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));
            }
        }
Example #9
0
        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));
        }
Example #10
0
        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));
        }
Example #11
0
        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)));
        }
Example #12
0
        private static TreeAndVersion IncrementallyParse(
            TextAndVersion newTextAndVersion,
            TreeAndVersion oldTreeAndVersion,
            CancellationToken cancellationToken)
        {
            var newText = newTextAndVersion.Text;
            var oldTree = oldTreeAndVersion.Tree;

            var oldText = oldTree.GetText(cancellationToken);
            var newTree = oldTree.WithChangedText(newText);

            Contract.ThrowIfNull(newTree);

            return(MakeNewTreeAndVersion(oldTree, oldText, oldTreeAndVersion.Version, newTree, newText, newTextAndVersion.Version));
        }
Example #13
0
        // 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)));
        }
Example #14
0
        // 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));
        }
Example #15
0
 private static TextAndVersion GetTextAndVersion(
     TreeAndVersion treeAndVersion, VersionStamp version, Encoding encoding, string filePath, CancellationToken cancellationToken)
 {
     var text = treeAndVersion.Tree.GetRoot(cancellationToken).GetText(encoding);
     return TextAndVersion.Create(text, version, filePath);
 }
Example #16
0
        private static TreeAndVersion IncrementallyParse(
            TextAndVersion newTextAndVersion,
            TreeAndVersion oldTreeAndVersion,
            CancellationToken cancellationToken)
        {
            var newText = newTextAndVersion.Text;
            var oldTree = oldTreeAndVersion.Tree;

            var oldText = oldTree.GetText(cancellationToken);
            var newTree = oldTree.WithChangedText(newText);
            Contract.ThrowIfNull(newTree);

            return MakeNewTreeAndVersion(oldTree, oldText, oldTreeAndVersion.Version, newTree, newText, newTextAndVersion.Version);
        }
Example #17
0
 private static async Task<TextAndVersion> GetTextAndVersionAsync(
     TreeAndVersion treeAndVersion, VersionStamp version, Encoding encoding, string filePath, CancellationToken cancellationToken)
 {
     var root = await treeAndVersion.Tree.GetRootAsync(cancellationToken).ConfigureAwait(false);
     return TextAndVersion.Create(root.GetText(encoding), version, filePath);
 }