[Add] FishNet
This commit is contained in:
@@ -0,0 +1,386 @@
|
||||
//
|
||||
// Author:
|
||||
// Jb Evain (jbevain@gmail.com)
|
||||
//
|
||||
// Copyright (c) 2008 - 2015 Jb Evain
|
||||
// Copyright (c) 2008 - 2011 Novell, Inc.
|
||||
//
|
||||
// Licensed under the MIT/X11 license.
|
||||
//
|
||||
|
||||
using MonoFN.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace MonoFN.Cecil
|
||||
{
|
||||
public interface IAssemblyResolver : IDisposable
|
||||
{
|
||||
AssemblyDefinition Resolve(AssemblyNameReference name);
|
||||
AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters);
|
||||
}
|
||||
|
||||
public interface IMetadataResolver
|
||||
{
|
||||
TypeDefinition Resolve(TypeReference type);
|
||||
FieldDefinition Resolve(FieldReference field);
|
||||
MethodDefinition Resolve(MethodReference method);
|
||||
}
|
||||
|
||||
#if !NET_CORE
|
||||
[Serializable]
|
||||
#endif
|
||||
public sealed class ResolutionException : Exception
|
||||
{
|
||||
public MemberReference Member { get; }
|
||||
public IMetadataScope Scope
|
||||
{
|
||||
get
|
||||
{
|
||||
TypeReference type = Member as TypeReference;
|
||||
if (type != null)
|
||||
return type.Scope;
|
||||
|
||||
TypeReference declaring_type = Member.DeclaringType;
|
||||
if (declaring_type != null)
|
||||
return declaring_type.Scope;
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public ResolutionException(MemberReference member) : base("Failed to resolve " + member.FullName)
|
||||
{
|
||||
if (member == null)
|
||||
throw new ArgumentNullException("member");
|
||||
|
||||
this.Member = member;
|
||||
}
|
||||
|
||||
public ResolutionException(MemberReference member, Exception innerException) : base("Failed to resolve " + member.FullName, innerException)
|
||||
{
|
||||
if (member == null)
|
||||
throw new ArgumentNullException("member");
|
||||
|
||||
this.Member = member;
|
||||
}
|
||||
|
||||
#if !NET_CORE
|
||||
private ResolutionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
#endif
|
||||
}
|
||||
|
||||
public class MetadataResolver : IMetadataResolver
|
||||
{
|
||||
public IAssemblyResolver AssemblyResolver { get; }
|
||||
|
||||
public MetadataResolver(IAssemblyResolver assemblyResolver)
|
||||
{
|
||||
if (assemblyResolver == null)
|
||||
throw new ArgumentNullException("assemblyResolver");
|
||||
|
||||
AssemblyResolver = assemblyResolver;
|
||||
}
|
||||
|
||||
public virtual TypeDefinition Resolve(TypeReference type)
|
||||
{
|
||||
Mixin.CheckType(type);
|
||||
|
||||
type = type.GetElementType();
|
||||
|
||||
IMetadataScope scope = type.Scope;
|
||||
|
||||
if (scope == null)
|
||||
return null;
|
||||
|
||||
switch (scope.MetadataScopeType)
|
||||
{
|
||||
case MetadataScopeType.AssemblyNameReference:
|
||||
AssemblyDefinition assembly = AssemblyResolver.Resolve((AssemblyNameReference)scope);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
|
||||
return GetType(assembly.MainModule, type);
|
||||
case MetadataScopeType.ModuleDefinition:
|
||||
return GetType((ModuleDefinition)scope, type);
|
||||
case MetadataScopeType.ModuleReference:
|
||||
if (type.Module.Assembly == null)
|
||||
return null;
|
||||
|
||||
Collection<ModuleDefinition> modules = type.Module.Assembly.Modules;
|
||||
ModuleReference module_ref = (ModuleReference)scope;
|
||||
for (int i = 0; i < modules.Count; i++)
|
||||
{
|
||||
ModuleDefinition netmodule = modules[i];
|
||||
if (netmodule.Name == module_ref.Name)
|
||||
return GetType(netmodule, type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private static TypeDefinition GetType(ModuleDefinition module, TypeReference reference)
|
||||
{
|
||||
TypeDefinition type = GetTypeDefinition(module, reference);
|
||||
if (type != null)
|
||||
return type;
|
||||
|
||||
if (!module.HasExportedTypes)
|
||||
return null;
|
||||
|
||||
Collection<ExportedType> exported_types = module.ExportedTypes;
|
||||
|
||||
for (int i = 0; i < exported_types.Count; i++)
|
||||
{
|
||||
ExportedType exported_type = exported_types[i];
|
||||
if (exported_type.Name != reference.Name)
|
||||
continue;
|
||||
|
||||
if (exported_type.Namespace != reference.Namespace)
|
||||
continue;
|
||||
|
||||
return exported_type.Resolve();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TypeDefinition GetTypeDefinition(ModuleDefinition module, TypeReference type)
|
||||
{
|
||||
if (!type.IsNested)
|
||||
return module.GetType(type.Namespace, type.Name);
|
||||
|
||||
TypeDefinition declaring_type = type.DeclaringType.Resolve();
|
||||
if (declaring_type == null)
|
||||
return null;
|
||||
|
||||
return declaring_type.GetNestedType(type.TypeFullName());
|
||||
}
|
||||
|
||||
public virtual FieldDefinition Resolve(FieldReference field)
|
||||
{
|
||||
Mixin.CheckField(field);
|
||||
|
||||
TypeDefinition type = Resolve(field.DeclaringType);
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
if (!type.HasFields)
|
||||
return null;
|
||||
|
||||
return GetField(type, field);
|
||||
}
|
||||
|
||||
private FieldDefinition GetField(TypeDefinition type, FieldReference reference)
|
||||
{
|
||||
while (type != null)
|
||||
{
|
||||
FieldDefinition field = GetField(type.Fields, reference);
|
||||
if (field != null)
|
||||
return field;
|
||||
|
||||
if (type.BaseType == null)
|
||||
return null;
|
||||
|
||||
type = Resolve(type.BaseType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static FieldDefinition GetField(Collection<FieldDefinition> fields, FieldReference reference)
|
||||
{
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
FieldDefinition field = fields[i];
|
||||
|
||||
if (field.Name != reference.Name)
|
||||
continue;
|
||||
|
||||
if (!AreSame(field.FieldType, reference.FieldType))
|
||||
continue;
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual MethodDefinition Resolve(MethodReference method)
|
||||
{
|
||||
Mixin.CheckMethod(method);
|
||||
|
||||
TypeDefinition type = Resolve(method.DeclaringType);
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
method = method.GetElementMethod();
|
||||
|
||||
if (!type.HasMethods)
|
||||
return null;
|
||||
|
||||
return GetMethod(type, method);
|
||||
}
|
||||
|
||||
private MethodDefinition GetMethod(TypeDefinition type, MethodReference reference)
|
||||
{
|
||||
while (type != null)
|
||||
{
|
||||
MethodDefinition method = GetMethod(type.Methods, reference);
|
||||
if (method != null)
|
||||
return method;
|
||||
|
||||
if (type.BaseType == null)
|
||||
return null;
|
||||
|
||||
type = Resolve(type.BaseType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodDefinition GetMethod(Collection<MethodDefinition> methods, MethodReference reference)
|
||||
{
|
||||
for (int i = 0; i < methods.Count; i++)
|
||||
{
|
||||
MethodDefinition method = methods[i];
|
||||
|
||||
if (method.Name != reference.Name)
|
||||
continue;
|
||||
|
||||
if (method.HasGenericParameters != reference.HasGenericParameters)
|
||||
continue;
|
||||
|
||||
if (method.HasGenericParameters && method.GenericParameters.Count != reference.GenericParameters.Count)
|
||||
continue;
|
||||
|
||||
if (!AreSame(method.ReturnType, reference.ReturnType))
|
||||
continue;
|
||||
|
||||
if (method.IsVarArg() != reference.IsVarArg())
|
||||
continue;
|
||||
|
||||
if (method.IsVarArg() && IsVarArgCallTo(method, reference))
|
||||
return method;
|
||||
|
||||
if (method.HasParameters != reference.HasParameters)
|
||||
continue;
|
||||
|
||||
if (!method.HasParameters && !reference.HasParameters)
|
||||
return method;
|
||||
|
||||
if (!AreSame(method.Parameters, reference.Parameters))
|
||||
continue;
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool AreSame(Collection<ParameterDefinition> a, Collection<ParameterDefinition> b)
|
||||
{
|
||||
int count = a.Count;
|
||||
|
||||
if (count != b.Count)
|
||||
return false;
|
||||
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
if (!AreSame(a[i].ParameterType, b[i].ParameterType))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsVarArgCallTo(MethodDefinition method, MethodReference reference)
|
||||
{
|
||||
if (method.Parameters.Count >= reference.Parameters.Count)
|
||||
return false;
|
||||
|
||||
if (reference.GetSentinelPosition() != method.Parameters.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < method.Parameters.Count; i++)
|
||||
if (!AreSame(method.Parameters[i].ParameterType, reference.Parameters[i].ParameterType))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool AreSame(TypeSpecification a, TypeSpecification b)
|
||||
{
|
||||
if (!AreSame(a.ElementType, b.ElementType))
|
||||
return false;
|
||||
|
||||
if (a.IsGenericInstance)
|
||||
return AreSame((GenericInstanceType)a, (GenericInstanceType)b);
|
||||
|
||||
if (a.IsRequiredModifier || a.IsOptionalModifier)
|
||||
return AreSame((IModifierType)a, (IModifierType)b);
|
||||
|
||||
if (a.IsArray)
|
||||
return AreSame((ArrayType)a, (ArrayType)b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool AreSame(ArrayType a, ArrayType b)
|
||||
{
|
||||
if (a.Rank != b.Rank)
|
||||
return false;
|
||||
|
||||
// TODO: dimensions
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool AreSame(IModifierType a, IModifierType b)
|
||||
{
|
||||
return AreSame(a.ModifierType, b.ModifierType);
|
||||
}
|
||||
|
||||
private static bool AreSame(GenericInstanceType a, GenericInstanceType b)
|
||||
{
|
||||
if (a.GenericArguments.Count != b.GenericArguments.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < a.GenericArguments.Count; i++)
|
||||
if (!AreSame(a.GenericArguments[i], b.GenericArguments[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool AreSame(GenericParameter a, GenericParameter b)
|
||||
{
|
||||
return a.Position == b.Position;
|
||||
}
|
||||
|
||||
private static bool AreSame(TypeReference a, TypeReference b)
|
||||
{
|
||||
if (ReferenceEquals(a, b))
|
||||
return true;
|
||||
|
||||
if (a == null || b == null)
|
||||
return false;
|
||||
|
||||
if (a.etype != b.etype)
|
||||
return false;
|
||||
|
||||
if (a.IsGenericParameter)
|
||||
return AreSame((GenericParameter)a, (GenericParameter)b);
|
||||
|
||||
if (a.IsTypeSpecification())
|
||||
return AreSame((TypeSpecification)a, (TypeSpecification)b);
|
||||
|
||||
if (a.Name != b.Name || a.Namespace != b.Namespace)
|
||||
return false;
|
||||
|
||||
return AreSame(a.DeclaringType, b.DeclaringType);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user