File: ILCompiler\Metadata\Transform.Field.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.MetadataTransform\ILCompiler.MetadataTransform.csproj (ILCompiler.MetadataTransform)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using Internal.Metadata.NativeFormat.Writer;

using Cts = Internal.TypeSystem;
using Ecma = System.Reflection.Metadata;

using Debug = System.Diagnostics.Debug;
using FieldAttributes = System.Reflection.FieldAttributes;

namespace ILCompiler.Metadata
{
    internal partial class Transform<TPolicy>
    {
        internal EntityMap<Cts.FieldDesc, MetadataRecord> _fields =
            new EntityMap<Cts.FieldDesc, MetadataRecord>(EqualityComparer<Cts.FieldDesc>.Default);

        private Action<Cts.FieldDesc, Field> _initFieldDef;
        private Action<Cts.FieldDesc, MemberReference> _initFieldRef;

        public override MetadataRecord HandleQualifiedField(Cts.FieldDesc field)
        {
            if (_policy.GeneratesMetadata(field) && field.GetTypicalFieldDefinition() == field)
            {
                QualifiedField record = new QualifiedField();
                record.Field = HandleFieldDefinition(field);
                record.EnclosingType = (TypeDefinition)HandleType(field.OwningType);
                return record;
            }
            else
            {
                return HandleFieldReference(field);
            }
        }

        private Field HandleFieldDefinition(Cts.FieldDesc field)
        {
            Debug.Assert(field.GetTypicalFieldDefinition() == field);
            Debug.Assert(_policy.GeneratesMetadata(field));
            return (Field)_fields.GetOrCreate(field, _initFieldDef ??= InitializeFieldDefinition);
        }

        private void InitializeFieldDefinition(Cts.FieldDesc entity, Field record)
        {
            record.Name = HandleString(entity.GetName());
            record.Flags = GetFieldAttributes(entity);

            var ecmaField = entity as Cts.Ecma.EcmaField;
            if (ecmaField != null)
            {
                Ecma.MetadataReader reader = ecmaField.MetadataReader;
                Ecma.FieldDefinition fieldDef = reader.GetFieldDefinition(ecmaField.Handle);

                record.Signature = new FieldSignature
                {
                    Type = entity.HasEmbeddedSignatureData
                        ? HandleFieldSignature(ecmaField.Module, fieldDef.Signature)
                        : HandleType(entity.FieldType),
                };

                Ecma.ConstantHandle defaultValueHandle = fieldDef.GetDefaultValue();
                if (!defaultValueHandle.IsNil)
                {
                    record.DefaultValue = HandleConstant(ecmaField.Module, defaultValueHandle);
                }

                Ecma.CustomAttributeHandleCollection customAttributes = fieldDef.GetCustomAttributes();
                if (customAttributes.Count > 0)
                {
                    record.CustomAttributes = HandleCustomAttributes(ecmaField.Module, customAttributes);
                }

                int offset = fieldDef.GetOffset();
                if (offset >= 0)
                    record.Offset = (uint)offset;
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        private MetadataRecord HandleFieldSignature(Cts.Ecma.EcmaModule module, Ecma.BlobHandle sigBlob)
        {
            Ecma.BlobReader reader = module.MetadataReader.GetBlobReader(sigBlob);
            Ecma.SignatureHeader header = reader.ReadSignatureHeader();
            Debug.Assert(header.Kind == Ecma.SignatureKind.Field);
            return HandleType(module, ref reader);
        }

        private MemberReference HandleFieldReference(Cts.FieldDesc field)
        {
            return (MemberReference)_fields.GetOrCreate(field, _initFieldRef ??= InitializeFieldReference);
        }

        private void InitializeFieldReference(Cts.FieldDesc entity, MemberReference record)
        {
            record.Name = HandleString(entity.GetName());
            record.Parent = HandleType(entity.OwningType);
            record.Signature = new FieldSignature
            {
                Type = HandleType(entity.GetTypicalFieldDefinition().FieldType),
                // TODO: CustomModifiers
            };
        }

        private static FieldAttributes GetFieldAttributes(Cts.FieldDesc field)
        {
            FieldAttributes result;

            var ecmaField = field as Cts.Ecma.EcmaField;
            if (ecmaField != null)
            {
                var fieldDefinition = ecmaField.MetadataReader.GetFieldDefinition(ecmaField.Handle);
                result = fieldDefinition.Attributes;
            }
            else
            {
                result = 0;

                if (field.IsStatic)
                    result |= FieldAttributes.Static;
                if (field.IsInitOnly)
                    result |= FieldAttributes.InitOnly;
                if (field.IsLiteral)
                    result |= FieldAttributes.Literal;
                if (field.HasRva)
                    result |= FieldAttributes.HasFieldRVA;

                // Not set: Visibility, NotSerialized, SpecialName, RTSpecialName, HasFieldMarshal, HasDefault
            }

            return result;
        }
    }
}