| File: Declarations\MergedTypeDeclaration.cs | Web Access |
| Project: src\roslyn\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.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { // An invariant of a merged type declaration is that all of its children are also merged // declarations. [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] internal sealed class MergedTypeDeclaration : MergedNamespaceOrTypeDeclaration { private readonly ImmutableArray<SingleTypeDeclaration> _declarations; private ImmutableArray<MergedTypeDeclaration> _lazyChildren; private ICollection<string> _lazyMemberNames; internal MergedTypeDeclaration(ImmutableArray<SingleTypeDeclaration> declarations) : base(declarations[0].Name) { _declarations = declarations; } public ImmutableArray<SingleTypeDeclaration> Declarations { get { return _declarations; } } public ImmutableArray<SyntaxReference> SyntaxReferences { get { return _declarations.SelectAsArray(r => r.SyntaxReference); } } /// <summary> /// Returns the original syntax nodes for this type declaration across all its parts. If /// <paramref name="quickAttributes"/> is provided, attributes will not be returned if it /// is certain there are none that could match the request. This prevents going back to /// source unnecessarily. /// </summary> public ImmutableArray<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations(QuickAttributes? quickAttributes) { var attributeSyntaxListBuilder = ArrayBuilder<SyntaxList<AttributeListSyntax>>.GetInstance(); foreach (var decl in _declarations) { if (!decl.HasAnyAttributes) { continue; } if (quickAttributes != null && (decl.QuickAttributes & quickAttributes.Value) == 0) { continue; } var syntaxRef = decl.SyntaxReference; var typeDecl = syntaxRef.GetSyntax(); SyntaxList<AttributeListSyntax> attributesSyntaxList; switch (typeDecl.Kind()) { case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.UnionDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: case SyntaxKind.ExtensionBlockDeclaration: attributesSyntaxList = ((TypeDeclarationSyntax)typeDecl).AttributeLists; break; case SyntaxKind.DelegateDeclaration: attributesSyntaxList = ((DelegateDeclarationSyntax)typeDecl).AttributeLists; break; case SyntaxKind.EnumDeclaration: attributesSyntaxList = ((EnumDeclarationSyntax)typeDecl).AttributeLists; break; default: throw ExceptionUtilities.UnexpectedValue(typeDecl.Kind()); } attributeSyntaxListBuilder.Add(attributesSyntaxList); } return attributeSyntaxListBuilder.ToImmutableAndFree(); } public override DeclarationKind Kind { get { return this.Declarations[0].Kind; } } public int Arity { get { return this.Declarations[0].Arity; } } public bool ContainsExtensionMethods { get { foreach (var decl in this.Declarations) { if (decl.AnyMemberHasExtensionMethodSyntax) return true; } return false; } } public bool ContainsExtensionDeclarations { get { foreach (var decl in this.Declarations) { if (decl.AnyExtensionDeclarationSyntax) return true; } return false; } } public bool HasPrimaryConstructor { get { foreach (var decl in this.Declarations) { if (decl.HasPrimaryConstructor) return true; } return false; } } public bool AnyMemberHasAttributes { get { foreach (var decl in this.Declarations) { if (decl.AnyMemberHasAttributes) return true; } return false; } } public LexicalSortKey GetLexicalSortKey(CSharpCompilation compilation) { LexicalSortKey sortKey = new LexicalSortKey(Declarations[0].NameLocation, compilation); for (var i = 1; i < Declarations.Length; i++) { sortKey = LexicalSortKey.First(sortKey, new LexicalSortKey(Declarations[i].NameLocation, compilation)); } return sortKey; } public OneOrMany<SourceLocation> NameLocations { get { if (Declarations.Length == 1) return OneOrMany.Create(Declarations[0].NameLocation); var builder = ArrayBuilder<SourceLocation>.GetInstance(Declarations.Length); foreach (var decl in Declarations) builder.AddIfNotNull(decl.NameLocation); return builder.ToOneOrManyAndFree(); } } private ImmutableArray<MergedTypeDeclaration> MakeChildren() { ArrayBuilder<SingleTypeDeclaration> nestedTypes = null; foreach (var decl in this.Declarations) { foreach (var child in decl.Children) { var asType = child as SingleTypeDeclaration; if (asType != null) { if (nestedTypes == null) { nestedTypes = ArrayBuilder<SingleTypeDeclaration>.GetInstance(); } nestedTypes.Add(asType); } } } var children = ArrayBuilder<MergedTypeDeclaration>.GetInstance(); if (nestedTypes != null) { var typesGrouped = nestedTypes.ToDictionary(t => t.Identity); nestedTypes.Free(); foreach (var typeGroup in typesGrouped.Values) { children.Add(new MergedTypeDeclaration(typeGroup)); } } return children.ToImmutableAndFree(); } public new ImmutableArray<MergedTypeDeclaration> Children { get { if (_lazyChildren.IsDefault) { ImmutableInterlocked.InterlockedInitialize(ref _lazyChildren, MakeChildren()); } return _lazyChildren; } } protected override ImmutableArray<Declaration> GetDeclarationChildren() { return StaticCast<Declaration>.From(this.Children); } public ICollection<string> MemberNames { get { if (_lazyMemberNames == null) { var names = UnionCollection<string>.Create(this.Declarations, d => d.MemberNames.Value); Interlocked.CompareExchange(ref _lazyMemberNames, names, null); } return _lazyMemberNames; } } internal string GetDebuggerDisplay() { string identifier = (Kind is DeclarationKind.Extension) ? "extension" : Name; return $"{nameof(MergedTypeDeclaration)} {identifier}"; } } }