File: Declarations\SingleTypeDeclaration.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.
 
#nullable disable
 
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed class SingleTypeDeclaration : SingleNamespaceOrTypeDeclaration
    {
        private readonly DeclarationKind _kind;
        private readonly TypeDeclarationFlags _flags;
        private readonly ushort _arity;
        private readonly DeclarationModifiers _modifiers;
        private readonly ImmutableArray<SingleTypeDeclaration> _children;
 
        /// <summary>
        /// Stored as a <see cref="StrongBox{T}"/> so that we can point weak-references at this instance and attempt to
        /// reuse it across edits if the original hasn't been GC'ed.
        /// </summary>
        private readonly StrongBox<ImmutableSegmentedHashSet<string>> _memberNames;
 
        /// <summary>
        /// Any special attributes we may be referencing directly as an attribute on this type or
        /// through a using alias in the file. For example
        /// <c>using X = System.Runtime.CompilerServices.TypeForwardedToAttribute</c> or
        /// <c>[TypeForwardedToAttribute]</c>.  Can be used to avoid having to go back to source
        /// to retrieve attributes when there is no chance they would bind to attribute of interest.
        /// </summary>
        public QuickAttributes QuickAttributes { get; }
 
        [Flags]
        internal enum TypeDeclarationFlags : ushort
        {
            None = 0,
            AnyMemberHasExtensionMethodSyntax = 1 << 1,
            HasAnyAttributes = 1 << 2,
            HasBaseDeclarations = 1 << 3,
            AnyMemberHasAttributes = 1 << 4,
            HasAnyNontypeMembers = 1 << 5,
 
            /// <summary>
            /// Simple program uses await expressions. Set only in conjunction with <see cref="TypeDeclarationFlags.IsSimpleProgram"/>
            /// </summary>
            HasAwaitExpressions = 1 << 6,
 
            /// <summary>
            /// Set only in conjunction with <see cref="TypeDeclarationFlags.IsSimpleProgram"/>
            /// </summary>
            IsIterator = 1 << 7,
 
            /// <summary>
            /// Set only in conjunction with <see cref="TypeDeclarationFlags.IsSimpleProgram"/>
            /// </summary>
            HasReturnWithExpression = 1 << 8,
 
            IsSimpleProgram = 1 << 9,
 
            HasRequiredMembers = 1 << 10,
 
            HasPrimaryConstructor = 1 << 11,
        }
 
        internal SingleTypeDeclaration(
            DeclarationKind kind,
            string name,
            int arity,
            DeclarationModifiers modifiers,
            TypeDeclarationFlags declFlags,
            SyntaxReference syntaxReference,
            SourceLocation nameLocation,
            StrongBox<ImmutableSegmentedHashSet<string>> memberNames,
            ImmutableArray<SingleTypeDeclaration> children,
            ImmutableArray<Diagnostic> diagnostics,
            QuickAttributes quickAttributes)
            : base(name, syntaxReference, nameLocation, diagnostics)
        {
            Debug.Assert(kind != DeclarationKind.Namespace);
 
            _kind = kind;
            _arity = (ushort)arity;
            _modifiers = modifiers;
            _memberNames = memberNames;
            _children = children;
            _flags = declFlags;
            QuickAttributes = quickAttributes;
        }
 
        public override DeclarationKind Kind
        {
            get
            {
                return _kind;
            }
        }
 
        public new ImmutableArray<SingleTypeDeclaration> Children
        {
            get
            {
                return _children;
            }
        }
 
        public int Arity
        {
            get
            {
                return _arity;
            }
        }
 
        public DeclarationModifiers Modifiers
        {
            get
            {
                return _modifiers;
            }
        }
 
        public StrongBox<ImmutableSegmentedHashSet<string>> MemberNames => _memberNames;
 
        public bool AnyMemberHasExtensionMethodSyntax
        {
            get
            {
                return (_flags & TypeDeclarationFlags.AnyMemberHasExtensionMethodSyntax) != 0;
            }
        }
 
        public bool HasAnyAttributes
        {
            get
            {
                return (_flags & TypeDeclarationFlags.HasAnyAttributes) != 0;
            }
        }
 
        public bool HasBaseDeclarations
        {
            get
            {
                return (_flags & TypeDeclarationFlags.HasBaseDeclarations) != 0;
            }
        }
 
        public bool AnyMemberHasAttributes
        {
            get
            {
                return (_flags & TypeDeclarationFlags.AnyMemberHasAttributes) != 0;
            }
        }
 
        public bool HasAnyNontypeMembers
        {
            get
            {
                return (_flags & TypeDeclarationFlags.HasAnyNontypeMembers) != 0;
            }
        }
 
        public bool HasAwaitExpressions
        {
            get
            {
                return (_flags & TypeDeclarationFlags.HasAwaitExpressions) != 0;
            }
        }
 
        public bool HasReturnWithExpression
        {
            get
            {
                return (_flags & TypeDeclarationFlags.HasReturnWithExpression) != 0;
            }
        }
 
        public bool IsIterator
        {
            get
            {
                return (_flags & TypeDeclarationFlags.IsIterator) != 0;
            }
        }
 
        public bool IsSimpleProgram
        {
            get
            {
                return (_flags & TypeDeclarationFlags.IsSimpleProgram) != 0;
            }
        }
 
        public bool HasRequiredMembers => (_flags & TypeDeclarationFlags.HasRequiredMembers) != 0;
 
        public bool HasPrimaryConstructor => (_flags & TypeDeclarationFlags.HasPrimaryConstructor) != 0;
 
        protected override ImmutableArray<SingleNamespaceOrTypeDeclaration> GetNamespaceOrTypeDeclarationChildren()
        {
            return StaticCast<SingleNamespaceOrTypeDeclaration>.From(_children);
        }
 
        internal TypeDeclarationIdentity Identity
        {
            get
            {
                return new TypeDeclarationIdentity(this);
            }
        }
 
        // identity that is used when collecting all declarations 
        // of same type across multiple containers
        internal readonly struct TypeDeclarationIdentity : IEquatable<TypeDeclarationIdentity>
        {
            private readonly SingleTypeDeclaration _decl;
 
            internal TypeDeclarationIdentity(SingleTypeDeclaration decl)
            {
                _decl = decl;
            }
 
            public override bool Equals(object obj)
            {
                return obj is TypeDeclarationIdentity && Equals((TypeDeclarationIdentity)obj);
            }
 
            public bool Equals(TypeDeclarationIdentity other)
            {
                var thisDecl = _decl;
                var otherDecl = other._decl;
 
                // same as itself
                if ((object)thisDecl == otherDecl)
                {
                    return true;
                }
 
                // arity, kind, name must match
                if ((thisDecl._arity != otherDecl._arity) ||
                    (thisDecl._kind != otherDecl._kind) ||
                    (thisDecl.name != otherDecl.name))
                {
                    return false;
                }
 
                if ((object)thisDecl.SyntaxReference.SyntaxTree != otherDecl.SyntaxReference.SyntaxTree
                    && ((thisDecl.Modifiers & DeclarationModifiers.File) != 0
                        || (otherDecl.Modifiers & DeclarationModifiers.File) != 0))
                {
                    // declarations of 'file' types are only the same type if they are in the same file
                    return false;
                }
 
                if (thisDecl._kind == DeclarationKind.Enum || thisDecl._kind == DeclarationKind.Delegate)
                {
                    // oh, so close, but enums and delegates cannot be partial
                    return false;
                }
 
                return true;
            }
 
            public override int GetHashCode()
            {
                var thisDecl = _decl;
                return Hash.Combine(thisDecl.Name.GetHashCode(),
                    Hash.Combine(thisDecl.Arity.GetHashCode(),
                    (int)thisDecl.Kind));
            }
        }
    }
}