<commit_before>﻿using NMF.CodeGen;
using NMF.Expressions;
using NMF.Models.Collections;
using NMF.Models.Repository;
using NMF.Transformations;
using NMF.Transformations.Core;
using NMF.Utilities;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NMF.Models.Meta
{
    public partial class Meta2ClassesTransformation
    {
        /// <summary>
        /// The transformation rule that generates the collection class for the children reference
        /// </summary>
        public class Class2Children : TransformationRule<IClass, CodeTypeDeclaration>
        {
            /// <summary>
            /// Creates the uninitialized output type declaration
            /// </summary>
            /// <param name="scope">The scope in which the reference is refined</param>
            /// <param name="context">The transformation context</param>
            /// <returns>The newly created code type declaration</returns>
            public override CodeTypeDeclaration CreateOutput(IClass scope, ITransformationContext context)
            {
                if (!scope.References.Any(r => r.IsContainment)) return null;
                return CodeDomHelper.CreateTypeDeclarationWithReference(scope.Name.ToPascalCase() + "ChildrenCollection");
            }

            protected virtual List<IReference> GetImplementingReferences(IClass scope, ITransformationContext context)
            {
                var generatedType = context.Trace.ResolveIn(Rule<Class2Type>(), scope);
                var r2p = Rule<Reference2Property>();
                return (from c in scope.Closure(c => c.BaseTypes)
                        from r in c.References
                        where r.IsContainment && generatedType.Members.Contains(context.Trace.ResolveIn(r2p, r))
                        select r).ToList();
            }

            private CodeFieldReferenceExpression parentRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_parent");

            /// <summary>
            /// Initializes the created type declaration
            /// </summary>
            /// <param name="scope">The scope in which the reference is refined</param>
            /// <param name="generatedType">The generated type declaration</param>
            /// <param name="context">The transformation context</param>
            public override void Transform(IClass scope, CodeTypeDeclaration generatedType, ITransformationContext context)
            {
                if (generatedType == null) return;
                generatedType.Attributes = MemberAttributes.Family;
                var scopeDeclaration = context.Trace.ResolveIn(Rule<Class2Type>(), scope);
                var elementType = CreateReference(null, true, context);
                var parent = new CodeMemberField(new CodeTypeReference(scopeDeclaration.Name), "_parent");
                parent.Attributes = MemberAttributes.Private;
                generatedType.Members.Add(parent);
                generatedType.BaseTypes.Add(typeof(ReferenceCollection).Name);

                generatedType.WriteDocumentation(string.Format("The collection class to to represent the children of the {0} class", scope.Name));

                var constructor = new CodeConstructor();
                constructor.Attributes = MemberAttributes.Public;
                constructor.Parameters.Add(new CodeParameterDeclarationExpression(parent.Type, "parent"));
                constructor.Statements.Add(new CodeAssignStatement(parentRef, new CodeArgumentReferenceExpression("parent")));

                constructor.WriteDocumentation("Creates a new instance");

                var implementingReferences = GetImplementingReferences(scope, context);

                CodeExpression standardValuesRef = null;

                generatedType.Members.Add(constructor);
                ImplementCollection(generatedType, elementType, standardValuesRef, implementingReferences, context);
            }

            /// <summary>
            /// Implements the ICollection interface
            /// </summary>
            /// <param name="generatedType">The generated code type declaration</param>
            /// <param name="elementType">The element type reference</param>
            /// <param name="implementingReferences">The attributes implementing the collection</param>
            protected virtual void ImplementCollection(CodeTypeDeclaration generatedType, CodeTypeReference elementType, CodeExpression standardValuesRef, List<IReference> implementingReferences, ITransformationContext context)
            {
                generatedType.BaseTypes.Add(new CodeTypeReference(typeof(ICollectionExpression<>).Name, elementType));
                generatedType.BaseTypes.Add(new CodeTypeReference(typeof(ICollection<>).Name, elementType));
                generatedType.Members.Add(GenerateAttachCore(implementingReferences));
                generatedType.Members.Add(GenerateDetachCore(implementingReferences));
                generatedType.Members.Add(GenerateAdd(implementingReferences, elementType, context));
                generatedType.Members.Add(GenerateClear(implementingReferences));
                generatedType.Members.Add(GenerateContains(implementingReferences, elementType, standardValuesRef));
                generatedType.Members.Add(GenerateCopyTo(implementingReferences, elementType, standardValuesRef));
                generatedType.Members.Add(GenerateCount(implementingReferences));
                generatedType.Members.Add(GenerateRemove(implementingReferences, elementType, context));
                generatedType.Members.Add(GenerateGenericGetEnumerator(implementingReferences, elementType, standardValuesRef));
            }

            private CodeMemberMethod GenerateAdd(IEnumerable<IReference> implementingReferences, CodeTypeReference elementType, ITransformationContext context)
            {
                var add = new CodeMemberMethod()
                {
                    Name = "Add",
                    Attributes = MemberAttributes.Public | MemberAttributes.Override,
                    ReturnType = null
                };
                add.Parameters.Add(new CodeParameterDeclarationExpression(elementType, "item"));
                var itemRef = new CodeArgumentReferenceExpression("item");
                foreach (var reference in implementingReferences)
                {
                    var propertyRef = GetPropertyReference(reference);
                    var propertyTypeRef = CreateReference(reference.Type, true, context);
                    if (reference.UpperBound == 1)
                    {
                        var ifNull = new CodeConditionStatement();
                        ifNull.Condition = new CodeBinaryOperatorExpression(propertyRef, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null));
                        if (reference.Type != null)
                        {
                            var variableName = reference.Name.ToCamelCase() + "Casted";
                            ifNull.TrueStatements.Add(new CodeVariableDeclarationStatement(propertyTypeRef, variableName, new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(itemRef, "As", propertyTypeRef))));
                            var varRef = new CodeVariableReferenceExpression(variableName);
                            var typeMatchIf = new CodeConditionStatement();
                            typeMatchIf.Condition = new CodeBinaryOperatorExpression(varRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
                            typeMatchIf.TrueStatements.Add(new CodeAssignStatement(propertyRef, varRef));
                            typeMatchIf.TrueStatements.Add(new CodeMethodReturnStatement());
                            ifNull.TrueStatements.Add(typeMatchIf);
                        }
                        else
                        {
                            ifNull.TrueStatements.Add(new CodeAssignStatement(propertyRef, itemRef));
                            ifNull.TrueStatements.Add(new CodeMethodReturnStatement());
                        }
                        add.Statements.Add(ifNull);
                    }
                    else
                    {
                        if (reference.Type != null)
                        {
                            var variableName = reference.Name.ToCamelCase() + "Casted";
                            add.Statements.Add(new CodeVariableDeclarationStatement(propertyTypeRef, variableName, new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(itemRef, "As", propertyTypeRef))));
                            var varRef = new CodeVariableReferenceExpression(variableName);
                            var typeMatchIf = new CodeConditionStatement();
                            typeMatchIf.Condition = new CodeBinaryOperatorExpression(varRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
                            if (reference.UpperBound == -1)
                            {
                                typeMatchIf.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", varRef));
                            }
                            else
                            {
                                var ifNotFull = new CodeConditionStatement();
                                ifNotFull.Condition = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(propertyRef, "Count"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(reference.UpperBound));
                                ifNotFull.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", itemRef));
                                typeMatchIf.TrueStatements.Add(ifNotFull);
                            }
                            add.Statements.Add(typeMatchIf);
                        }
                        else
                        {
                            if (reference.UpperBound == -1)
                            {
                                add.Statements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", itemRef));
                                break;
                            }
                            else
                            {
                                var ifNotFull = new CodeConditionStatement();
                                ifNotFull.Condition = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(propertyRef, "Count"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(reference.UpperBound));
                                ifNotFull.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", itemRef));
                                add.Statements.Add(ifNotFull);
                            }
                        }
                    }
                }
                add.WriteDocumentation("Adds the given element to the collection", null, new Dictionary<string, string>() { { "item", "The item to add" } });
                return add;
            }

            private CodeMemberMethod GenerateClear(IEnumerable<IReference> implementingReferences)<commit_msg>Fixed small bug in generated children reference<commit_after>﻿using NMF.CodeGen;
using NMF.Expressions;
using NMF.Models.Collections;
using NMF.Models.Repository;
using NMF.Transformations;
using NMF.Transformations.Core;
using NMF.Utilities;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NMF.Models.Meta
{
    public partial class Meta2ClassesTransformation
    {
        /// <summary>
        /// The transformation rule that generates the collection class for the children reference
        /// </summary>
        public class Class2Children : TransformationRule<IClass, CodeTypeDeclaration>
        {
            /// <summary>
            /// Creates the uninitialized output type declaration
            /// </summary>
            /// <param name="scope">The scope in which the reference is refined</param>
            /// <param name="context">The transformation context</param>
            /// <returns>The newly created code type declaration</returns>
            public override CodeTypeDeclaration CreateOutput(IClass scope, ITransformationContext context)
            {
                if (!scope.References.Any(r => r.IsContainment)) return null;
                return CodeDomHelper.CreateTypeDeclarationWithReference(scope.Name.ToPascalCase() + "ChildrenCollection");
            }

            protected virtual List<IReference> GetImplementingReferences(IClass scope, ITransformationContext context)
            {
                var generatedType = context.Trace.ResolveIn(Rule<Class2Type>(), scope);
                var r2p = Rule<Reference2Property>();
                return (from c in scope.Closure(c => c.BaseTypes)
                        from r in c.References
                        where r.IsContainment && generatedType.Members.Contains(context.Trace.ResolveIn(r2p, r))
                        select r).ToList();
            }

            private CodeFieldReferenceExpression parentRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_parent");

            /// <summary>
            /// Initializes the created type declaration
            /// </summary>
            /// <param name="scope">The scope in which the reference is refined</param>
            /// <param name="generatedType">The generated type declaration</param>
            /// <param name="context">The transformation context</param>
            public override void Transform(IClass scope, CodeTypeDeclaration generatedType, ITransformationContext context)
            {
                if (generatedType == null) return;
                generatedType.Attributes = MemberAttributes.Family;
                var scopeDeclaration = context.Trace.ResolveIn(Rule<Class2Type>(), scope);
                var elementType = CreateReference(null, true, context);
                var parent = new CodeMemberField(new CodeTypeReference(scopeDeclaration.Name), "_parent");
                parent.Attributes = MemberAttributes.Private;
                generatedType.Members.Add(parent);
                generatedType.BaseTypes.Add(typeof(ReferenceCollection).Name);

                generatedType.WriteDocumentation(string.Format("The collection class to to represent the children of the {0} class", scope.Name));

                var constructor = new CodeConstructor();
                constructor.Attributes = MemberAttributes.Public;
                constructor.Parameters.Add(new CodeParameterDeclarationExpression(parent.Type, "parent"));
                constructor.Statements.Add(new CodeAssignStatement(parentRef, new CodeArgumentReferenceExpression("parent")));

                constructor.WriteDocumentation("Creates a new instance");

                var implementingReferences = GetImplementingReferences(scope, context);

                CodeExpression standardValuesRef = null;

                generatedType.Members.Add(constructor);
                ImplementCollection(generatedType, elementType, standardValuesRef, implementingReferences, context);
            }

            /// <summary>
            /// Implements the ICollection interface
            /// </summary>
            /// <param name="generatedType">The generated code type declaration</param>
            /// <param name="elementType">The element type reference</param>
            /// <param name="implementingReferences">The attributes implementing the collection</param>
            protected virtual void ImplementCollection(CodeTypeDeclaration generatedType, CodeTypeReference elementType, CodeExpression standardValuesRef, List<IReference> implementingReferences, ITransformationContext context)
            {
                generatedType.BaseTypes.Add(new CodeTypeReference(typeof(ICollectionExpression<>).Name, elementType));
                generatedType.BaseTypes.Add(new CodeTypeReference(typeof(ICollection<>).Name, elementType));
                generatedType.Members.Add(GenerateAttachCore(implementingReferences));
                generatedType.Members.Add(GenerateDetachCore(implementingReferences));
                generatedType.Members.Add(GenerateAdd(implementingReferences, elementType, context));
                generatedType.Members.Add(GenerateClear(implementingReferences));
                generatedType.Members.Add(GenerateContains(implementingReferences, elementType, standardValuesRef));
                generatedType.Members.Add(GenerateCopyTo(implementingReferences, elementType, standardValuesRef));
                generatedType.Members.Add(GenerateCount(implementingReferences));
                generatedType.Members.Add(GenerateRemove(implementingReferences, elementType, context));
                generatedType.Members.Add(GenerateGenericGetEnumerator(implementingReferences, elementType, standardValuesRef));
            }

            private CodeMemberMethod GenerateAdd(IEnumerable<IReference> implementingReferences, CodeTypeReference elementType, ITransformationContext context)
            {
                var add = new CodeMemberMethod()
                {
                    Name = "Add",
                    Attributes = MemberAttributes.Public | MemberAttributes.Override,
                    ReturnType = null
                };
                add.Parameters.Add(new CodeParameterDeclarationExpression(elementType, "item"));
                var itemRef = new CodeArgumentReferenceExpression("item");
                foreach (var reference in implementingReferences)
                {
                    var propertyRef = GetPropertyReference(reference);
                    var propertyTypeRef = CreateReference(reference.Type, true, context);
                    if (reference.UpperBound == 1)
                    {
                        var ifNull = new CodeConditionStatement();
                        ifNull.Condition = new CodeBinaryOperatorExpression(propertyRef, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null));
                        if (reference.Type != null)
                        {
                            var variableName = reference.Name.ToCamelCase() + "Casted";
                            ifNull.TrueStatements.Add(new CodeVariableDeclarationStatement(propertyTypeRef, variableName, new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(itemRef, "As", propertyTypeRef))));
                            var varRef = new CodeVariableReferenceExpression(variableName);
                            var typeMatchIf = new CodeConditionStatement();
                            typeMatchIf.Condition = new CodeBinaryOperatorExpression(varRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
                            typeMatchIf.TrueStatements.Add(new CodeAssignStatement(propertyRef, varRef));
                            typeMatchIf.TrueStatements.Add(new CodeMethodReturnStatement());
                            ifNull.TrueStatements.Add(typeMatchIf);
                        }
                        else
                        {
                            ifNull.TrueStatements.Add(new CodeAssignStatement(propertyRef, itemRef));
                            ifNull.TrueStatements.Add(new CodeMethodReturnStatement());
                        }
                        add.Statements.Add(ifNull);
                    }
                    else
                    {
                        if (reference.Type != null)
                        {
                            var variableName = reference.Name.ToCamelCase() + "Casted";
                            add.Statements.Add(new CodeVariableDeclarationStatement(propertyTypeRef, variableName, new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(itemRef, "As", propertyTypeRef))));
                            var varRef = new CodeVariableReferenceExpression(variableName);
                            var typeMatchIf = new CodeConditionStatement();
                            typeMatchIf.Condition = new CodeBinaryOperatorExpression(varRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
                            if (reference.UpperBound == -1)
                            {
                                typeMatchIf.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", varRef));
                            }
                            else
                            {
                                var ifNotFull = new CodeConditionStatement();
                                ifNotFull.Condition = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(propertyRef, "Count"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(reference.UpperBound));
                                ifNotFull.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", varRef));
                                typeMatchIf.TrueStatements.Add(ifNotFull);
                            }
                            add.Statements.Add(typeMatchIf);
                        }
                        else
                        {
                            if (reference.UpperBound == -1)
                            {
                                add.Statements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", itemRef));
                                break;
                            }
                            else
                            {
                                var ifNotFull = new CodeConditionStatement();
                                ifNotFull.Condition = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(propertyRef, "Count"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(reference.UpperBound));
                                ifNotFull.TrueStatements.Add(new CodeMethodInvokeExpression(propertyRef, "Add", itemRef));
                                add.Statements.Add(ifNotFull);
                            }
                        }
                    }
                }
                add.WriteDocumentation("Adds the given element to the collection", null, new Dictionary<string, string>() { { "item", "The item to add" } });
                return add;
            }

            private CodeMemberMethod GenerateClear(IEnumerable<IReference> implementingReferences)
{'fraction_non_alphanumeric': 0.0783289817232376, 'fraction_numerical': 0.0009735805637916538, 'mean_word_length': 1.9793012524719842, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7589294', 'n_tokens_mistral': 4811, 'n_tokens_neox': 4621, 'n_words': 985}