File: Syntax\CSharpSyntaxTree.LazySyntaxTree.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    public partial class CSharpSyntaxTree
    {
        private sealed class LazySyntaxTree : CSharpSyntaxTree
        {
            private readonly SourceText _text;
            private readonly CSharpParseOptions _options;
            private readonly string _path;
            private readonly ImmutableDictionary<string, ReportDiagnostic> _diagnosticOptions;
            private CSharpSyntaxNode? _lazyRoot;
 
            internal LazySyntaxTree(
                SourceText text,
                CSharpParseOptions options,
                string path,
                ImmutableDictionary<string, ReportDiagnostic>? diagnosticOptions)
            {
                Debug.Assert(options != null);
 
                _text = text;
                _options = options;
                _path = path ?? string.Empty;
                _diagnosticOptions = diagnosticOptions ?? EmptyDiagnosticOptions;
            }
 
            public override string FilePath
            {
                get { return _path; }
            }
 
            public override SourceText GetText(CancellationToken cancellationToken)
            {
                return _text;
            }
 
            public override bool TryGetText([NotNullWhen(true)] out SourceText? text)
            {
                text = _text;
                return true;
            }
 
            public override Encoding? Encoding
            {
                get { return _text.Encoding; }
            }
 
            public override int Length
            {
                get { return _text.Length; }
            }
 
            public override CSharpSyntaxNode GetRoot(CancellationToken cancellationToken)
            {
                if (_lazyRoot == null)
                {
                    // Parse the syntax tree
                    var tree = SyntaxFactory.ParseSyntaxTree(_text, _options, _path, cancellationToken);
                    var root = CloneNodeAsRoot((CSharpSyntaxNode)tree.GetRoot(cancellationToken));
 
                    Interlocked.CompareExchange(ref _lazyRoot, root, null);
                }
 
                return _lazyRoot;
            }
 
            public override bool TryGetRoot([NotNullWhen(true)] out CSharpSyntaxNode? root)
            {
                root = _lazyRoot;
                return root != null;
            }
 
            public override bool HasCompilationUnitRoot
            {
                get
                {
                    return true;
                }
            }
 
            public override CSharpParseOptions Options
            {
                get
                {
                    return _options;
                }
            }
 
            [Obsolete("Obsolete due to performance problems, use CompilationOptions.SyntaxTreeOptionsProvider instead", error: false)]
            public override ImmutableDictionary<string, ReportDiagnostic> DiagnosticOptions => _diagnosticOptions;
 
            public override SyntaxReference GetReference(SyntaxNode node)
            {
                return new SimpleSyntaxReference(node);
            }
 
            public override SyntaxTree WithRootAndOptions(SyntaxNode root, ParseOptions options)
            {
                if (ReferenceEquals(_lazyRoot, root) && ReferenceEquals(_options, options))
                {
                    return this;
                }
 
                return new ParsedSyntaxTree(
                    textOpt: null,
                    _text.Encoding,
                    _text.ChecksumAlgorithm,
                    _path,
                    (CSharpParseOptions)options,
                    (CSharpSyntaxNode)root,
                    _lazyDirectives,
                    _diagnosticOptions,
                    cloneRoot: true);
            }
 
            public override SyntaxTree WithFilePath(string path)
            {
                if (_path == path)
                {
                    return this;
                }
 
                if (TryGetRoot(out var root))
                {
                    return new ParsedSyntaxTree(
                        _text,
                        _text.Encoding,
                        _text.ChecksumAlgorithm,
                        path,
                        _options,
                        root,
                        directives: default,
                        _diagnosticOptions,
                        cloneRoot: true);
                }
                else
                {
                    return new LazySyntaxTree(_text, _options, path, _diagnosticOptions);
                }
            }
 
            [Obsolete("Obsolete due to performance problems, use CompilationOptions.SyntaxTreeOptionsProvider instead", error: false)]
            public override SyntaxTree WithDiagnosticOptions(ImmutableDictionary<string, ReportDiagnostic> options)
            {
                if (options is null)
                {
                    options = EmptyDiagnosticOptions;
                }
 
                if (ReferenceEquals(_diagnosticOptions, options))
                {
                    return this;
                }
 
                if (TryGetRoot(out var root))
                {
                    return new ParsedSyntaxTree(
                        _text,
                        _text.Encoding,
                        _text.ChecksumAlgorithm,
                        _path,
                        _options,
                        root,
                        directives: default,
                        options,
                        cloneRoot: true);
                }
                else
                {
                    return new LazySyntaxTree(_text, _options, _path, options);
                }
            }
        }
    }
}