~ubuntu-branches/ubuntu/oneiric/cecil/oneiric

« back to all changes in this revision

Viewing changes to Mono.Cecil/TypeParser.cs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane, Iain Lane, Jo Shields
  • Date: 2011-08-07 22:38:20 UTC
  • mfrom: (1.1.7 upstream) (6.1.6 experimental)
  • Revision ID: james.westby@ubuntu.com-20110807223820-nfdm4q0pk2smjm11
Tags: 0.9.5+dfsg-1
[ Iain Lane ]
* [411dc78] Update to use my d.o email address
* [74bedaf] Disable clilibs; this is an unstable library
  apps grow unnecessary depends otherwise
* [5288c1f] Mangle debian version in watch file to take care of repacking.
  Also update watch file to look at new github location for tarballs
* [8f7110f] Relax version restriction on cli-common-dev; anything from 0.8
  will do

[ Jo Shields ]
* [e846eb8] Imported Upstream version 0.9.5+dfsg
* [3017d96] Bump build dependencies, as we're building for Mono 2.10 now.
* [27c2cff] Set to DebSrc 3.0, so we can apply patches via Quilt.
* [d0447b3] Update build to use XBuild, not manual compiler invocation.
* [08d2b92] Patch to avoid building tests (which rely on NUnit 2.4)
* [fa5a033] Update install file to include all new assemblies and locations.
* [43bd1e2] Since upstream no longer ships a pcfile, add our own.
* [942ead4] Don't try to ship a Changelog when none exists.
* [ba8232d] Erase obj/ folders in clean rule.
* [090af34] Exclude modulerefs on Windowsy libraries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// TypeParser.cs
 
3
//
 
4
// Author:
 
5
//   Jb Evain (jbevain@gmail.com)
 
6
//
 
7
// Copyright (c) 2008 - 2011 Jb Evain
 
8
//
 
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:
 
16
//
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
//
 
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.
 
27
//
 
28
 
 
29
using System;
 
30
using System.Text;
 
31
 
 
32
using Mono.Cecil.Metadata;
 
33
 
 
34
namespace Mono.Cecil {
 
35
 
 
36
        class TypeParser {
 
37
 
 
38
                class Type {
 
39
                        public const int Ptr = -1;
 
40
                        public const int ByRef = -2;
 
41
                        public const int SzArray = -3;
 
42
 
 
43
                        public string type_fullname;
 
44
                        public string [] nested_names;
 
45
                        public int arity;
 
46
                        public int [] specs;
 
47
                        public Type [] generic_arguments;
 
48
                        public string assembly;
 
49
                }
 
50
 
 
51
                readonly string fullname;
 
52
                readonly int length;
 
53
 
 
54
                int position;
 
55
 
 
56
                TypeParser (string fullname)
 
57
                {
 
58
                        this.fullname = fullname;
 
59
                        this.length = fullname.Length;
 
60
                }
 
61
 
 
62
                Type ParseType (bool fq_name)
 
63
                {
 
64
                        var type = new Type ();
 
65
                        type.type_fullname = ParsePart ();
 
66
 
 
67
                        type.nested_names = ParseNestedNames ();
 
68
 
 
69
                        if (TryGetArity (type))
 
70
                                type.generic_arguments = ParseGenericArguments (type.arity);
 
71
 
 
72
                        type.specs = ParseSpecs ();
 
73
 
 
74
                        if (fq_name)
 
75
                                type.assembly = ParseAssemblyName ();
 
76
 
 
77
                        return type;
 
78
                }
 
79
 
 
80
                static bool TryGetArity (Type type)
 
81
                {
 
82
                        int arity = 0;
 
83
 
 
84
                        TryAddArity (type.type_fullname, ref arity);
 
85
 
 
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);
 
90
                        }
 
91
 
 
92
                        type.arity = arity;
 
93
                        return arity > 0;
 
94
                }
 
95
 
 
96
                static bool TryGetArity (string name, out int arity)
 
97
                {
 
98
                        arity = 0;
 
99
                        var index = name.LastIndexOf ('`');
 
100
                        if (index == -1)
 
101
                                return false;
 
102
 
 
103
                        return ParseInt32 (name.Substring (index + 1), out arity);
 
104
                }
 
105
 
 
106
                static bool ParseInt32 (string value, out int result)
 
107
                {
 
108
#if CF
 
109
                        try {
 
110
                                result = int.Parse (value);
 
111
                                return true;
 
112
                        } catch {
 
113
                                result = 0;
 
114
                                return false;
 
115
                        }
 
116
#else
 
117
                        return int.TryParse (value, out result);
 
118
#endif
 
119
                }
 
120
 
 
121
                static void TryAddArity (string name, ref int arity)
 
122
                {
 
123
                        int type_arity;
 
124
                        if (!TryGetArity (name, out type_arity))
 
125
                                return;
 
126
 
 
127
                        arity += type_arity;
 
128
                }
 
129
 
 
130
                string ParsePart ()
 
131
                {
 
132
                        int start = position;
 
133
                        while (position < length && !IsDelimiter (fullname [position]))
 
134
                                position++;
 
135
 
 
136
                        return fullname.Substring (start, position - start);
 
137
                }
 
138
 
 
139
                static bool IsDelimiter (char chr)
 
140
                {
 
141
                        return "+,[]*&".IndexOf (chr) != -1;
 
142
                }
 
143
 
 
144
                void TryParseWhiteSpace ()
 
145
                {
 
146
                        while (position < length && Char.IsWhiteSpace (fullname [position]))
 
147
                                position++;
 
148
                }
 
149
 
 
150
                string [] ParseNestedNames ()
 
151
                {
 
152
                        string [] nested_names = null;
 
153
                        while (TryParse ('+'))
 
154
                                Add (ref nested_names, ParsePart ());
 
155
 
 
156
                        return nested_names;
 
157
                }
 
158
 
 
159
                bool TryParse (char chr)
 
160
                {
 
161
                        if (position < length && fullname [position] == chr) {
 
162
                                position++;
 
163
                                return true;
 
164
                        }
 
165
 
 
166
                        return false;
 
167
                }
 
168
 
 
169
                static void Add<T> (ref T [] array, T item)
 
170
                {
 
171
                        if (array == null) {
 
172
                                array = new [] { item };
 
173
                                return;
 
174
                        }
 
175
 
 
176
#if !CF
 
177
                        Array.Resize (ref array, array.Length + 1);
 
178
#else
 
179
                        var copy = new T [array.Length + 1];
 
180
                        Array.Copy (array, copy, array.Length);
 
181
                        array = copy;
 
182
#endif
 
183
                        array [array.Length - 1] = item;
 
184
                }
 
185
 
 
186
                int [] ParseSpecs ()
 
187
                {
 
188
                        int [] specs = null;
 
189
 
 
190
                        while (position < length) {
 
191
                                switch (fullname [position]) {
 
192
                                case '*':
 
193
                                        position++;
 
194
                                        Add (ref specs, Type.Ptr);
 
195
                                        break;
 
196
                                case '&':
 
197
                                        position++;
 
198
                                        Add (ref specs, Type.ByRef);
 
199
                                        break;
 
200
                                case '[':
 
201
                                        position++;
 
202
                                        switch (fullname [position]) {
 
203
                                        case ']':
 
204
                                                position++;
 
205
                                                Add (ref specs, Type.SzArray);
 
206
                                                break;
 
207
                                        case '*':
 
208
                                                position++;
 
209
                                                Add (ref specs, 1);
 
210
                                                break;
 
211
                                        default:
 
212
                                                var rank = 1;
 
213
                                                while (TryParse (','))
 
214
                                                        rank++;
 
215
 
 
216
                                                Add (ref specs, rank);
 
217
 
 
218
                                                TryParse (']');
 
219
                                                break;
 
220
                                        }
 
221
                                        break;
 
222
                                default:
 
223
                                        return specs;
 
224
                                }
 
225
                        }
 
226
 
 
227
                        return specs;
 
228
                }
 
229
 
 
230
                Type [] ParseGenericArguments (int arity)
 
231
                {
 
232
                        Type [] generic_arguments = null;
 
233
 
 
234
                        if (position == length || fullname [position] != '[')
 
235
                                return generic_arguments;
 
236
 
 
237
                        TryParse ('[');
 
238
 
 
239
                        for (int i = 0; i < arity; i++) {
 
240
                                var fq_argument = TryParse ('[');
 
241
                                Add (ref generic_arguments, ParseType (fq_argument));
 
242
                                if (fq_argument)
 
243
                                        TryParse (']');
 
244
 
 
245
                                TryParse (',');
 
246
                                TryParseWhiteSpace ();
 
247
                        }
 
248
 
 
249
                        TryParse (']');
 
250
 
 
251
                        return generic_arguments;
 
252
                }
 
253
 
 
254
                string ParseAssemblyName ()
 
255
                {
 
256
                        if (!TryParse (','))
 
257
                                return string.Empty;
 
258
 
 
259
                        TryParseWhiteSpace ();
 
260
 
 
261
                        var start = position;
 
262
                        while (position < length) {
 
263
                                var chr = fullname [position];
 
264
                                if (chr == '[' || chr == ']')
 
265
                                        break;
 
266
 
 
267
                                position++;
 
268
                        }
 
269
 
 
270
                        return fullname.Substring (start, position - start);
 
271
                }
 
272
 
 
273
                public static TypeReference ParseType (ModuleDefinition module, string fullname)
 
274
                {
 
275
                        if (fullname == null)
 
276
                                return null;
 
277
 
 
278
                        var parser = new TypeParser (fullname);
 
279
                        return GetTypeReference (module, parser.ParseType (true));
 
280
                }
 
281
 
 
282
                static TypeReference GetTypeReference (ModuleDefinition module, Type type_info)
 
283
                {
 
284
                        TypeReference type;
 
285
                        if (!TryGetDefinition (module, type_info, out type))
 
286
                                type = CreateReference (type_info, module, GetMetadataScope (module, type_info));
 
287
 
 
288
                        return CreateSpecs (type, type_info);
 
289
                }
 
290
 
 
291
                static TypeReference CreateSpecs (TypeReference type, Type type_info)
 
292
                {
 
293
                        type = TryCreateGenericInstanceType (type, type_info);
 
294
 
 
295
                        var specs = type_info.specs;
 
296
                        if (specs.IsNullOrEmpty ())
 
297
                                return type;
 
298
 
 
299
                        for (int i = 0; i < specs.Length; i++) {
 
300
                                switch (specs [i]) {
 
301
                                case Type.Ptr:
 
302
                                        type = new PointerType (type);
 
303
                                        break;
 
304
                                case Type.ByRef:
 
305
                                        type = new ByReferenceType (type);
 
306
                                        break;
 
307
                                case Type.SzArray:
 
308
                                        type = new ArrayType (type);
 
309
                                        break;
 
310
                                default:
 
311
                                        var array = new ArrayType (type);
 
312
                                        array.Dimensions.Clear ();
 
313
 
 
314
                                        for (int j = 0; j < specs [i]; j++)
 
315
                                                array.Dimensions.Add (new ArrayDimension ());
 
316
 
 
317
                                        type = array;
 
318
                                        break;
 
319
                                }
 
320
                        }
 
321
 
 
322
                        return type;
 
323
                }
 
324
 
 
325
                static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info)
 
326
                {
 
327
                        var generic_arguments = type_info.generic_arguments;
 
328
                        if (generic_arguments.IsNullOrEmpty ())
 
329
                                return type;
 
330
 
 
331
                        var instance = new GenericInstanceType (type);
 
332
                        var instance_arguments = instance.GenericArguments;
 
333
 
 
334
                        for (int i = 0; i < generic_arguments.Length; i++)
 
335
                                instance_arguments.Add (GetTypeReference (type.Module, generic_arguments [i]));
 
336
 
 
337
                        return instance;
 
338
                }
 
339
 
 
340
                public static void SplitFullName (string fullname, out string @namespace, out string name)
 
341
                {
 
342
                        var last_dot = fullname.LastIndexOf ('.');
 
343
 
 
344
                        if (last_dot == -1) {
 
345
                                @namespace = string.Empty;
 
346
                                name = fullname;
 
347
                        } else {
 
348
                                @namespace = fullname.Substring (0, last_dot);
 
349
                                name = fullname.Substring (last_dot + 1);
 
350
                        }
 
351
                }
 
352
 
 
353
                static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope)
 
354
                {
 
355
                        string @namespace, name;
 
356
                        SplitFullName (type_info.type_fullname, out @namespace, out name);
 
357
 
 
358
                        var type = new TypeReference (@namespace, name, module, scope);
 
359
                        MetadataSystem.TryProcessPrimitiveType (type);
 
360
 
 
361
                        AdjustGenericParameters (type);
 
362
 
 
363
                        var nested_names = type_info.nested_names;
 
364
                        if (nested_names.IsNullOrEmpty ())
 
365
                                return type;
 
366
 
 
367
                        for (int i = 0; i < nested_names.Length; i++) {
 
368
                                type = new TypeReference (string.Empty, nested_names [i], module, null) {
 
369
                                        DeclaringType = type,
 
370
                                };
 
371
 
 
372
                                AdjustGenericParameters (type);
 
373
                        }
 
374
 
 
375
                        return type;
 
376
                }
 
377
 
 
378
                static void AdjustGenericParameters (TypeReference type)
 
379
                {
 
380
                        int arity;
 
381
                        if (!TryGetArity (type.Name, out arity))
 
382
                                return;
 
383
 
 
384
                        for (int i = 0; i < arity; i++)
 
385
                                type.GenericParameters.Add (new GenericParameter (type));
 
386
                }
 
387
 
 
388
                static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info)
 
389
                {
 
390
                        if (string.IsNullOrEmpty (type_info.assembly))
 
391
                                return module.TypeSystem.Corlib;
 
392
 
 
393
                        return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly));
 
394
                }
 
395
 
 
396
                static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern)
 
397
                {
 
398
                        var references = module.AssemblyReferences;
 
399
 
 
400
                        for (int i = 0; i < references.Count; i++) {
 
401
                                var reference = references [i];
 
402
                                if (reference.FullName == pattern.FullName)
 
403
                                        return reference;
 
404
                        }
 
405
 
 
406
                        return pattern;
 
407
                }
 
408
 
 
409
                static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type)
 
410
                {
 
411
                        type = null;
 
412
                        if (!TryCurrentModule (module, type_info))
 
413
                                return false;
 
414
 
 
415
                        var typedef = module.GetType (type_info.type_fullname);
 
416
                        if (typedef == null)
 
417
                                return false;
 
418
 
 
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]);
 
423
                        }
 
424
 
 
425
                        type = typedef;
 
426
                        return true;
 
427
                }
 
428
 
 
429
                static bool TryCurrentModule (ModuleDefinition module, Type type_info)
 
430
                {
 
431
                        if (string.IsNullOrEmpty (type_info.assembly))
 
432
                                return true;
 
433
 
 
434
                        if (module.assembly != null && module.assembly.Name.FullName == type_info.assembly)
 
435
                                return true;
 
436
 
 
437
                        return false;
 
438
                }
 
439
 
 
440
                public static string ToParseable (TypeReference type)
 
441
                {
 
442
                        if (type == null)
 
443
                                return null;
 
444
 
 
445
                        var name = new StringBuilder ();
 
446
                        AppendType (type, name, true, true);
 
447
                        return name.ToString ();
 
448
                }
 
449
 
 
450
                static void AppendType (TypeReference type, StringBuilder name, bool fq_name, bool top_level)
 
451
                {
 
452
                        var declaring_type = type.DeclaringType;
 
453
                        if (declaring_type != null) {
 
454
                                AppendType (declaring_type, name, false, top_level);
 
455
                                name.Append ('+');
 
456
                        }
 
457
 
 
458
                        var @namespace = type.Namespace;
 
459
                        if (!string.IsNullOrEmpty (@namespace)) {
 
460
                                name.Append (@namespace);
 
461
                                name.Append ('.');
 
462
                        }
 
463
 
 
464
                        name.Append (type.GetElementType ().Name);
 
465
 
 
466
                        if (!fq_name)
 
467
                                return;
 
468
 
 
469
                        if (type.IsTypeSpecification ())
 
470
                                AppendTypeSpecification ((TypeSpecification) type, name);
 
471
 
 
472
                        if (RequiresFullyQualifiedName (type, top_level)) {
 
473
                                name.Append (", ");
 
474
                                name.Append (GetScopeFullName (type));
 
475
                        }
 
476
                }
 
477
 
 
478
                static string GetScopeFullName (TypeReference type)
 
479
                {
 
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;
 
486
                        }
 
487
 
 
488
                        throw new ArgumentException ();
 
489
                }
 
490
 
 
491
                static void AppendTypeSpecification (TypeSpecification type, StringBuilder name)
 
492
                {
 
493
                        if (type.ElementType.IsTypeSpecification ())
 
494
                                AppendTypeSpecification ((TypeSpecification) type.ElementType, name);
 
495
 
 
496
                        switch (type.etype) {
 
497
                        case ElementType.Ptr:
 
498
                                name.Append ('*');
 
499
                                break;
 
500
                        case ElementType.ByRef:
 
501
                                name.Append ('&');
 
502
                                break;
 
503
                        case ElementType.SzArray:
 
504
                        case ElementType.Array:
 
505
                                var array = (ArrayType) type;
 
506
                                if (array.IsVector) {
 
507
                                        name.Append ("[]");
 
508
                                } else {
 
509
                                        name.Append ('[');
 
510
                                        for (int i = 1; i < array.Rank; i++)
 
511
                                                name.Append (',');
 
512
                                        name.Append (']');
 
513
                                }
 
514
                                break;
 
515
                        case ElementType.GenericInst:
 
516
                                var instance = (GenericInstanceType) type;
 
517
                                var arguments = instance.GenericArguments;
 
518
 
 
519
                                name.Append ('[');
 
520
 
 
521
                                for (int i = 0; i < arguments.Count; i++) {
 
522
                                        if (i > 0)
 
523
                                                name.Append (',');
 
524
 
 
525
                                        var argument = arguments [i];
 
526
                                        var requires_fqname = argument.Scope != argument.Module;
 
527
 
 
528
                                        if (requires_fqname)
 
529
                                                name.Append ('[');
 
530
 
 
531
                                        AppendType (argument, name, true, false);
 
532
 
 
533
                                        if (requires_fqname)
 
534
                                                name.Append (']');
 
535
                                }
 
536
 
 
537
                                name.Append (']');
 
538
                                break;
 
539
                        default:
 
540
                                return;
 
541
                        }
 
542
                }
 
543
 
 
544
                static bool RequiresFullyQualifiedName (TypeReference type, bool top_level)
 
545
                {
 
546
                        if (type.Scope == type.Module)
 
547
                                return false;
 
548
 
 
549
                        if (type.Scope.Name == "mscorlib" && top_level)
 
550
                                return false;
 
551
 
 
552
                        return true;
 
553
                }
 
554
        }
 
555
}