267 lines
8.6 KiB
C#
267 lines
8.6 KiB
C#
|
//
|
||
|
// DefaultReferenceImporter.cs
|
||
|
//
|
||
|
// Author:
|
||
|
// Jb Evain (jbevain@novell.com)
|
||
|
//
|
||
|
// (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;
|
||
|
|
||
|
internal class DefaultImporter : IImporter {
|
||
|
|
||
|
ModuleDefinition m_module;
|
||
|
|
||
|
public ModuleDefinition Module {
|
||
|
get { return m_module; }
|
||
|
}
|
||
|
|
||
|
public DefaultImporter (ModuleDefinition module)
|
||
|
{
|
||
|
m_module = module;
|
||
|
}
|
||
|
|
||
|
public AssemblyNameReference ImportAssembly (AssemblyNameReference asm)
|
||
|
{
|
||
|
AssemblyNameReference asmRef = GetAssemblyNameReference (asm);
|
||
|
if (asmRef != null)
|
||
|
return asmRef;
|
||
|
|
||
|
asmRef = new AssemblyNameReference (
|
||
|
asm.Name, asm.Culture, asm.Version);
|
||
|
asmRef.PublicKeyToken = asm.PublicKeyToken;
|
||
|
asmRef.HashAlgorithm = asm.HashAlgorithm;
|
||
|
m_module.AssemblyReferences.Add (asmRef);
|
||
|
return asmRef;
|
||
|
}
|
||
|
|
||
|
AssemblyNameReference GetAssemblyNameReference (AssemblyNameReference asm)
|
||
|
{
|
||
|
foreach (AssemblyNameReference reference in m_module.AssemblyReferences)
|
||
|
if (reference.FullName == asm.FullName)
|
||
|
return reference;
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
TypeSpecification GetTypeSpec (TypeSpecification original, ImportContext context)
|
||
|
{
|
||
|
TypeSpecification typeSpec;
|
||
|
|
||
|
TypeReference elementType = ImportTypeReference (original.ElementType, context);
|
||
|
if (original is PointerType) {
|
||
|
typeSpec = new PointerType (elementType);
|
||
|
} else if (original is ArrayType) { // deal with complex arrays
|
||
|
typeSpec = new ArrayType (elementType);
|
||
|
} else if (original is ReferenceType) {
|
||
|
typeSpec = new ReferenceType (elementType);
|
||
|
} else if (original is GenericInstanceType) {
|
||
|
GenericInstanceType git = original as GenericInstanceType;
|
||
|
GenericInstanceType genElemType = new GenericInstanceType (elementType);
|
||
|
|
||
|
context.GenericContext.CheckProvider (genElemType.GetOriginalType (), git.GenericArguments.Count);
|
||
|
foreach (TypeReference arg in git.GenericArguments)
|
||
|
genElemType.GenericArguments.Add (ImportTypeReference (arg, context));
|
||
|
|
||
|
typeSpec = genElemType;
|
||
|
} else if (original is ModifierOptional) {
|
||
|
TypeReference mt = (original as ModifierOptional).ModifierType;
|
||
|
typeSpec = new ModifierOptional (elementType, ImportTypeReference (mt, context));
|
||
|
} else if (original is ModifierRequired) {
|
||
|
TypeReference mt = (original as ModifierRequired).ModifierType;
|
||
|
typeSpec = new ModifierRequired (elementType, ImportTypeReference (mt, context));
|
||
|
} else if (original is SentinelType) {
|
||
|
typeSpec = new SentinelType (elementType);
|
||
|
} else if (original is FunctionPointerType) {
|
||
|
FunctionPointerType ori = original as FunctionPointerType;
|
||
|
|
||
|
FunctionPointerType fnptr = new FunctionPointerType (
|
||
|
ori.HasThis,
|
||
|
ori.ExplicitThis,
|
||
|
ori.CallingConvention,
|
||
|
new MethodReturnType (ImportTypeReference (ori.ReturnType.ReturnType, context)));
|
||
|
|
||
|
foreach (ParameterDefinition parameter in ori.Parameters)
|
||
|
fnptr.Parameters.Add (new ParameterDefinition (ImportTypeReference (parameter.ParameterType, context)));
|
||
|
|
||
|
typeSpec = fnptr;
|
||
|
} else
|
||
|
throw new ReflectionException ("Unknown element type: {0}", original.GetType ().Name);
|
||
|
|
||
|
return typeSpec;
|
||
|
}
|
||
|
|
||
|
static GenericParameter GetGenericParameter (GenericParameter gp, ImportContext context)
|
||
|
{
|
||
|
GenericParameter p;
|
||
|
if (gp.Owner is TypeReference)
|
||
|
p = context.GenericContext.Type.GenericParameters [gp.Position];
|
||
|
else if (gp.Owner is MethodReference)
|
||
|
p = context.GenericContext.Method.GenericParameters [gp.Position];
|
||
|
else
|
||
|
throw new NotSupportedException ();
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
TypeReference AdjustReference (TypeReference type, TypeReference reference)
|
||
|
{
|
||
|
if (type.IsValueType && !reference.IsValueType)
|
||
|
reference.IsValueType = true;
|
||
|
|
||
|
if (type.HasGenericParameters) {
|
||
|
for (int i = reference.GenericParameters.Count; i < type.GenericParameters.Count; i++)
|
||
|
reference.GenericParameters.Add (new GenericParameter (i, reference));
|
||
|
}
|
||
|
|
||
|
return reference;
|
||
|
}
|
||
|
|
||
|
public virtual TypeReference ImportTypeReference (TypeReference t, ImportContext context)
|
||
|
{
|
||
|
if (t.Module == m_module)
|
||
|
return t;
|
||
|
|
||
|
if (t is TypeSpecification)
|
||
|
return GetTypeSpec (t as TypeSpecification, context);
|
||
|
|
||
|
if (t is GenericParameter)
|
||
|
return GetGenericParameter (t as GenericParameter, context);
|
||
|
|
||
|
TypeReference type = m_module.TypeReferences [t.FullName];
|
||
|
if (type != null)
|
||
|
return AdjustReference (t, type);
|
||
|
|
||
|
AssemblyNameReference asm;
|
||
|
if (t.Scope is AssemblyNameReference)
|
||
|
asm = ImportAssembly ((AssemblyNameReference) t.Scope);
|
||
|
else if (t.Scope is ModuleDefinition)
|
||
|
asm = ImportAssembly (((ModuleDefinition) t.Scope).Assembly.Name);
|
||
|
else
|
||
|
throw new NotImplementedException ();
|
||
|
|
||
|
if (t.DeclaringType != null) {
|
||
|
type = new TypeReference (t.Name, string.Empty, asm, t.IsValueType);
|
||
|
type.DeclaringType = ImportTypeReference (t.DeclaringType, context);
|
||
|
} else
|
||
|
type = new TypeReference (t.Name, t.Namespace, asm, t.IsValueType);
|
||
|
|
||
|
TypeReference contextType = context.GenericContext.Type;
|
||
|
|
||
|
context.GenericContext.Type = type;
|
||
|
|
||
|
GenericParameter.CloneInto (t, type, context);
|
||
|
|
||
|
context.GenericContext.Type = contextType;
|
||
|
|
||
|
m_module.TypeReferences.Add (type);
|
||
|
return type;
|
||
|
}
|
||
|
|
||
|
public virtual FieldReference ImportFieldReference (FieldReference fr, ImportContext context)
|
||
|
{
|
||
|
if (fr.DeclaringType.Module == m_module)
|
||
|
return fr;
|
||
|
|
||
|
FieldReference field = (FieldReference) GetMemberReference (fr);
|
||
|
if (field != null)
|
||
|
return field;
|
||
|
|
||
|
field = new FieldReference (
|
||
|
fr.Name,
|
||
|
ImportTypeReference (fr.DeclaringType, context),
|
||
|
ImportTypeReference (fr.FieldType, context));
|
||
|
|
||
|
m_module.MemberReferences.Add (field);
|
||
|
return field;
|
||
|
}
|
||
|
|
||
|
MethodReference GetMethodSpec (MethodReference meth, ImportContext context)
|
||
|
{
|
||
|
if (!(meth is GenericInstanceMethod))
|
||
|
return null;
|
||
|
|
||
|
GenericInstanceMethod gim = meth as GenericInstanceMethod;
|
||
|
GenericInstanceMethod ngim = new GenericInstanceMethod (
|
||
|
ImportMethodReference (gim.ElementMethod, context));
|
||
|
|
||
|
context.GenericContext.CheckProvider (ngim.GetOriginalMethod (), gim.GenericArguments.Count);
|
||
|
foreach (TypeReference arg in gim.GenericArguments)
|
||
|
ngim.GenericArguments.Add (ImportTypeReference (arg, context));
|
||
|
|
||
|
return ngim;
|
||
|
}
|
||
|
|
||
|
public virtual MethodReference ImportMethodReference (MethodReference mr, ImportContext context)
|
||
|
{
|
||
|
if (mr.DeclaringType.Module == m_module)
|
||
|
return mr;
|
||
|
|
||
|
if (mr is MethodSpecification)
|
||
|
return GetMethodSpec (mr, context);
|
||
|
|
||
|
MethodReference meth = (MethodReference) GetMemberReference (mr);
|
||
|
if (meth != null)
|
||
|
return meth;
|
||
|
|
||
|
meth = new MethodReference (
|
||
|
mr.Name,
|
||
|
mr.HasThis,
|
||
|
mr.ExplicitThis,
|
||
|
mr.CallingConvention);
|
||
|
meth.DeclaringType = ImportTypeReference (mr.DeclaringType, context);
|
||
|
|
||
|
TypeReference contextType = context.GenericContext.Type;
|
||
|
MethodReference contextMethod = context.GenericContext.Method;
|
||
|
|
||
|
context.GenericContext.Method = meth;
|
||
|
context.GenericContext.Type = meth.DeclaringType.GetOriginalType();
|
||
|
|
||
|
GenericParameter.CloneInto (mr, meth, context);
|
||
|
|
||
|
meth.ReturnType.ReturnType = ImportTypeReference (mr.ReturnType.ReturnType, context);
|
||
|
|
||
|
foreach (ParameterDefinition param in mr.Parameters)
|
||
|
meth.Parameters.Add (new ParameterDefinition (
|
||
|
ImportTypeReference (param.ParameterType, context)));
|
||
|
|
||
|
context.GenericContext.Type = contextType;
|
||
|
context.GenericContext.Method = contextMethod;
|
||
|
|
||
|
m_module.MemberReferences.Add (meth);
|
||
|
return meth;
|
||
|
}
|
||
|
|
||
|
MemberReference GetMemberReference (MemberReference member)
|
||
|
{
|
||
|
foreach (MemberReference reference in m_module.MemberReferences)
|
||
|
if (reference.ToString () == member.ToString ())
|
||
|
return reference;
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|