File: Compilation\SyntaxAndDeclarationManager.LazyState.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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed partial class SyntaxAndDeclarationManager : CommonSyntaxAndDeclarationManager
    {
        internal sealed class State
        {
            internal readonly ImmutableArray<SyntaxTree> SyntaxTrees; // In ordinal order.
            internal readonly ImmutableDictionary<SyntaxTree, int> OrdinalMap; // Inverse of syntaxTrees array (i.e. maps tree to index)
            internal readonly ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> LoadDirectiveMap;
            internal readonly ImmutableDictionary<string, SyntaxTree> LoadedSyntaxTreeMap;
            internal readonly ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> RootNamespaces;
 
            /// <summary>
            /// Mapping from a syntax tree to the last fully computed member names for each the types (in lexical order)
            /// for this file.  Specifically, the key of the collection is the tree the data is cached for.  The <see
            /// cref="OneOrMany"/> is a compact array of items, each of which corresponds to the prior type-declaration
            /// in the tree that contributed members (in lexical order).  Each item in that compact array is then the
            /// member names for that particular type declaration.
            /// </summary>
            /// <remarks>
            /// Member names often don't change for most edits, so being able to reuse the same set from the last time
            /// things were computed saves on a lot of memory churn producing the new set, then GC'ing the last set
            /// (esp. for very large types). The value is stored as a <see cref="OneOrMany"/> as the most common case
            /// for most files is a single type declaration.
            /// <para/>
            /// We store this with weak references so that we can obtain this optimization in the common case where the 
            /// old declaration is still around rooting the old names.  If the decls are gone though, the names are subject
            /// to being cleaned up by the GC and we may not be able to use them.
            /// </remarks>
            internal readonly ImmutableDictionary<SyntaxTree, OneOrMany<WeakReference<StrongBox<ImmutableSegmentedHashSet<string>>>>> LastComputedMemberNames;
            internal readonly DeclarationTable DeclarationTable;
 
            internal State(
                ImmutableArray<SyntaxTree> syntaxTrees,
                ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
                ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> loadDirectiveMap,
                ImmutableDictionary<string, SyntaxTree> loadedSyntaxTreeMap,
                ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> rootNamespaces,
                ImmutableDictionary<SyntaxTree, OneOrMany<WeakReference<StrongBox<ImmutableSegmentedHashSet<string>>>>> lastComputedMemberNames,
                DeclarationTable declarationTable)
            {
                Debug.Assert(syntaxTrees.All(tree => syntaxTrees[syntaxTreeOrdinalMap[tree]] == tree));
                Debug.Assert(syntaxTrees.SetEquals(rootNamespaces.Keys.AsImmutable(), EqualityComparer<SyntaxTree>.Default));
 
                this.SyntaxTrees = syntaxTrees;
                this.OrdinalMap = syntaxTreeOrdinalMap;
                this.LoadDirectiveMap = loadDirectiveMap;
                this.LoadedSyntaxTreeMap = loadedSyntaxTreeMap;
                this.RootNamespaces = rootNamespaces;
                this.LastComputedMemberNames = lastComputedMemberNames;
                this.DeclarationTable = declarationTable;
            }
        }
    }
}