a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
432 lines
13 KiB
C#
432 lines
13 KiB
C#
//
|
|
// ReflectionHelper.cs
|
|
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// (C) 2005 Jb Evain
|
|
// (C) 2006 Evaluant RC S.A.
|
|
// (C) 2007 Jb Evain
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
namespace Mono.Cecil {
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using SR = System.Reflection;
|
|
using System.Text;
|
|
|
|
internal sealed class ReflectionHelper {
|
|
|
|
ModuleDefinition m_module;
|
|
|
|
public ReflectionHelper (ModuleDefinition module)
|
|
{
|
|
m_module = module;
|
|
}
|
|
|
|
public AssemblyNameReference ImportAssembly (SR.Assembly asm)
|
|
{
|
|
AssemblyNameReference asmRef = GetAssemblyNameReference (asm.GetName ());
|
|
if (asmRef != null)
|
|
return asmRef;
|
|
|
|
SR.AssemblyName asmName = asm.GetName ();
|
|
asmRef = new AssemblyNameReference (
|
|
asmName.Name, asmName.CultureInfo.Name, asmName.Version);
|
|
asmRef.PublicKeyToken = asmName.GetPublicKeyToken ();
|
|
asmRef.HashAlgorithm = (AssemblyHashAlgorithm) asmName.HashAlgorithm;
|
|
asmRef.Culture = asmName.CultureInfo.ToString ();
|
|
m_module.AssemblyReferences.Add (asmRef);
|
|
return asmRef;
|
|
}
|
|
|
|
AssemblyNameReference GetAssemblyNameReference (SR.AssemblyName name)
|
|
{
|
|
foreach (AssemblyNameReference reference in m_module.AssemblyReferences)
|
|
if (reference.FullName == name.FullName)
|
|
return reference;
|
|
|
|
return null;
|
|
}
|
|
|
|
public static string GetTypeSignature (Type t)
|
|
{
|
|
if (t.HasElementType) {
|
|
if (t.IsPointer)
|
|
return string.Concat (GetTypeSignature (t.GetElementType ()), "*");
|
|
else if (t.IsArray) {
|
|
int rank = t.GetArrayRank ();
|
|
if (rank == 1)
|
|
return string.Concat (GetTypeSignature (t.GetElementType ()), "[]");
|
|
|
|
StringBuilder sb = new StringBuilder ();
|
|
sb.Append ('[');
|
|
for (int i = 1; i < rank; i++)
|
|
sb.Append (',');
|
|
sb.Append (']');
|
|
|
|
return string.Concat (GetTypeSignature (t.GetElementType ()), sb.ToString ());
|
|
} else if (t.IsByRef)
|
|
return string.Concat(GetTypeSignature(t.GetElementType()), "&");
|
|
}
|
|
|
|
if (IsGenericTypeSpec (t)) {
|
|
StringBuilder sb = new StringBuilder ();
|
|
sb.Append (GetTypeSignature (GetGenericTypeDefinition (t)));
|
|
sb.Append ("<");
|
|
Type [] genArgs = GetGenericArguments (t);
|
|
for (int i = 0; i < genArgs.Length; i++) {
|
|
if (i > 0)
|
|
sb.Append (",");
|
|
sb.Append (GetTypeSignature (genArgs [i]));
|
|
}
|
|
sb.Append (">");
|
|
return sb.ToString ();
|
|
}
|
|
|
|
if (IsGenericParameter (t))
|
|
return t.Name;
|
|
|
|
if (t.DeclaringType != null)
|
|
return string.Concat (t.DeclaringType.FullName, "/", t.Name);
|
|
|
|
if (t.Namespace == null || t.Namespace.Length == 0)
|
|
return t.Name;
|
|
|
|
return string.Concat (t.Namespace, ".", t.Name);
|
|
}
|
|
|
|
static bool GetProperty (object o, string prop)
|
|
{
|
|
SR.PropertyInfo pi = o.GetType ().GetProperty (prop);
|
|
if (pi == null)
|
|
return false;
|
|
|
|
return (bool) pi.GetValue (o, null);
|
|
}
|
|
|
|
public static bool IsGenericType (Type t)
|
|
{
|
|
return GetProperty (t, "IsGenericType");
|
|
}
|
|
|
|
static bool IsGenericParameter (Type t)
|
|
{
|
|
return GetProperty (t, "IsGenericParameter");
|
|
}
|
|
|
|
static bool IsGenericTypeDefinition (Type t)
|
|
{
|
|
return GetProperty (t, "IsGenericTypeDefinition");
|
|
}
|
|
|
|
static bool IsGenericTypeSpec (Type t)
|
|
{
|
|
return IsGenericType (t) && !IsGenericTypeDefinition (t);
|
|
}
|
|
|
|
static Type GetGenericTypeDefinition (Type t)
|
|
{
|
|
return (Type) t.GetType ().GetMethod ("GetGenericTypeDefinition").Invoke (t, null);
|
|
}
|
|
|
|
static Type [] GetGenericArguments (Type t)
|
|
{
|
|
return (Type []) t.GetType ().GetMethod ("GetGenericArguments").Invoke (t, null);
|
|
}
|
|
|
|
GenericInstanceType GetGenericType (Type t, TypeReference element, ImportContext context)
|
|
{
|
|
GenericInstanceType git = new GenericInstanceType (element);
|
|
foreach (Type genArg in GetGenericArguments (t))
|
|
git.GenericArguments.Add (ImportSystemType (genArg, context));
|
|
|
|
return git;
|
|
}
|
|
|
|
static bool GenericParameterOfMethod (Type t)
|
|
{
|
|
return t.GetType ().GetProperty ("DeclaringMethod").GetValue (t, null) != null;
|
|
}
|
|
|
|
static GenericParameter GetGenericParameter (Type t, ImportContext context)
|
|
{
|
|
int pos = (int) t.GetType ().GetProperty ("GenericParameterPosition").GetValue (t, null);
|
|
IGenericParameterProvider provider;
|
|
if (GenericParameterOfMethod (t))
|
|
provider = context.GenericContext.Method;
|
|
else
|
|
provider = context.GenericContext.Type;
|
|
|
|
if (provider == null)
|
|
throw new InvalidOperationException ("Invalid context");
|
|
|
|
return provider.GenericParameters [pos];
|
|
}
|
|
|
|
TypeReference GetTypeSpec (Type t, ImportContext context)
|
|
{
|
|
Stack s = new Stack ();
|
|
while (t.HasElementType || IsGenericTypeSpec (t)) {
|
|
s.Push (t);
|
|
if (t.HasElementType)
|
|
t = t.GetElementType ();
|
|
else if (IsGenericTypeSpec (t)) {
|
|
t = (Type) t.GetType ().GetMethod ("GetGenericTypeDefinition").Invoke (t, null);
|
|
break;
|
|
}
|
|
}
|
|
|
|
TypeReference elementType = ImportSystemType (t, context);
|
|
while (s.Count > 0) {
|
|
t = (Type) s.Pop ();
|
|
if (t.IsPointer)
|
|
elementType = new PointerType (elementType);
|
|
else if (t.IsArray)
|
|
elementType = new ArrayType (elementType, t.GetArrayRank ());
|
|
else if (t.IsByRef)
|
|
elementType = new ReferenceType (elementType);
|
|
else if (IsGenericTypeSpec (t))
|
|
elementType = GetGenericType (t, elementType, context);
|
|
else
|
|
throw new ReflectionException ("Unknown element type");
|
|
}
|
|
|
|
return elementType;
|
|
}
|
|
|
|
TypeReference AdjustReference (Type type, TypeReference reference)
|
|
{
|
|
if (type.IsValueType && !reference.IsValueType)
|
|
reference.IsValueType = true;
|
|
|
|
if (IsGenericTypeDefinition (type)) {
|
|
Type [] parameters = GetGenericArguments (type);
|
|
for (int i = reference.GenericParameters.Count; i < parameters.Length; i++)
|
|
reference.GenericParameters.Add (new GenericParameter (i, reference));
|
|
}
|
|
|
|
return reference;
|
|
}
|
|
|
|
public TypeReference ImportSystemType (Type t, ImportContext context)
|
|
{
|
|
if (t.HasElementType || IsGenericTypeSpec (t))
|
|
return GetTypeSpec (t, context);
|
|
|
|
if (IsGenericParameter (t))
|
|
return GetGenericParameter (t, context);
|
|
|
|
TypeReference type = m_module.TypeReferences [GetTypeSignature (t)];
|
|
if (type != null)
|
|
return AdjustReference (t, type);
|
|
|
|
AssemblyNameReference asm = ImportAssembly (t.Assembly);
|
|
if (t.DeclaringType != null) {
|
|
type = new TypeReference (t.Name, string.Empty, asm, t.IsValueType);
|
|
type.DeclaringType = ImportSystemType (t.DeclaringType, context);
|
|
} else
|
|
type = new TypeReference (t.Name, t.Namespace, asm, t.IsValueType);
|
|
|
|
if (IsGenericTypeDefinition (t))
|
|
foreach (Type genParam in GetGenericArguments (t))
|
|
type.GenericParameters.Add (new GenericParameter (genParam.Name, type));
|
|
|
|
context.GenericContext.Type = type;
|
|
|
|
m_module.TypeReferences.Add (type);
|
|
return type;
|
|
}
|
|
|
|
static string GetMethodBaseSignature (SR.MethodBase meth, Type declaringType, Type retType)
|
|
{
|
|
StringBuilder sb = new StringBuilder ();
|
|
sb.Append (GetTypeSignature (retType));
|
|
sb.Append (' ');
|
|
sb.Append (GetTypeSignature (declaringType));
|
|
sb.Append ("::");
|
|
sb.Append (meth.Name);
|
|
if (IsGenericMethodSpec (meth)) {
|
|
sb.Append ("<");
|
|
Type [] genArgs = GetGenericArguments (meth as SR.MethodInfo);
|
|
for (int i = 0; i < genArgs.Length; i++) {
|
|
if (i > 0)
|
|
sb.Append (",");
|
|
sb.Append (GetTypeSignature (genArgs [i]));
|
|
}
|
|
sb.Append (">");
|
|
}
|
|
sb.Append ("(");
|
|
SR.ParameterInfo [] parameters = meth.GetParameters ();
|
|
for (int i = 0; i < parameters.Length; i++) {
|
|
if (i > 0)
|
|
sb.Append (",");
|
|
sb.Append (GetTypeSignature (parameters [i].ParameterType));
|
|
}
|
|
sb.Append (")");
|
|
return sb.ToString ();
|
|
}
|
|
|
|
static bool IsGenericMethod (SR.MethodBase mb)
|
|
{
|
|
return GetProperty (mb, "IsGenericMethod");
|
|
}
|
|
|
|
static bool IsGenericMethodDefinition (SR.MethodBase mb)
|
|
{
|
|
return GetProperty (mb, "IsGenericMethodDefinition");
|
|
}
|
|
|
|
static bool IsGenericMethodSpec (SR.MethodBase mb)
|
|
{
|
|
return IsGenericMethod (mb) && !IsGenericMethodDefinition (mb);
|
|
}
|
|
|
|
static Type [] GetGenericArguments (SR.MethodInfo mi)
|
|
{
|
|
return (Type []) mi.GetType ().GetMethod ("GetGenericArguments").Invoke (mi, null);
|
|
}
|
|
|
|
static int GetMetadataToken (SR.MethodInfo mi)
|
|
{
|
|
return (int) mi.GetType ().GetProperty ("MetadataToken").GetValue (mi, null);
|
|
}
|
|
|
|
MethodReference ImportGenericInstanceMethod (SR.MethodInfo mi, ImportContext context)
|
|
{
|
|
SR.MethodInfo gmd = (SR.MethodInfo) mi.GetType ().GetMethod ("GetGenericMethodDefinition").Invoke (mi, null);
|
|
GenericInstanceMethod gim = new GenericInstanceMethod (
|
|
ImportMethodBase (gmd, gmd.ReturnType, context));
|
|
|
|
foreach (Type genArg in GetGenericArguments (mi))
|
|
gim.GenericArguments.Add (ImportSystemType (genArg, context));
|
|
|
|
return gim;
|
|
}
|
|
|
|
MethodReference ImportMethodBase (SR.MethodBase mb, Type retType, ImportContext context)
|
|
{
|
|
if (IsGenericMethod (mb) && !IsGenericMethodDefinition (mb))
|
|
return ImportGenericInstanceMethod ((SR.MethodInfo) mb, context);
|
|
|
|
Type originalDecType = mb.DeclaringType;
|
|
Type declaringTypeDef = originalDecType;
|
|
while (IsGenericTypeSpec (declaringTypeDef))
|
|
declaringTypeDef = GetGenericTypeDefinition (declaringTypeDef);
|
|
|
|
if (mb.DeclaringType != declaringTypeDef && mb is SR.MethodInfo) {
|
|
int mt = GetMetadataToken (mb as SR.MethodInfo);
|
|
// hack to get the generic method definition from the constructed method
|
|
foreach (SR.MethodInfo mi in declaringTypeDef.GetMethods ()) {
|
|
if (GetMetadataToken (mi) == mt) {
|
|
mb = mi;
|
|
retType = mi.ReturnType;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
string sig = GetMethodBaseSignature (mb, originalDecType, retType);
|
|
MethodReference meth = (MethodReference) GetMemberReference (sig);
|
|
if (meth != null)
|
|
return meth;
|
|
|
|
meth = new MethodReference (
|
|
mb.Name,
|
|
(mb.CallingConvention & SR.CallingConventions.HasThis) > 0,
|
|
(mb.CallingConvention & SR.CallingConventions.ExplicitThis) > 0,
|
|
MethodCallingConvention.Default); // TODO: get the real callconv
|
|
meth.DeclaringType = ImportSystemType (originalDecType, context);
|
|
|
|
if (IsGenericMethod (mb))
|
|
foreach (Type genParam in GetGenericArguments (mb as SR.MethodInfo))
|
|
meth.GenericParameters.Add (new GenericParameter (genParam.Name, meth));
|
|
|
|
TypeReference contextType = context.GenericContext.Type;
|
|
MethodReference contextMethod = context.GenericContext.Method;
|
|
|
|
context.GenericContext.Method = meth;
|
|
context.GenericContext.Type = ImportSystemType (declaringTypeDef, context);
|
|
|
|
meth.ReturnType.ReturnType = ImportSystemType (retType, context);
|
|
|
|
SR.ParameterInfo [] parameters = mb.GetParameters ();
|
|
for (int i = 0; i < parameters.Length; i++)
|
|
meth.Parameters.Add (new ParameterDefinition (
|
|
ImportSystemType (parameters [i].ParameterType, context)));
|
|
|
|
context.GenericContext.Type = contextType;
|
|
context.GenericContext.Method = contextMethod;
|
|
|
|
m_module.MemberReferences.Add (meth);
|
|
return meth;
|
|
}
|
|
|
|
public MethodReference ImportConstructorInfo (SR.ConstructorInfo ci, ImportContext context)
|
|
{
|
|
return ImportMethodBase (ci, typeof (void), context);
|
|
}
|
|
|
|
public MethodReference ImportMethodInfo (SR.MethodInfo mi, ImportContext context)
|
|
{
|
|
return ImportMethodBase (mi, mi.ReturnType, context);
|
|
}
|
|
|
|
static string GetFieldSignature (SR.FieldInfo field)
|
|
{
|
|
StringBuilder sb = new StringBuilder ();
|
|
sb.Append (GetTypeSignature (field.FieldType));
|
|
sb.Append (' ');
|
|
sb.Append (GetTypeSignature (field.DeclaringType));
|
|
sb.Append ("::");
|
|
sb.Append (field.Name);
|
|
return sb.ToString ();
|
|
}
|
|
|
|
public FieldReference ImportFieldInfo (SR.FieldInfo fi, ImportContext context)
|
|
{
|
|
string sig = GetFieldSignature (fi);
|
|
FieldReference f = (FieldReference) GetMemberReference (sig);
|
|
if (f != null)
|
|
return f;
|
|
|
|
f = new FieldReference (
|
|
fi.Name,
|
|
ImportSystemType (fi.DeclaringType, context),
|
|
ImportSystemType (fi.FieldType, context));
|
|
|
|
m_module.MemberReferences.Add (f);
|
|
return f;
|
|
}
|
|
|
|
MemberReference GetMemberReference (string signature)
|
|
{
|
|
foreach (MemberReference reference in m_module.MemberReferences)
|
|
if (reference.ToString () == signature)
|
|
return reference;
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|