File: Linker\InterfaceImplementor.cs
Web Access
Project: src\src\tools\illink\src\linker\Mono.Linker.csproj (illink)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Mono.Cecil;
 
namespace Mono.Linker
{
	public class InterfaceImplementor
	{
		/// <summary>
		/// The type that implements <see cref="InterfaceImplementor.InterfaceType"/>.
		/// </summary>
		public TypeDefinition Implementor { get; }
		/// <summary>
		/// The .interfaceimpl on <see cref="InterfaceImplementor.Implementor"/>that points to <see cref="InterfaceImplementor.InterfaceType"/>
		/// </summary>
		public InterfaceImplementation InterfaceImplementation { get; }
		/// <summary>
		/// The type of the interface that is implemented by <see cref="InterfaceImplementor.Implementor"/>
		/// </summary>
		public TypeDefinition InterfaceType { get; }
 
		public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType, IMetadataResolver resolver)
		{
			Implementor = implementor;
			InterfaceImplementation = interfaceImplementation;
			InterfaceType = interfaceType;
			Debug.Assert(resolver.Resolve (interfaceImplementation.InterfaceType) == interfaceType);
		}
 
		public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefinition interfaceType, IMetadataResolver resolver)
		{
			foreach(InterfaceImplementation iface in implementor.Interfaces) {
				if (resolver.Resolve(iface.InterfaceType) == interfaceType) {
					return new InterfaceImplementor(implementor, iface, interfaceType, resolver);
				}
			}
 
			Queue<TypeDefinition> ifacesToCheck = new ();
			ifacesToCheck.Enqueue(implementor);
			while (ifacesToCheck.Count > 0) {
				var currentIface = ifacesToCheck.Dequeue ();
 
				foreach(InterfaceImplementation ifaceImpl in currentIface.Interfaces) {
					var iface = resolver.Resolve (ifaceImpl.InterfaceType);
					if (iface == interfaceType) {
						return new InterfaceImplementor(implementor, ifaceImpl, interfaceType, resolver);
					}
					ifacesToCheck.Enqueue (iface);
				}
			}
			throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any interfaces");
		}
	}
}