File: Emitter\NoPia\EmbeddedType.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.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;
using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer;
 
#if !DEBUG
using NamedTypeSymbolAdapter = Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol;
using FieldSymbolAdapter = Microsoft.CodeAnalysis.CSharp.Symbols.FieldSymbol;
using MethodSymbolAdapter = Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol;
using EventSymbolAdapter = Microsoft.CodeAnalysis.CSharp.Symbols.EventSymbol;
using PropertySymbolAdapter = Microsoft.CodeAnalysis.CSharp.Symbols.PropertySymbol;
#endif
 
namespace Microsoft.CodeAnalysis.CSharp.Emit.NoPia
{
    internal sealed class EmbeddedType : EmbeddedTypesManager.CommonEmbeddedType
    {
        private bool _embeddedAllMembersOfImplementedInterface;
 
        public EmbeddedType(EmbeddedTypesManager typeManager, NamedTypeSymbolAdapter underlyingNamedType) :
            base(typeManager, underlyingNamedType)
        {
            Debug.Assert(underlyingNamedType.AdaptedNamedTypeSymbol.IsDefinition);
            Debug.Assert(underlyingNamedType.AdaptedNamedTypeSymbol.IsTopLevelType());
            Debug.Assert(!underlyingNamedType.AdaptedNamedTypeSymbol.IsGenericType);
        }
 
        public void EmbedAllMembersOfImplementedInterface(SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            Debug.Assert(UnderlyingNamedType.AdaptedNamedTypeSymbol.IsInterfaceType());
 
            if (_embeddedAllMembersOfImplementedInterface)
            {
                return;
            }
 
            _embeddedAllMembersOfImplementedInterface = true;
 
            // Embed all members
            foreach (MethodSymbol m in UnderlyingNamedType.AdaptedNamedTypeSymbol.GetMethodsToEmit())
            {
                if ((object)m != null)
                {
                    TypeManager.EmbedMethod(this, m.GetCciAdapter(), syntaxNodeOpt, diagnostics);
                }
            }
 
            // We also should embed properties and events, but we don't need to do this explicitly here
            // because accessors embed them automatically.
 
            // Do the same for implemented interfaces.
            foreach (NamedTypeSymbol @interface in UnderlyingNamedType.AdaptedNamedTypeSymbol.GetInterfacesToEmit())
            {
                TypeManager.ModuleBeingBuilt.Translate(@interface, syntaxNodeOpt, diagnostics, fromImplements: true);
            }
        }
 
        protected override int GetAssemblyRefIndex()
        {
            ImmutableArray<AssemblySymbol> refs = TypeManager.ModuleBeingBuilt.SourceModule.GetReferencedAssemblySymbols();
            return refs.IndexOf(UnderlyingNamedType.AdaptedNamedTypeSymbol.ContainingAssembly, ReferenceEqualityComparer.Instance);
        }
 
        protected override bool IsPublic
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.DeclaredAccessibility == Accessibility.Public;
            }
        }
 
        protected override Cci.ITypeReference GetBaseClass(PEModuleBuilder moduleBuilder, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            NamedTypeSymbol baseType = UnderlyingNamedType.AdaptedNamedTypeSymbol.BaseTypeNoUseSiteDiagnostics;
            return (object)baseType != null ? moduleBuilder.Translate(baseType, syntaxNodeOpt, diagnostics) : null;
        }
 
        protected override IEnumerable<FieldSymbolAdapter> GetFieldsToEmit()
        {
            return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetFieldsToEmit()
#if DEBUG
                .Select(s => s.GetCciAdapter())
#endif
                ;
        }
 
        protected override IEnumerable<MethodSymbolAdapter> GetMethodsToEmit()
        {
            return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetMethodsToEmit()
#if DEBUG
                .Select(s => s?.GetCciAdapter())
#endif
                ;
        }
 
        protected override IEnumerable<EventSymbolAdapter> GetEventsToEmit()
        {
            return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetEventsToEmit()
#if DEBUG
                .Select(s => s.GetCciAdapter())
#endif
                ;
        }
 
        protected override IEnumerable<PropertySymbolAdapter> GetPropertiesToEmit()
        {
            return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetPropertiesToEmit()
#if DEBUG
                .Select(s => s.GetCciAdapter())
#endif
                ;
        }
 
        protected override IEnumerable<Cci.TypeReferenceWithAttributes> GetInterfaces(EmitContext context)
        {
            Debug.Assert((object)TypeManager.ModuleBeingBuilt == context.Module);
 
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            foreach (NamedTypeSymbol @interface in UnderlyingNamedType.AdaptedNamedTypeSymbol.GetInterfacesToEmit())
            {
                var typeRef = moduleBeingBuilt.Translate(
                    @interface,
                    (CSharpSyntaxNode)context.SyntaxNode,
                    context.Diagnostics);
 
                var type = TypeWithAnnotations.Create(@interface);
                yield return type.GetTypeRefWithAttributes(
                    moduleBeingBuilt,
                    declaringSymbol: UnderlyingNamedType.AdaptedNamedTypeSymbol,
                    typeRef);
            }
        }
 
        protected override bool IsAbstract
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsMetadataAbstract;
            }
        }
 
        protected override bool IsBeforeFieldInit
        {
            get
            {
                switch (UnderlyingNamedType.AdaptedNamedTypeSymbol.TypeKind)
                {
                    case TypeKind.Enum:
                    case TypeKind.Delegate:
                    //C# interfaces don't have fields so the flag doesn't really matter, but Dev10 omits it
                    case TypeKind.Interface:
                        return false;
                }
 
                // We shouldn't embed static constructor.
                return true;
            }
        }
 
        protected override bool IsComImport
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsComImport;
            }
        }
 
        protected override bool IsInterface
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsInterfaceType();
            }
        }
 
        protected override bool IsDelegate
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsDelegateType();
            }
        }
 
        protected override bool IsSerializable
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsSerializable;
            }
        }
 
        protected override bool IsSpecialName
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.HasSpecialName;
            }
        }
 
        protected override bool IsWindowsRuntimeImport
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsWindowsRuntimeImport;
            }
        }
 
        protected override bool IsSealed
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.IsMetadataSealed;
            }
        }
 
        protected override TypeLayout? GetTypeLayoutIfStruct()
        {
            if (UnderlyingNamedType.AdaptedNamedTypeSymbol.IsStructType())
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.Layout;
            }
            return null;
        }
 
        protected override System.Runtime.InteropServices.CharSet StringFormat
        {
            get
            {
                return UnderlyingNamedType.AdaptedNamedTypeSymbol.MarshallingCharSet;
            }
        }
 
        protected override IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(PEModuleBuilder moduleBuilder)
        {
            return UnderlyingNamedType.AdaptedNamedTypeSymbol.GetCustomAttributesToEmit(moduleBuilder);
        }
 
        protected override CSharpAttributeData CreateTypeIdentifierAttribute(bool hasGuid, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            var member = hasGuid ?
                WellKnownMember.System_Runtime_InteropServices_TypeIdentifierAttribute__ctor :
                WellKnownMember.System_Runtime_InteropServices_TypeIdentifierAttribute__ctorStringString;
            var ctor = TypeManager.GetWellKnownMethod(member, syntaxNodeOpt, diagnostics);
            if ((object)ctor == null)
            {
                return null;
            }
 
            if (hasGuid)
            {
                // This is an interface with a GuidAttribute, so we will generate the no-parameter TypeIdentifier.
                return SynthesizedAttributeData.Create(TypeManager.ModuleBeingBuilt.Compilation, ctor, ImmutableArray<TypedConstant>.Empty, ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty);
            }
            else
            {
                // This is an interface with no GuidAttribute, or some other type, so we will generate the
                // TypeIdentifier with name and scope parameters.
 
                // Look for a GUID attribute attached to type's containing assembly. If we find one, we'll use it;
                // otherwise, we expect that we will have reported an error (ERRID_PIAHasNoAssemblyGuid1) about this assembly, since
                // you can't /link against an assembly which lacks a GuidAttribute.
 
                var stringType = TypeManager.GetSystemStringType(syntaxNodeOpt, diagnostics);
 
                if ((object)stringType != null)
                {
                    string guidString = TypeManager.GetAssemblyGuidString(UnderlyingNamedType.AdaptedNamedTypeSymbol.ContainingAssembly);
                    return SynthesizedAttributeData.Create(TypeManager.ModuleBeingBuilt.Compilation, ctor,
                                    ImmutableArray.Create(new TypedConstant(stringType, TypedConstantKind.Primitive, guidString),
                                                    new TypedConstant(stringType, TypedConstantKind.Primitive,
                                                                            UnderlyingNamedType.AdaptedNamedTypeSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat))),
                                    ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty);
                }
            }
 
            return null;
        }
 
        protected override void ReportMissingAttribute(AttributeDescription description, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            EmbeddedTypesManager.Error(diagnostics, ErrorCode.ERR_InteropTypeMissingAttribute, syntaxNodeOpt, UnderlyingNamedType.AdaptedNamedTypeSymbol, description.FullName);
        }
 
        protected override void EmbedDefaultMembers(string defaultMember, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            foreach (Symbol s in UnderlyingNamedType.AdaptedNamedTypeSymbol.GetMembers(defaultMember))
            {
                switch (s.Kind)
                {
                    case SymbolKind.Field:
                        TypeManager.EmbedField(this, ((FieldSymbol)s).GetCciAdapter(), syntaxNodeOpt, diagnostics);
                        break;
                    case SymbolKind.Method:
                        TypeManager.EmbedMethod(this, ((MethodSymbol)s).GetCciAdapter(), syntaxNodeOpt, diagnostics);
                        break;
                    case SymbolKind.Property:
                        TypeManager.EmbedProperty(this, ((PropertySymbol)s).GetCciAdapter(), syntaxNodeOpt, diagnostics);
                        break;
                    case SymbolKind.Event:
                        TypeManager.EmbedEvent(this, ((EventSymbol)s).GetCciAdapter(), syntaxNodeOpt, diagnostics, isUsedForComAwareEventBinding: false);
                        break;
                }
            }
        }
    }
}