File: src\runtime\src\coreclr\tools\Common\TypeSystem\Ecma\EcmaType.TypeEquivalence.cs
Web Access
Project: src\runtime\src\coreclr\tools\aot\ILCompiler.TypeSystem\ILCompiler.TypeSystem.csproj (ILCompiler.TypeSystem)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Reflection;
using System.Reflection.Metadata;
using System.Threading;

namespace Internal.TypeSystem.Ecma
{
    public partial class EcmaType
    {
        private  TypeIdentifierData _data;

        private TypeIdentifierData ComputeTypeIdentifierFromGuids()
        {
            CustomAttributeValue<TypeDesc>? guidAttribute;

            if (IsInterface && _typeDefinition.Attributes.HasFlag(TypeAttributes.Import))
            {
                // ComImport interfaces get scope from their GUID
                guidAttribute = this.GetDecodedCustomAttribute("System.Runtime.InteropServices", "GuidAttribute");
            }
            else
            {
                // other equivalent types get it from the declaring assembly
                var attributeHandle = this.MetadataReader.GetCustomAttributeHandle(MetadataReader.GetAssemblyDefinition().GetCustomAttributes(), "System.Runtime.InteropServices", "GuidAttribute");

                if (attributeHandle.IsNil)
                    return null;

                guidAttribute = this.MetadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(this.Module));
            }

            if (!guidAttribute.HasValue)
                return null;

            if (guidAttribute.Value.FixedArguments.Length < 1)
                return null;

            if (guidAttribute.Value.FixedArguments[0].Type != Context.GetWellKnownType(WellKnownType.String))
                return null;

            string scope = (string)guidAttribute.Value.FixedArguments[0].Value;
            string name = this.GetName();

            if (this.Namespace.Length > 0)
                name = this.GetNamespace() + "." + name;

            return new TypeIdentifierData(scope, name);
        }

        private TypeIdentifierData ComputeTypeIdentifierData()
        {
            if (!Context.SupportsTypeEquivalence)
                return null;

            // Check for type identifier attribute
            var typeIdentifierAttribute = this.GetDecodedCustomAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute");

            if (typeIdentifierAttribute.HasValue)
            {
                // If the type has a type identifier attribute it is always considered to be type equivalent
                if (typeIdentifierAttribute.Value.FixedArguments.Length == 0)
                    return ComputeTypeIdentifierFromGuids();

                if (typeIdentifierAttribute.Value.FixedArguments.Length != 2)
                    return null;

                if (typeIdentifierAttribute.Value.FixedArguments[0].Type != Context.GetWellKnownType(WellKnownType.String))
                    return null;

                if (typeIdentifierAttribute.Value.FixedArguments[1].Type != Context.GetWellKnownType(WellKnownType.String))
                    return null;

                return new TypeIdentifierData((string)typeIdentifierAttribute.Value.FixedArguments[0].Value, (string)typeIdentifierAttribute.Value.FixedArguments[1].Value);
            }

            // In addition to the TypeIdentifierAttribute certain other types may also be opted in to type equivalence
            if (Context.SupportsCOMInterop)
            {
                // 1. The assembly is marked with ImportedFromTypeLibAttribute or PrimaryInteropAssemblyAttribute
                // We will verify this by checking for their attribute handles using the Metadata Reader.

                CustomAttributeHandle importedFromTypeLibHdl = this.MetadataReader.GetCustomAttributeHandle(
                    MetadataReader.GetAssemblyDefinition().GetCustomAttributes(),
                    "System.Runtime.InteropServices",
                    "ImportedFromTypeLibAttribute"
                );

                CustomAttributeHandle primaryInteropAssemblyHdl = this.MetadataReader.GetCustomAttributeHandle(
                    MetadataReader.GetAssemblyDefinition().GetCustomAttributes(),
                    "System.Runtime.InteropServices",
                    "PrimaryInteropAssemblyAttribute"
                );

                if (!importedFromTypeLibHdl.IsNil || !primaryInteropAssemblyHdl.IsNil)
                {
                    // This type has a TypeIdentifier attribute if it has an appropriate shape to be considered type equivalent
                    if (!TypeHasCharacteristicsRequiredToBeTypeEquivalent)
                        return null;

                    return ComputeTypeIdentifierFromGuids();
                }
            }

            return null;
        }

        public override TypeIdentifierData TypeIdentifierData
        {
            get
            {
                if (_data != null)
                {
                    if (object.ReferenceEquals(_data, TypeIdentifierData.Empty))
                        return null;
                    return _data;
                }
                var data = ComputeTypeIdentifierData() ?? TypeIdentifierData.Empty;

                Interlocked.CompareExchange(ref _data, data, null);

                // Recurse to read from _data and return a consistent result
                return this.TypeIdentifierData;
            }
        }

        public override bool IsWindowsRuntime
        {
            get
            {
                return _typeDefinition.Attributes.HasFlag(TypeAttributes.WindowsRuntime);
            }
        }

        public override bool IsComImport
        {
            get
            {
                return _typeDefinition.Attributes.HasFlag(TypeAttributes.Import);
            }
        }

        public override bool IsComEventInterface
        {
            get
            {
                return HasCustomAttribute("System.Runtime.InteropServices", "ComEventInterfaceAttribute");
            }
        }
    }
}