5
// Jb Evain (jbevain@gmail.com)
7
// Copyright (c) 2008 - 2011 Jb Evain
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Collections.Generic;
31
using SR = System.Reflection;
33
using Mono.Cecil.Metadata;
35
namespace Mono.Cecil {
37
enum ImportGenericKind {
42
class MetadataImporter {
44
readonly ModuleDefinition module;
46
public MetadataImporter (ModuleDefinition module)
52
static readonly Dictionary<Type, ElementType> type_etype_mapping = new Dictionary<Type, ElementType> (18) {
53
{ typeof (void), ElementType.Void },
54
{ typeof (bool), ElementType.Boolean },
55
{ typeof (char), ElementType.Char },
56
{ typeof (sbyte), ElementType.I1 },
57
{ typeof (byte), ElementType.U1 },
58
{ typeof (short), ElementType.I2 },
59
{ typeof (ushort), ElementType.U2 },
60
{ typeof (int), ElementType.I4 },
61
{ typeof (uint), ElementType.U4 },
62
{ typeof (long), ElementType.I8 },
63
{ typeof (ulong), ElementType.U8 },
64
{ typeof (float), ElementType.R4 },
65
{ typeof (double), ElementType.R8 },
66
{ typeof (string), ElementType.String },
67
{ typeof (TypedReference), ElementType.TypedByRef },
68
{ typeof (IntPtr), ElementType.I },
69
{ typeof (UIntPtr), ElementType.U },
70
{ typeof (object), ElementType.Object },
73
public TypeReference ImportType (Type type, IGenericContext context)
75
return ImportType (type, context, ImportGenericKind.Open);
78
public TypeReference ImportType (Type type, IGenericContext context, ImportGenericKind import_kind)
80
if (IsTypeSpecification (type) || ImportOpenGenericType (type, import_kind))
81
return ImportTypeSpecification (type, context);
83
var reference = new TypeReference (
87
ImportScope (type.Assembly),
90
reference.etype = ImportElementType (type);
92
if (IsNestedType (type))
93
reference.DeclaringType = ImportType (type.DeclaringType, context, import_kind);
95
reference.Namespace = type.Namespace;
97
if (type.IsGenericType)
98
ImportGenericParameters (reference, type.GetGenericArguments ());
103
static bool ImportOpenGenericType (Type type, ImportGenericKind import_kind)
105
return type.IsGenericType && type.IsGenericTypeDefinition && import_kind == ImportGenericKind.Open;
108
static bool ImportOpenGenericMethod (SR.MethodBase method, ImportGenericKind import_kind)
110
return method.IsGenericMethod && method.IsGenericMethodDefinition && import_kind == ImportGenericKind.Open;
113
static bool IsNestedType (Type type)
116
return type.IsNested;
118
return type.DeclaringType != null;
122
TypeReference ImportTypeSpecification (Type type, IGenericContext context)
125
return new ByReferenceType (ImportType (type.GetElementType (), context));
128
return new PointerType (ImportType (type.GetElementType (), context));
131
return new ArrayType (ImportType (type.GetElementType (), context), type.GetArrayRank ());
133
if (type.IsGenericType)
134
return ImportGenericInstance (type, context);
136
if (type.IsGenericParameter)
137
return ImportGenericParameter (type, context);
139
throw new NotSupportedException (type.FullName);
142
static TypeReference ImportGenericParameter (Type type, IGenericContext context)
145
throw new InvalidOperationException ();
147
var owner = type.DeclaringMethod != null
152
throw new InvalidOperationException ();
154
return owner.GenericParameters [type.GenericParameterPosition];
157
TypeReference ImportGenericInstance (Type type, IGenericContext context)
159
var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition);
160
var instance = new GenericInstanceType (element_type);
161
var arguments = type.GetGenericArguments ();
162
var instance_arguments = instance.GenericArguments;
164
for (int i = 0; i < arguments.Length; i++)
165
instance_arguments.Add (ImportType (arguments [i], context ?? element_type));
170
static bool IsTypeSpecification (Type type)
172
return type.HasElementType
173
|| IsGenericInstance (type)
174
|| type.IsGenericParameter;
177
static bool IsGenericInstance (Type type)
179
return type.IsGenericType && !type.IsGenericTypeDefinition;
182
static ElementType ImportElementType (Type type)
185
if (!type_etype_mapping.TryGetValue (type, out etype))
186
return ElementType.None;
191
AssemblyNameReference ImportScope (SR.Assembly assembly)
193
AssemblyNameReference scope;
195
var name = assembly.GetName ();
197
if (TryGetAssemblyNameReference (name, out scope))
200
scope = new AssemblyNameReference (name.Name, name.Version) {
201
Culture = name.CultureInfo.Name,
202
PublicKeyToken = name.GetPublicKeyToken (),
203
HashAlgorithm = (AssemblyHashAlgorithm) name.HashAlgorithm,
206
module.AssemblyReferences.Add (scope);
210
var name = AssemblyNameReference.Parse (assembly.FullName);
212
if (TryGetAssemblyNameReference (name, out scope))
215
module.AssemblyReferences.Add (name);
222
bool TryGetAssemblyNameReference (SR.AssemblyName name, out AssemblyNameReference assembly_reference)
224
var references = module.AssemblyReferences;
226
for (int i = 0; i < references.Count; i++) {
227
var reference = references [i];
228
if (name.FullName != reference.FullName) // TODO compare field by field
231
assembly_reference = reference;
235
assembly_reference = null;
240
public FieldReference ImportField (SR.FieldInfo field, IGenericContext context)
242
var declaring_type = ImportType (field.DeclaringType, context);
244
if (IsGenericInstance (field.DeclaringType))
245
field = ResolveFieldDefinition (field);
247
return new FieldReference {
249
DeclaringType = declaring_type,
250
FieldType = ImportType (field.FieldType, context ?? declaring_type),
254
static SR.FieldInfo ResolveFieldDefinition (SR.FieldInfo field)
257
return field.Module.ResolveField (field.MetadataToken);
259
return field.DeclaringType.GetGenericTypeDefinition ().GetField (field.Name,
260
SR.BindingFlags.Public
261
| SR.BindingFlags.NonPublic
262
| (field.IsStatic ? SR.BindingFlags.Static : SR.BindingFlags.Instance));
266
public MethodReference ImportMethod (SR.MethodBase method, IGenericContext context, ImportGenericKind import_kind)
268
if (IsMethodSpecification (method) || ImportOpenGenericMethod (method, import_kind))
269
return ImportMethodSpecification (method, context);
271
var declaring_type = ImportType (method.DeclaringType, context);
273
if (IsGenericInstance (method.DeclaringType))
274
method = method.Module.ResolveMethod (method.MetadataToken);
276
var reference = new MethodReference {
278
HasThis = HasCallingConvention (method, SR.CallingConventions.HasThis),
279
ExplicitThis = HasCallingConvention (method, SR.CallingConventions.ExplicitThis),
280
DeclaringType = ImportType (method.DeclaringType, context, ImportGenericKind.Definition),
283
if (HasCallingConvention (method, SR.CallingConventions.VarArgs))
284
reference.CallingConvention &= MethodCallingConvention.VarArg;
286
if (method.IsGenericMethod)
287
ImportGenericParameters (reference, method.GetGenericArguments ());
289
var method_info = method as SR.MethodInfo;
290
reference.ReturnType = method_info != null
291
? ImportType (method_info.ReturnType, context ?? reference)
292
: ImportType (typeof (void), null);
294
var parameters = method.GetParameters ();
295
var reference_parameters = reference.Parameters;
297
for (int i = 0; i < parameters.Length; i++)
298
reference_parameters.Add (
299
new ParameterDefinition (ImportType (parameters [i].ParameterType, context ?? reference)));
301
reference.DeclaringType = declaring_type;
306
static void ImportGenericParameters (IGenericParameterProvider provider, Type [] arguments)
308
var provider_parameters = provider.GenericParameters;
310
for (int i = 0; i < arguments.Length; i++)
311
provider_parameters.Add (new GenericParameter (arguments [i].Name, provider));
314
static bool IsMethodSpecification (SR.MethodBase method)
316
return method.IsGenericMethod && !method.IsGenericMethodDefinition;
319
MethodReference ImportMethodSpecification (SR.MethodBase method, IGenericContext context)
321
var method_info = method as SR.MethodInfo;
322
if (method_info == null)
323
throw new InvalidOperationException ();
325
var element_method = ImportMethod (method_info.GetGenericMethodDefinition (), context, ImportGenericKind.Definition);
326
var instance = new GenericInstanceMethod (element_method);
327
var arguments = method.GetGenericArguments ();
328
var instance_arguments = instance.GenericArguments;
330
for (int i = 0; i < arguments.Length; i++)
331
instance_arguments.Add (ImportType (arguments [i], context ?? element_method));
336
static bool HasCallingConvention (SR.MethodBase method, SR.CallingConventions conventions)
338
return (method.CallingConvention & conventions) != 0;
342
public TypeReference ImportType (TypeReference type, IGenericContext context)
344
if (type.IsTypeSpecification ())
345
return ImportTypeSpecification (type, context);
347
var reference = new TypeReference (
351
ImportScope (type.Scope),
354
MetadataSystem.TryProcessPrimitiveType (reference);
357
reference.DeclaringType = ImportType (type.DeclaringType, context);
359
if (type.HasGenericParameters)
360
ImportGenericParameters (reference, type);
365
IMetadataScope ImportScope (IMetadataScope scope)
367
switch (scope.MetadataScopeType) {
368
case MetadataScopeType.AssemblyNameReference:
369
return ImportAssemblyName ((AssemblyNameReference) scope);
370
case MetadataScopeType.ModuleDefinition:
371
return ImportAssemblyName (((ModuleDefinition) scope).Assembly.Name);
372
case MetadataScopeType.ModuleReference:
373
throw new NotImplementedException ();
376
throw new NotSupportedException ();
379
AssemblyNameReference ImportAssemblyName (AssemblyNameReference name)
381
AssemblyNameReference reference;
382
if (TryGetAssemblyNameReference (name, out reference))
385
reference = new AssemblyNameReference (name.Name, name.Version) {
386
Culture = name.Culture,
387
HashAlgorithm = name.HashAlgorithm,
390
var pk_token = !name.PublicKeyToken.IsNullOrEmpty ()
391
? new byte [name.PublicKeyToken.Length]
394
if (pk_token.Length > 0)
395
Buffer.BlockCopy (name.PublicKeyToken, 0, pk_token, 0, pk_token.Length);
397
reference.PublicKeyToken = pk_token;
399
module.AssemblyReferences.Add (reference);
404
bool TryGetAssemblyNameReference (AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference)
406
var references = module.AssemblyReferences;
408
for (int i = 0; i < references.Count; i++) {
409
var reference = references [i];
410
if (name_reference.FullName != reference.FullName) // TODO compare field by field
413
assembly_reference = reference;
417
assembly_reference = null;
421
static void ImportGenericParameters (IGenericParameterProvider imported, IGenericParameterProvider original)
423
var parameters = original.GenericParameters;
424
var imported_parameters = imported.GenericParameters;
426
for (int i = 0; i < parameters.Count; i++)
427
imported_parameters.Add (new GenericParameter (parameters [i].Name, imported));
430
TypeReference ImportTypeSpecification (TypeReference type, IGenericContext context)
432
switch (type.etype) {
433
case ElementType.SzArray:
434
var vector = (ArrayType) type;
435
return new ArrayType (ImportType (vector.ElementType, context));
436
case ElementType.Ptr:
437
var pointer = (PointerType) type;
438
return new PointerType (ImportType (pointer.ElementType, context));
439
case ElementType.ByRef:
440
var byref = (ByReferenceType) type;
441
return new ByReferenceType (ImportType (byref.ElementType, context));
442
case ElementType.Pinned:
443
var pinned = (PinnedType) type;
444
return new PinnedType (ImportType (pinned.ElementType, context));
445
case ElementType.Sentinel:
446
var sentinel = (SentinelType) type;
447
return new SentinelType (ImportType (sentinel.ElementType, context));
448
case ElementType.CModOpt:
449
var modopt = (OptionalModifierType) type;
450
return new OptionalModifierType (
451
ImportType (modopt.ModifierType, context),
452
ImportType (modopt.ElementType, context));
453
case ElementType.CModReqD:
454
var modreq = (RequiredModifierType) type;
455
return new RequiredModifierType (
456
ImportType (modreq.ModifierType, context),
457
ImportType (modreq.ElementType, context));
458
case ElementType.Array:
459
var array = (ArrayType) type;
460
var imported_array = new ArrayType (ImportType (array.ElementType, context));
462
return imported_array;
464
var dimensions = array.Dimensions;
465
var imported_dimensions = imported_array.Dimensions;
467
imported_dimensions.Clear ();
469
for (int i = 0; i < dimensions.Count; i++) {
470
var dimension = dimensions [i];
472
imported_dimensions.Add (new ArrayDimension (dimension.LowerBound, dimension.UpperBound));
475
return imported_array;
476
case ElementType.GenericInst:
477
var instance = (GenericInstanceType) type;
478
var element_type = ImportType (instance.ElementType, context);
479
var imported_instance = new GenericInstanceType (element_type);
481
var arguments = instance.GenericArguments;
482
var imported_arguments = imported_instance.GenericArguments;
484
for (int i = 0; i < arguments.Count; i++)
485
imported_arguments.Add (ImportType (arguments [i], context));
487
return imported_instance;
488
case ElementType.Var:
489
if (context == null || context.Type == null)
490
throw new InvalidOperationException ();
492
return ((TypeReference) context.Type).GetElementType ().GenericParameters [((GenericParameter) type).Position];
493
case ElementType.MVar:
494
if (context == null || context.Method == null)
495
throw new InvalidOperationException ();
497
return context.Method.GenericParameters [((GenericParameter) type).Position];
500
throw new NotSupportedException (type.etype.ToString ());
503
public FieldReference ImportField (FieldReference field, IGenericContext context)
505
var declaring_type = ImportType (field.DeclaringType, context);
507
return new FieldReference {
509
DeclaringType = declaring_type,
510
FieldType = ImportType (field.FieldType, context ?? declaring_type),
514
public MethodReference ImportMethod (MethodReference method, IGenericContext context)
516
if (method.IsGenericInstance)
517
return ImportMethodSpecification (method, context);
519
var declaring_type = ImportType (method.DeclaringType, context);
521
var reference = new MethodReference {
523
HasThis = method.HasThis,
524
ExplicitThis = method.ExplicitThis,
525
DeclaringType = declaring_type,
528
reference.CallingConvention = method.CallingConvention;
530
if (method.HasGenericParameters)
531
ImportGenericParameters (reference, method);
533
reference.ReturnType = ImportType (method.ReturnType, context ?? reference);
535
if (!method.HasParameters)
538
var reference_parameters = reference.Parameters;
540
var parameters = method.Parameters;
541
for (int i = 0; i < parameters.Count; i++)
542
reference_parameters.Add (
543
new ParameterDefinition (ImportType (parameters [i].ParameterType, context ?? reference)));
548
MethodSpecification ImportMethodSpecification (MethodReference method, IGenericContext context)
550
if (!method.IsGenericInstance)
551
throw new NotSupportedException ();
553
var instance = (GenericInstanceMethod) method;
554
var element_method = ImportMethod (instance.ElementMethod, context);
555
var imported_instance = new GenericInstanceMethod (element_method);
557
var arguments = instance.GenericArguments;
558
var imported_arguments = imported_instance.GenericArguments;
560
for (int i = 0; i < arguments.Count; i++)
561
imported_arguments.Add (ImportType (arguments [i], context));
563
return imported_instance;