|
// 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");
}
}
}
|