File: Experimental\TypeReferenceSearcher.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 System.Text;
using System.Diagnostics.Contracts;
using System.Collections;
using Microsoft.Cci;
 
namespace Microsoft.Cci.Extensions
{
    public class TypeReferenceDependency
    {
        public TypeReferenceDependency(ITypeReference type, ITypeDefinitionMember member)
        {
            this.TypeReference = type;
            this.DependentMember = member;
            this.DependentType = member.ContainingTypeDefinition;
        }
 
        public TypeReferenceDependency(ITypeReference type, ITypeDefinition typeDef)
        {
            this.TypeReference = type;
            this.DependentMember = null;
            this.DependentType = typeDef;
        }
 
        public ITypeReference TypeReference { get; private set; }
 
        public ITypeDefinitionMember DependentMember { get; private set; }
 
        public ITypeDefinition DependentType { get; private set; }
 
        internal class TypeReferenceDependencyComparer : IEqualityComparer<TypeReferenceDependency>
        {
            public bool Equals(TypeReferenceDependency x, TypeReferenceDependency y)
            {
                return object.Equals(x.TypeReference, y.TypeReference)
                    && object.Equals(x.DependentMember, y.DependentMember)
                    && object.Equals(x.DependentType, y.DependentMember);
            }
 
            public int GetHashCode(TypeReferenceDependency obj)
            {
                return obj.TypeReference.GetHashCode() ^ obj.DependentType.GetHashCode();
            }
        }
    }
 
#pragma warning disable 612,618
    public class TypeReferenceSearcher : BaseMetadataTraverser
#pragma warning restore 612,618
    {
        private Func<ITypeReference, bool> _typePredicate;
        private readonly ICollection<TypeReferenceDependency> _dependencies;
 
        public TypeReferenceSearcher()
        {
            _dependencies = new HashSet<TypeReferenceDependency>(new TypeReferenceDependency.TypeReferenceDependencyComparer());
        }
 
        public ICollection<TypeReferenceDependency> Dependencies { get { return _dependencies; } }
 
        public void Search(Func<ITypeReference, bool> typePredicate, IAssembly assembly)
        {
            _typePredicate = typePredicate;
            _dependencies.Clear();
            this.Visit(assembly);
        }
 
        public override void Visit(INamespaceTypeReference type)
        {
            AddTypeReference(type);
            base.Visit(type);
        }
 
        public override void Visit(INestedTypeReference type)
        {
            AddTypeReference(type);
            base.Visit(type);
        }
        public override void Visit(IPropertyDefinition property)
        {
            base.Visit(property);
        }
 
        public override void Visit(ITypeDefinition type)
        {
            if (type.IsVisibleOutsideAssembly())
                base.Visit(type);
        }
 
        public override void Visit(ITypeDefinitionMember member)
        {
            if (member.IsVisibleOutsideAssembly())
                base.Visit(member);
        }
 
        public override void Visit(ICustomAttribute attribute)
        {
            //TODO: For now ignore attribute dependencies
            //Visit(attribute.Type); // For some reason the base visitor doesn't visit the attribute type
            //base.Visit(attribute); 
        }
 
        private void AddTypeReference(ITypeReference type)
        {
            Contract.Assert(type == type.UnWrap());
 
            if (_typePredicate(type))
            {
                IPropertyDefinition property = GetCurrent<IPropertyDefinition>();
                if (property != null)
                {
                    if (property.IsVisibleOutsideAssembly())
                    {
                        if (property.Getter != null)
                            _dependencies.Add(new TypeReferenceDependency(type, property.Getter.ResolvedTypeDefinitionMember));
                        if (property.Setter != null)
                            _dependencies.Add(new TypeReferenceDependency(type, property.Setter.ResolvedTypeDefinitionMember));
                    }
                }
 
                ITypeDefinitionMember member = GetCurrent<ITypeDefinitionMember>();
                if (member != null)
                {
                    if (member.IsVisibleOutsideAssembly())
                        _dependencies.Add(new TypeReferenceDependency(type, member));
 
                    return;
                }
 
                ITypeDefinition typeDef = GetCurrentType();
                if (typeDef != null)
                {
                    if (typeDef.IsVisibleOutsideAssembly())
                        _dependencies.Add(new TypeReferenceDependency(type, typeDef));
                    return;
                }
            }
        }
 
        private T GetCurrent<T>() where T : class
        {
            foreach (var p in path)
            {
                var type = p as T;
 
                if (type != null)
                    return type;
            }
            return null;
        }
 
        private ITypeDefinition GetCurrentType()
        {
            foreach (var p in path)
            {
                var type = p as ITypeDefinition;
 
                // We want to skip over generic parameter types
                if (type != null && !(type is IGenericParameter))
                    return type;
            }
            return null;
        }
    }
}