<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using AsmResolver.Net.Cil;
using AsmResolver.Net.Signatures;

namespace AsmResolver.Net.Cts
{
    public class MemberCloner
    {
        private sealed class MemberClonerReferenceImporter : ReferenceImporter
        {
            private readonly MemberCloner _memberCloner;

            public MemberClonerReferenceImporter(MemberCloner memberCloner, MetadataImage image) 
                : base(image)
            {
                _memberCloner = memberCloner;
            }

            public override ITypeDefOrRef ImportType(TypeDefinition type)
            {
                IMemberReference newType;
                return _memberCloner._createdMembers.TryGetValue(type, out newType)
                    ? (ITypeDefOrRef) newType
                    : base.ImportType(type);
            }

            public override IMethodDefOrRef ImportMethod(MethodDefinition method)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(method, out newMember)
                    ? (IMethodDefOrRef) newMember
                    : base.ImportMethod(method);
            }

            public override IMemberReference ImportField(FieldDefinition field)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(field, out newMember)
                    ? newMember
                    : base.ImportField(field);
            }

            public override MemberReference ImportMember(MemberReference reference)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(reference, out newMember)
                    ? (MemberReference) newMember
                    : base.ImportMember(reference);
            }

            public override IMemberReference ImportReference(IMemberReference reference)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(reference, out newMember)
                    ? newMember
                    : base.ImportReference(reference);
            }
        }

        private readonly MetadataImage _targetImage;
        private readonly IDictionary<IMemberReference, IMemberReference> _createdMembers =
            new Dictionary<IMemberReference, IMemberReference>(new SignatureComparer());
        private readonly IReferenceImporter _importer;

        public MemberCloner(MetadataImage targetImage)
        {
            if (targetImage == null)
                throw new ArgumentNullException("targetImage");
            _targetImage = targetImage;
            _importer = new MemberClonerReferenceImporter(this, targetImage);
        }

        public IList<TypeDefinition> CloneTypes(IList<TypeDefinition> types)
        {
            var newTypes = types.Select(CreateTypeStub).ToArray();
            
            for (var index = 0; index < newTypes.Length; index++)
                DeclareMemberStubs(types[index], newTypes[index]);
            
            for (var index = 0; index < newTypes.Length; index++)
                FinalizeTypeStub(types[index], newTypes[index]);

            return newTypes;
        }
        
        public TypeDefinition CloneType(TypeDefinition type)
        {
            var newType = CreateTypeStub(type);
            DeclareMemberStubs(type, newType);
            FinalizeTypeStub(type, newType);
            return newType;
        }

        private FieldDefinition CloneField(FieldDefinition field)
        {
            var newField = new FieldDefinition(field.Name, field.Attributes, _importer.ImportFieldSignature(field.Signature));

            if (newField.Constant != null)
                newField.Constant = new Constant(field.Constant.ConstantType, new DataBlobSignature(field.Constant.Value.Data));
            
            if (newField.PInvokeMap != null)
                newField.PInvokeMap = CloneImplementationMap(field.PInvokeMap);

            _createdMembers.Add(field, newField);
            CloneCustomAttributes(field, newField);
            
            return newField;
        }

        private TypeDefinition CreateTypeStub(TypeDefinition type)
        {
            var newType = new TypeDefinition(type.Namespace, type.Name, type.Attributes);
            _createdMembers.Add(type, newType);
            
            foreach (var nestedType in type.NestedClasses)
                newType.NestedClasses.Add(new NestedClass(CreateTypeStub(nestedType.Class)));

            return newType;
        }

        private void DeclareMemberStubs(TypeDefinition type, TypeDefinition stub)
        {
            foreach (var nestedType in type.NestedClasses)
                DeclareMemberStubs(nestedType.Class, (TypeDefinition) _createdMembers[nestedType.Class]);
            
            foreach (var field in type.Fields)
                stub.Fields.Add(CloneField(field));
            foreach (var method in type.Methods)
                stub.Methods.Add(CreateMethodStub(method));
            
            if (type.PropertyMap != null)
            {
                stub.PropertyMap = new PropertyMap();
                foreach (var property in type.PropertyMap.Properties)
                    stub.PropertyMap.Properties.Add(CloneProperty(property));
            }
            
            if (type.EventMap != null)
            {
                stub.EventMap = new EventMap();
                foreach (var @event in type.EventMap.Events)
                    stub.EventMap.Events.Add(CloneEvent(@event));
            }
        }

        private void FinalizeTypeStub(TypeDefinition type, TypeDefinition stub)
        {
            foreach (var nestedType in type.NestedClasses)
                FinalizeTypeStub(nestedType.Class, (TypeDefinition) _createdMembers[nestedType.Class]);
            
            foreach (var method in type.Methods)
                FinalizeMethod(method, (MethodDefinition) _createdMembers[method]);
            
            stub.BaseType = _importer.ImportType(type.BaseType);

            if (type.ClassLayout != null)
                stub.ClassLayout = new ClassLayout(type.ClassLayout.ClassSize, type.ClassLayout.PackingSize);

            CloneGenericParameters(type, stub);
            CloneCustomAttributes(type, stub);
        }

        private EventDefinition CloneEvent(EventDefinition @event)
        {
            var newEvent = new EventDefinition(
                @event.Name,<commit_msg>Bugfix MemberCloner: TypeDef.BaseType can be null.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using AsmResolver.Net.Cil;
using AsmResolver.Net.Signatures;

namespace AsmResolver.Net.Cts
{
    public class MemberCloner
    {
        private sealed class MemberClonerReferenceImporter : ReferenceImporter
        {
            private readonly MemberCloner _memberCloner;

            public MemberClonerReferenceImporter(MemberCloner memberCloner, MetadataImage image) 
                : base(image)
            {
                _memberCloner = memberCloner;
            }

            public override ITypeDefOrRef ImportType(TypeDefinition type)
            {
                IMemberReference newType;
                return _memberCloner._createdMembers.TryGetValue(type, out newType)
                    ? (ITypeDefOrRef) newType
                    : base.ImportType(type);
            }

            public override IMethodDefOrRef ImportMethod(MethodDefinition method)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(method, out newMember)
                    ? (IMethodDefOrRef) newMember
                    : base.ImportMethod(method);
            }

            public override IMemberReference ImportField(FieldDefinition field)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(field, out newMember)
                    ? newMember
                    : base.ImportField(field);
            }

            public override MemberReference ImportMember(MemberReference reference)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(reference, out newMember)
                    ? (MemberReference) newMember
                    : base.ImportMember(reference);
            }

            public override IMemberReference ImportReference(IMemberReference reference)
            {
                IMemberReference newMember;
                return _memberCloner._createdMembers.TryGetValue(reference, out newMember)
                    ? newMember
                    : base.ImportReference(reference);
            }
        }

        private readonly MetadataImage _targetImage;
        private readonly IDictionary<IMemberReference, IMemberReference> _createdMembers =
            new Dictionary<IMemberReference, IMemberReference>(new SignatureComparer());
        private readonly IReferenceImporter _importer;

        public MemberCloner(MetadataImage targetImage)
        {
            if (targetImage == null)
                throw new ArgumentNullException("targetImage");
            _targetImage = targetImage;
            _importer = new MemberClonerReferenceImporter(this, targetImage);
        }

        public IList<TypeDefinition> CloneTypes(IList<TypeDefinition> types)
        {
            var newTypes = types.Select(CreateTypeStub).ToArray();
            
            for (var index = 0; index < newTypes.Length; index++)
                DeclareMemberStubs(types[index], newTypes[index]);
            
            for (var index = 0; index < newTypes.Length; index++)
                FinalizeTypeStub(types[index], newTypes[index]);

            return newTypes;
        }
        
        public TypeDefinition CloneType(TypeDefinition type)
        {
            var newType = CreateTypeStub(type);
            DeclareMemberStubs(type, newType);
            FinalizeTypeStub(type, newType);
            return newType;
        }

        private FieldDefinition CloneField(FieldDefinition field)
        {
            var newField = new FieldDefinition(field.Name, field.Attributes, _importer.ImportFieldSignature(field.Signature));

            if (newField.Constant != null)
                newField.Constant = new Constant(field.Constant.ConstantType, new DataBlobSignature(field.Constant.Value.Data));
            
            if (newField.PInvokeMap != null)
                newField.PInvokeMap = CloneImplementationMap(field.PInvokeMap);

            _createdMembers.Add(field, newField);
            CloneCustomAttributes(field, newField);
            
            return newField;
        }

        private TypeDefinition CreateTypeStub(TypeDefinition type)
        {
            var newType = new TypeDefinition(type.Namespace, type.Name, type.Attributes);
            _createdMembers.Add(type, newType);
            
            foreach (var nestedType in type.NestedClasses)
                newType.NestedClasses.Add(new NestedClass(CreateTypeStub(nestedType.Class)));

            return newType;
        }

        private void DeclareMemberStubs(TypeDefinition type, TypeDefinition stub)
        {
            foreach (var nestedType in type.NestedClasses)
                DeclareMemberStubs(nestedType.Class, (TypeDefinition) _createdMembers[nestedType.Class]);
            
            foreach (var field in type.Fields)
                stub.Fields.Add(CloneField(field));
            foreach (var method in type.Methods)
                stub.Methods.Add(CreateMethodStub(method));
            
            if (type.PropertyMap != null)
            {
                stub.PropertyMap = new PropertyMap();
                foreach (var property in type.PropertyMap.Properties)
                    stub.PropertyMap.Properties.Add(CloneProperty(property));
            }
            
            if (type.EventMap != null)
            {
                stub.EventMap = new EventMap();
                foreach (var @event in type.EventMap.Events)
                    stub.EventMap.Events.Add(CloneEvent(@event));
            }
        }

        private void FinalizeTypeStub(TypeDefinition type, TypeDefinition stub)
        {
            foreach (var nestedType in type.NestedClasses)
                FinalizeTypeStub(nestedType.Class, (TypeDefinition) _createdMembers[nestedType.Class]);
            
            foreach (var method in type.Methods)
                FinalizeMethod(method, (MethodDefinition) _createdMembers[method]);
            
            if (type.BaseType != null)
                stub.BaseType = _importer.ImportType(type.BaseType);

            if (type.ClassLayout != null)
                stub.ClassLayout = new ClassLayout(type.ClassLayout.ClassSize, type.ClassLayout.PackingSize);

            CloneGenericParameters(type, stub);
            CloneCustomAttributes(type, stub);
        }

        private EventDefinition CloneEvent(EventDefinition @event)
        {
            var newEvent = new EventDefinition(
                @event.Name,
{'fraction_non_alphanumeric': 0.0707070707070707, 'fraction_numerical': 0.00030152268958239106, 'mean_word_length': 1.9113451832345842, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4313767', 'n_tokens_mistral': 3210, 'n_tokens_neox': 3084, 'n_words': 639}