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.
32
using Mono.Cecil.Metadata;
34
namespace Mono.Cecil {
39
public const int Ptr = -1;
40
public const int ByRef = -2;
41
public const int SzArray = -3;
43
public string type_fullname;
44
public string [] nested_names;
47
public Type [] generic_arguments;
48
public string assembly;
51
readonly string fullname;
56
TypeParser (string fullname)
58
this.fullname = fullname;
59
this.length = fullname.Length;
62
Type ParseType (bool fq_name)
64
var type = new Type ();
65
type.type_fullname = ParsePart ();
67
type.nested_names = ParseNestedNames ();
69
if (TryGetArity (type))
70
type.generic_arguments = ParseGenericArguments (type.arity);
72
type.specs = ParseSpecs ();
75
type.assembly = ParseAssemblyName ();
80
static bool TryGetArity (Type type)
84
TryAddArity (type.type_fullname, ref arity);
86
var nested_names = type.nested_names;
87
if (!nested_names.IsNullOrEmpty ()) {
88
for (int i = 0; i < nested_names.Length; i++)
89
TryAddArity (nested_names [i], ref arity);
96
static bool TryGetArity (string name, out int arity)
99
var index = name.LastIndexOf ('`');
103
return ParseInt32 (name.Substring (index + 1), out arity);
106
static bool ParseInt32 (string value, out int result)
110
result = int.Parse (value);
117
return int.TryParse (value, out result);
121
static void TryAddArity (string name, ref int arity)
124
if (!TryGetArity (name, out type_arity))
132
int start = position;
133
while (position < length && !IsDelimiter (fullname [position]))
136
return fullname.Substring (start, position - start);
139
static bool IsDelimiter (char chr)
141
return "+,[]*&".IndexOf (chr) != -1;
144
void TryParseWhiteSpace ()
146
while (position < length && Char.IsWhiteSpace (fullname [position]))
150
string [] ParseNestedNames ()
152
string [] nested_names = null;
153
while (TryParse ('+'))
154
Add (ref nested_names, ParsePart ());
159
bool TryParse (char chr)
161
if (position < length && fullname [position] == chr) {
169
static void Add<T> (ref T [] array, T item)
172
array = new [] { item };
177
Array.Resize (ref array, array.Length + 1);
179
var copy = new T [array.Length + 1];
180
Array.Copy (array, copy, array.Length);
183
array [array.Length - 1] = item;
190
while (position < length) {
191
switch (fullname [position]) {
194
Add (ref specs, Type.Ptr);
198
Add (ref specs, Type.ByRef);
202
switch (fullname [position]) {
205
Add (ref specs, Type.SzArray);
213
while (TryParse (','))
216
Add (ref specs, rank);
230
Type [] ParseGenericArguments (int arity)
232
Type [] generic_arguments = null;
234
if (position == length || fullname [position] != '[')
235
return generic_arguments;
239
for (int i = 0; i < arity; i++) {
240
var fq_argument = TryParse ('[');
241
Add (ref generic_arguments, ParseType (fq_argument));
246
TryParseWhiteSpace ();
251
return generic_arguments;
254
string ParseAssemblyName ()
259
TryParseWhiteSpace ();
261
var start = position;
262
while (position < length) {
263
var chr = fullname [position];
264
if (chr == '[' || chr == ']')
270
return fullname.Substring (start, position - start);
273
public static TypeReference ParseType (ModuleDefinition module, string fullname)
275
if (fullname == null)
278
var parser = new TypeParser (fullname);
279
return GetTypeReference (module, parser.ParseType (true));
282
static TypeReference GetTypeReference (ModuleDefinition module, Type type_info)
285
if (!TryGetDefinition (module, type_info, out type))
286
type = CreateReference (type_info, module, GetMetadataScope (module, type_info));
288
return CreateSpecs (type, type_info);
291
static TypeReference CreateSpecs (TypeReference type, Type type_info)
293
type = TryCreateGenericInstanceType (type, type_info);
295
var specs = type_info.specs;
296
if (specs.IsNullOrEmpty ())
299
for (int i = 0; i < specs.Length; i++) {
302
type = new PointerType (type);
305
type = new ByReferenceType (type);
308
type = new ArrayType (type);
311
var array = new ArrayType (type);
312
array.Dimensions.Clear ();
314
for (int j = 0; j < specs [i]; j++)
315
array.Dimensions.Add (new ArrayDimension ());
325
static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info)
327
var generic_arguments = type_info.generic_arguments;
328
if (generic_arguments.IsNullOrEmpty ())
331
var instance = new GenericInstanceType (type);
332
var instance_arguments = instance.GenericArguments;
334
for (int i = 0; i < generic_arguments.Length; i++)
335
instance_arguments.Add (GetTypeReference (type.Module, generic_arguments [i]));
340
public static void SplitFullName (string fullname, out string @namespace, out string name)
342
var last_dot = fullname.LastIndexOf ('.');
344
if (last_dot == -1) {
345
@namespace = string.Empty;
348
@namespace = fullname.Substring (0, last_dot);
349
name = fullname.Substring (last_dot + 1);
353
static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope)
355
string @namespace, name;
356
SplitFullName (type_info.type_fullname, out @namespace, out name);
358
var type = new TypeReference (@namespace, name, module, scope);
359
MetadataSystem.TryProcessPrimitiveType (type);
361
AdjustGenericParameters (type);
363
var nested_names = type_info.nested_names;
364
if (nested_names.IsNullOrEmpty ())
367
for (int i = 0; i < nested_names.Length; i++) {
368
type = new TypeReference (string.Empty, nested_names [i], module, null) {
369
DeclaringType = type,
372
AdjustGenericParameters (type);
378
static void AdjustGenericParameters (TypeReference type)
381
if (!TryGetArity (type.Name, out arity))
384
for (int i = 0; i < arity; i++)
385
type.GenericParameters.Add (new GenericParameter (type));
388
static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info)
390
if (string.IsNullOrEmpty (type_info.assembly))
391
return module.TypeSystem.Corlib;
393
return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly));
396
static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern)
398
var references = module.AssemblyReferences;
400
for (int i = 0; i < references.Count; i++) {
401
var reference = references [i];
402
if (reference.FullName == pattern.FullName)
409
static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type)
412
if (!TryCurrentModule (module, type_info))
415
var typedef = module.GetType (type_info.type_fullname);
419
var nested_names = type_info.nested_names;
420
if (!nested_names.IsNullOrEmpty ()) {
421
for (int i = 0; i < nested_names.Length; i++)
422
typedef = typedef.GetNestedType (nested_names [i]);
429
static bool TryCurrentModule (ModuleDefinition module, Type type_info)
431
if (string.IsNullOrEmpty (type_info.assembly))
434
if (module.assembly != null && module.assembly.Name.FullName == type_info.assembly)
440
public static string ToParseable (TypeReference type)
445
var name = new StringBuilder ();
446
AppendType (type, name, true, true);
447
return name.ToString ();
450
static void AppendType (TypeReference type, StringBuilder name, bool fq_name, bool top_level)
452
var declaring_type = type.DeclaringType;
453
if (declaring_type != null) {
454
AppendType (declaring_type, name, false, top_level);
458
var @namespace = type.Namespace;
459
if (!string.IsNullOrEmpty (@namespace)) {
460
name.Append (@namespace);
464
name.Append (type.GetElementType ().Name);
469
if (type.IsTypeSpecification ())
470
AppendTypeSpecification ((TypeSpecification) type, name);
472
if (RequiresFullyQualifiedName (type, top_level)) {
474
name.Append (GetScopeFullName (type));
478
static string GetScopeFullName (TypeReference type)
480
var scope = type.Scope;
481
switch (scope.MetadataScopeType) {
482
case MetadataScopeType.AssemblyNameReference:
483
return ((AssemblyNameReference) scope).FullName;
484
case MetadataScopeType.ModuleDefinition:
485
return ((ModuleDefinition) scope).Assembly.Name.FullName;
488
throw new ArgumentException ();
491
static void AppendTypeSpecification (TypeSpecification type, StringBuilder name)
493
if (type.ElementType.IsTypeSpecification ())
494
AppendTypeSpecification ((TypeSpecification) type.ElementType, name);
496
switch (type.etype) {
497
case ElementType.Ptr:
500
case ElementType.ByRef:
503
case ElementType.SzArray:
504
case ElementType.Array:
505
var array = (ArrayType) type;
506
if (array.IsVector) {
510
for (int i = 1; i < array.Rank; i++)
515
case ElementType.GenericInst:
516
var instance = (GenericInstanceType) type;
517
var arguments = instance.GenericArguments;
521
for (int i = 0; i < arguments.Count; i++) {
525
var argument = arguments [i];
526
var requires_fqname = argument.Scope != argument.Module;
531
AppendType (argument, name, true, false);
544
static bool RequiresFullyQualifiedName (TypeReference type, bool top_level)
546
if (type.Scope == type.Module)
549
if (type.Scope.Name == "mscorlib" && top_level)