<commit_before>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Voyagers.Utilities.ObjectComparer.Attributes;

namespace Voyagers.Utilities.ObjectComparer
{
    internal static class ReflectionHelper
    {
        /// <summary>
        /// Returns if <param name="type">type</param> 
        /// implements IEnumerable&lt;T&gt;, and <param name="genericArgument"></param> containing 
        /// the generic argument of IEnumerable&lt;T&gt;
        /// </summary>
        /// <param name="type"></param>
        /// <param name="genericArgument">out parameter containing the type argument of IEnumerable&lt;T&gt;</param>
        /// <returns></returns>
        internal static bool TryGetIEnumerableGenericArgument(Type type, out Type genericArgument)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            // Check whether type implements IEnumerable<T> first
            Type ienumerableType = type.GetInterfaces()
                                       .FirstOrDefault(
                                           interfaceType =>
                                           interfaceType.IsGenericType &&
                                           interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
            genericArgument = ienumerableType != null ? ienumerableType.GetGenericArguments()[0] : null;
            return genericArgument != null;
        }

        /// <summary>
        /// Returns true if any members of<param name="type">type</param> contain the KeyAttribute
        /// </summary>
        /// <param name="type"></param>
        /// <param name="propertyInfos">out parameter of PropertyInfos containing all properties with KeyAttribute</param>
        /// <returns></returns>
        internal static bool TryGetKeyAttriubte(Type type, out IEnumerable<PropertyInfo> propertyInfos)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            propertyInfos = from prop in GetPropertyInfos(type)
                            where Attribute.IsDefined(prop, typeof(KeyAttribute))
                            select prop;
            if (propertyInfos.Any())
            {
                return true;
            }

            // KeyAttribute is not declared on the type, search for MetadataTypeAttribute
            var metadataTypeAttributes =
                (MetadataTypeAttribute[])type.GetCustomAttributes(typeof(MetadataTypeAttribute));
            if (!metadataTypeAttributes.Any())
            {
                return false;
            }

            propertyInfos = from metadataTypeAttribute in metadataTypeAttributes
                            let metadataClassType = metadataTypeAttribute.MetadataClassType
                            from propertyInfo in GetPropertyInfos(metadataClassType)
                            let metadataClassPropertyInfo = metadataClassType.GetProperty(propertyInfo.Name)
                            where Attribute.IsDefined(metadataClassPropertyInfo, typeof(KeyAttribute))
                            select metadataClassPropertyInfo;

            return propertyInfos.Any();
        }

        internal static bool HasIgnoreVarianceAttribute(params PropertyInfo[] propertyInfos)
        {
            if (propertyInfos == null)
            {
                throw new ArgumentNullException("propertyInfos");
            }

            // Two scenarios here:
            // 1. IgnoreVarianceAttribute is applied on the property of the containing class
            // 2. IgnoreVarianceAttirubte is applied on the declaring type of the property
            if (propertyInfos.Any(pi => Attribute.IsDefined(pi, typeof(IgnoreVarianceAttribute)) ||
                                        HasIgnoreVarianceAttribute(pi.DeclaringType)))
            {
                return true;
            }

            // IgnoreVarianceAttribute is not declared on the type, search for MetadataTypeAttribute
            // Look for propertyInfos in the metadata class, if a metadata class exists
            var metadataPropertyInfos = (from propertyInfo in propertyInfos
                                         let metadataTypeAttributes =
                                             (MetadataTypeAttribute[])
                                             propertyInfo.DeclaringType.GetCustomAttributes(
                                                 typeof(MetadataTypeAttribute))
                                         where metadataTypeAttributes.Any()
                                         let metadataProperty =
                                             metadataTypeAttributes[0].MetadataClassType.GetProperty(propertyInfo.Name)
                                         where metadataProperty != null
                                         select metadataProperty).ToList();

            // No propertyInfos exist, because no metadata classes exist
            if (!metadataPropertyInfos.Any())
            {
                return false;
            }

            return
                metadataPropertyInfos.Any(
                    metadataClassPropertyInfo =>
                    Attribute.IsDefined(metadataClassPropertyInfo, typeof(IgnoreVarianceAttribute)) ||
                    HasIgnoreVarianceAttribute(metadataClassPropertyInfo.DeclaringType));
        }

        /// <summary>
        /// Check if any property of a given Type array contains IgnoreVarianceAttribute
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        internal static bool HasIgnoreVarianceAttribute(params Type[] type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            return type.Any(t => Attribute.IsDefined(t, typeof(IgnoreVarianceAttribute)));
        }

        internal static IEnumerable<PropertyInfo> GetPropertyInfos(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            // Skip indexers using p.GetIndexParameters().Length == 0
            return
                type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => p.CanRead && p.GetIndexParameters().Length == 0);
        }

        /// <summary>
        /// Convert item of type <typeparam name="T">T</typeparam> to IEnumerable&lt;<typeparam name="T">T</typeparam>&gt;
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        internal static IEnumerable<T> Yield<T>(this T item)
        {
            if (ReferenceEquals(item, null))
            {
                throw new ArgumentNullException("item");
            }

            yield return item;
        }

        /// <summary>
        /// Returns true if Type of obj is string, DateTime, or obj.GetType().IsPrimitive returns true
        /// </summary>
        /// <param name="objs"></param>
        /// <returns></returns>
        internal static bool ShouldIgnoreVariance(params object[] objs)
        {
            return objs != null && objs.All(o => !ReferenceEquals(o, null) && (o is string || o is DateTime || o.GetType().IsPrimitive));
        }
    }
}
<commit_msg>Use LINQ query syntax instead of method syntax. Update comments.<commit_after>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Voyagers.Utilities.ObjectComparer.Attributes;

namespace Voyagers.Utilities.ObjectComparer
{
    internal static class ReflectionHelper
    {
        /// <summary>
        /// Returns if <param name="type">type</param> 
        /// implements IEnumerable&lt;T&gt;, and <param name="genericArgument"></param> containing 
        /// the generic argument of IEnumerable&lt;T&gt;
        /// </summary>
        /// <param name="type"></param>
        /// <param name="genericArgument">out parameter containing the type argument of IEnumerable&lt;T&gt;</param>
        /// <returns></returns>
        internal static bool TryGetIEnumerableGenericArgument(Type type, out Type genericArgument)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            // Check whether type implements IEnumerable<T> first
            Type ienumerableType = type.GetInterfaces()
                                       .FirstOrDefault(
                                           interfaceType =>
                                           interfaceType.IsGenericType &&
                                           interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
            genericArgument = ienumerableType != null ? ienumerableType.GetGenericArguments()[0] : null;
            return genericArgument != null;
        }

        /// <summary>
        /// Returns true if any members of<param name="type">type</param> contain the KeyAttribute
        /// </summary>
        /// <param name="type"></param>
        /// <param name="propertyInfos">out parameter of PropertyInfos containing all properties with KeyAttribute</param>
        /// <returns></returns>
        internal static bool TryGetKeyAttriubte(Type type, out IEnumerable<PropertyInfo> propertyInfos)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            propertyInfos = from prop in GetPropertyInfos(type)
                            where Attribute.IsDefined(prop, typeof(KeyAttribute))
                            select prop;
            if (propertyInfos.Any())
            {
                return true;
            }

            // KeyAttribute is not declared on the type, search for MetadataTypeAttribute
            var metadataTypeAttributes =
                (MetadataTypeAttribute[])type.GetCustomAttributes(typeof(MetadataTypeAttribute));
            if (!metadataTypeAttributes.Any())
            {
                return false;
            }

            // MetadataAttribute exists on the type, find its metadata class and check if KeyAttribute exists
            // on any properties in the metadata class
            propertyInfos = from metadataTypeAttribute in metadataTypeAttributes
                            let metadataClassType = metadataTypeAttribute.MetadataClassType
                            from propertyInfo in GetPropertyInfos(metadataClassType)
                            let metadataClassPropertyInfo = metadataClassType.GetProperty(propertyInfo.Name)
                            where Attribute.IsDefined(metadataClassPropertyInfo, typeof(KeyAttribute))
                            select metadataClassPropertyInfo;

            return propertyInfos.Any();
        }

        internal static bool HasIgnoreVarianceAttribute(params PropertyInfo[] propertyInfos)
        {
            if (propertyInfos == null)
            {
                throw new ArgumentNullException("propertyInfos");
            }

            // Two scenarios here:
            // 1. IgnoreVarianceAttribute is applied on the property of the containing class
            // 2. IgnoreVarianceAttirubte is applied on the declaring type of the property
            if (propertyInfos.Any(pi => Attribute.IsDefined(pi, typeof(IgnoreVarianceAttribute)) ||
                                        HasIgnoreVarianceAttribute(pi.DeclaringType)))
            {
                return true;
            }

            // IgnoreVarianceAttribute is not declared on the type, search for MetadataTypeAttribute
            // Look for propertyInfos in the metadata class, if a metadata class exists
            var metadataPropertyInfos = (from propertyInfo in propertyInfos
                                         let metadataTypeAttributes =
                                             (MetadataTypeAttribute[])
                                             propertyInfo.DeclaringType.GetCustomAttributes(
                                                 typeof(MetadataTypeAttribute))
                                         where metadataTypeAttributes.Any()
                                         let metadataProperty =
                                             metadataTypeAttributes[0].MetadataClassType.GetProperty(propertyInfo.Name)
                                         where metadataProperty != null
                                         select metadataProperty).ToList();

            // No propertyInfos exist, because no metadata classes exist
            if (!metadataPropertyInfos.Any())
            {
                return false;
            }

            return (from metadataPropertyInfo in metadataPropertyInfos
                    where
                        Attribute.IsDefined(metadataPropertyInfo, typeof(IgnoreVarianceAttribute)) ||
                        HasIgnoreVarianceAttribute(metadataPropertyInfo.DeclaringType)
                    select metadataPropertyInfo).Any();
        }

        /// <summary>
        /// Check if any property of a given Type array contains IgnoreVarianceAttribute
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        internal static bool HasIgnoreVarianceAttribute(params Type[] type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            return type.Any(t => Attribute.IsDefined(t, typeof(IgnoreVarianceAttribute)));
        }

        internal static IEnumerable<PropertyInfo> GetPropertyInfos(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            // Skip indexers using p.GetIndexParameters().Length == 0
            return from prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                   where prop.CanRead && prop.GetIndexParameters().Length == 0
                   select prop;
        }

        /// <summary>
        /// Convert item of type <typeparam name="T">T</typeparam> to IEnumerable&lt;<typeparam name="T">T</typeparam>&gt;
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        internal static IEnumerable<T> Yield<T>(this T item)
        {
            if (ReferenceEquals(item, null))
            {
                throw new ArgumentNullException("item");
            }

            yield return item;
        }

        /// <summary>
        /// Returns true if Type of obj is string, DateTime, or obj.GetType().IsPrimitive returns true
        /// </summary>
        /// <param name="objs"></param>
        /// <returns></returns>
        internal static bool ShouldIgnoreVariance(params object[] objs)
        {
            return objs != null &&
                   objs.All(o => !ReferenceEquals(o, null) && (o is string || o is DateTime || o.GetType().IsPrimitive));
        }
    }
}

{'fraction_non_alphanumeric': 0.08778250900753358, 'fraction_numerical': 0.0007861120209629873, 'mean_word_length': 1.627991048373214, 'pattern_counts': {'":': 0, '<': 107, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 52, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2976048', 'n_tokens_mistral': 3300, 'n_tokens_neox': 3207, 'n_words': 846}