File: Traversers\SimpleTypeMemberTraverser.cs
Web Access
Project: src\src\Microsoft.Cci.Extensions\Microsoft.Cci.Extensions.csproj (Microsoft.Cci.Extensions)
// 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 System.Linq;
using Microsoft.Cci.Extensions;
using Microsoft.Cci.Filters;
 
namespace Microsoft.Cci.Traversers
{
    public class SimpleTypeMemberTraverser
    {
        private readonly ICciFilter _filter;
 
        public SimpleTypeMemberTraverser(ICciFilter filter)
        {
            _filter = filter ?? new IncludeAllFilter();
        }
 
        public ICciFilter Filter { get { return _filter; } }
 
        public bool IncludeForwardedTypes { get; set; }
 
        public virtual void Visit(IEnumerable<IAssembly> assemblies)
        {
            foreach (var assembly in assemblies)
                Visit(assembly);
        }
 
        public virtual void Visit(IAssembly assembly)
        {
            Visit(assembly.GetAllNamespaces());
        }
 
        public virtual void Visit(IEnumerable<INamespaceDefinition> namespaces)
        {
            namespaces = namespaces.Where(_filter.Include);
            namespaces = namespaces.Where(ns => ns.GetTypes(this.IncludeForwardedTypes).Any(_filter.Include));
            namespaces = namespaces.OrderBy(GetNamespaceKey, StringComparer.OrdinalIgnoreCase);
 
            foreach (var ns in namespaces)
                Visit(ns);
        }
 
        public virtual string GetNamespaceKey(INamespaceDefinition ns)
        {
            return ns.UniqueId();
        }
 
        public virtual void Visit(INamespaceDefinition ns)
        {
            Visit(ns.GetTypes(this.IncludeForwardedTypes));
        }
 
        public virtual void Visit(IEnumerable<ITypeDefinition> types)
        {
            types = types.Where(_filter.Include);
            types = types.OrderBy(GetTypeKey, StringComparer.OrdinalIgnoreCase);
 
            foreach (var type in types)
                Visit(type);
        }
 
        public virtual string GetTypeKey(ITypeDefinition type)
        {
            return type.UniqueId();
        }
 
        public virtual void Visit(ITypeDefinition type)
        {
            Visit(type, type.Fields);
            Visit(type.Methods.Where(m => m.IsConstructor));
            Visit(type.Properties);
            Visit(type.Events);
            Visit(type.Methods.Where(m => !m.IsConstructor));
            Visit((IEnumerable<ITypeDefinition>)type.NestedTypes);
        }
 
        public virtual void Visit(IEnumerable<ITypeDefinitionMember> members)
        {
            // We don't want to apply a different sort order if one already exists
            // and instead want to apply it in addition to the current sort order.
            //
            // This can happen for enums, as an example, where we want to prefer numeric
            // order rather than the default alphabetical order.
 
            if (members is IOrderedEnumerable<ITypeDefinitionMember> orderedTypeDefinitionMembers)
            {
                members = orderedTypeDefinitionMembers.ThenBy(GetMemberKey, StringComparer.OrdinalIgnoreCase);
            }
            else if (members is IOrderedEnumerable<IFieldDefinition> orderedFieldDefinitionMembers)
            {
                // This is required due to IOrderedEnumerable being covariant on .NET Core, but not on .NET Framework
                members = orderedFieldDefinitionMembers.ThenBy(GetMemberKey, StringComparer.OrdinalIgnoreCase);
            }
            else
            {
                members = members.OrderBy(GetMemberKey, StringComparer.OrdinalIgnoreCase);
            }
            members = members.Where(_filter.Include);
 
            foreach (var member in members)
                Visit(member);
        }
 
        public virtual void Visit(ITypeDefinition parentType, IEnumerable<IFieldDefinition> fields)
        {
            if (parentType.IsEnum)
            {
                // Enums are generally sorted in numeric order, rather than alphabetically
                // We will try to do the same here to make it more consistent with the impl
                fields = fields.OrderBy((fieldDefinition) => fieldDefinition.Constant.Value);
            }
            this.Visit((IEnumerable<ITypeDefinitionMember>)fields);
        }
 
        public virtual string GetMemberKey(ITypeDefinitionMember member)
        {
            return member.UniqueId();
        }
 
        public virtual void Visit(ITypeDefinitionMember member)
        {
        }
    }
}