Merge pull request #2721 from ludovic-henry/fix-mono_ms_ticks
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / MarkStep.cs
1 //
2 // MarkStep.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
8 // (C) 2007 Novell, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections;
32 using System.Linq;
33
34 using Mono.Cecil;
35 using Mono.Cecil.Cil;
36
37 namespace Mono.Linker.Steps {
38
39         public class MarkStep : IStep {
40
41                 protected LinkContext _context;
42                 protected Queue _methods;
43                 protected ArrayList _virtual_methods;
44
45                 public AnnotationStore Annotations {
46                         get { return _context.Annotations; }
47                 }
48
49                 public MarkStep ()
50                 {
51                         _methods = new Queue ();
52                         _virtual_methods = new ArrayList ();
53                 }
54
55                 public virtual void Process (LinkContext context)
56                 {
57                         _context = context;
58
59                         Initialize ();
60                         Process ();
61                 }
62
63                 void Initialize ()
64                 {
65                         foreach (AssemblyDefinition assembly in _context.GetAssemblies ())
66                                 InitializeAssembly (assembly);
67                 }
68
69                 protected virtual void InitializeAssembly (AssemblyDefinition assembly)
70                 {
71                         MarkAssembly (assembly);
72                         foreach (TypeDefinition type in assembly.MainModule.Types) {
73                                 if (!Annotations.IsMarked (type))
74                                         continue;
75
76                                 InitializeType (type);
77                         }
78                 }
79
80                 void InitializeType (TypeDefinition type)
81                 {
82                         MarkType (type);
83
84                         if (type.HasFields)
85                                 InitializeFields (type);
86                         if (type.HasMethods)
87                                 InitializeMethods (type.Methods);
88
89                         if (type.HasNestedTypes) {
90                                 foreach (var nested in type.NestedTypes) {
91                                         if (Annotations.IsMarked (nested))
92                                                 InitializeType (nested);
93                                 }
94                         }
95                 }
96
97                 void InitializeFields (TypeDefinition type)
98                 {
99                         foreach (FieldDefinition field in type.Fields)
100                                 if (Annotations.IsMarked (field))
101                                         MarkField (field);
102                 }
103
104                 void InitializeMethods (ICollection methods)
105                 {
106                         foreach (MethodDefinition method in methods)
107                                 if (Annotations.IsMarked (method))
108                                         EnqueueMethod (method);
109                 }
110
111                 void Process ()
112                 {
113                         if (QueueIsEmpty ())
114                                 throw new InvalidOperationException ("No entry methods");
115
116                         while (!QueueIsEmpty ()) {
117                                 ProcessQueue ();
118                                 ProcessVirtualMethods ();
119                         }
120                 }
121
122                 void ProcessQueue ()
123                 {
124                         while (!QueueIsEmpty ()) {
125                                 MethodDefinition method = (MethodDefinition) _methods.Dequeue ();
126                                 Annotations.Push (method);
127                                 ProcessMethod (method);
128                                 Annotations.Pop ();
129                         }
130                 }
131
132                 bool QueueIsEmpty ()
133                 {
134                         return _methods.Count == 0;
135                 }
136
137                 protected virtual void EnqueueMethod (MethodDefinition method)
138                 {
139                         _methods.Enqueue (method);
140                 }
141
142                 void ProcessVirtualMethods ()
143                 {
144                         foreach (MethodDefinition method in _virtual_methods) {
145                                 Annotations.Push (method);
146                                 ProcessVirtualMethod (method);
147                                 Annotations.Pop ();
148                         }
149                 }
150
151                 void ProcessVirtualMethod (MethodDefinition method)
152                 {
153                         IList overrides = Annotations.GetOverrides (method);
154                         if (overrides == null)
155                                 return;
156
157                         foreach (MethodDefinition @override in overrides)
158                                 ProcessOverride (@override);
159                 }
160
161                 void ProcessOverride (MethodDefinition method)
162                 {
163                         if (!Annotations.IsMarked (method.DeclaringType))
164                                 return;
165
166                         if (Annotations.IsProcessed (method))
167                                 return;
168
169                         if (Annotations.IsMarked (method))
170                                 return;
171
172                         MarkMethod (method);
173                         ProcessVirtualMethod (method);
174                 }
175
176                 void MarkMarshalSpec (IMarshalInfoProvider spec)
177                 {
178                         if (!spec.HasMarshalInfo)
179                                 return;
180
181                         var marshaler = spec.MarshalInfo as CustomMarshalInfo;
182                         if (marshaler == null)
183                                 return;
184
185                         MarkType (marshaler.ManagedType);
186                 }
187
188                 void MarkCustomAttributes (ICustomAttributeProvider provider)
189                 {
190                         if (!provider.HasCustomAttributes)
191                                 return;
192
193                         foreach (CustomAttribute ca in provider.CustomAttributes)
194                                 MarkCustomAttribute (ca);
195                 }
196
197                 protected virtual void MarkCustomAttribute (CustomAttribute ca)
198                 {
199                         Annotations.Push (ca);
200                         MarkMethod (ca.Constructor);
201
202                         MarkCustomAttributeArguments (ca);
203
204                         TypeReference constructor_type = ca.Constructor.DeclaringType;
205                         TypeDefinition type = constructor_type.Resolve ();
206                         if (type == null) {
207                                 Annotations.Pop ();
208                                 throw new ResolutionException (constructor_type);
209                         }
210
211                         MarkCustomAttributeProperties (ca, type);
212                         MarkCustomAttributeFields (ca, type);
213                         Annotations.Pop ();
214                 }
215
216                 protected void MarkSecurityDeclarations (ISecurityDeclarationProvider provider)
217                 {
218                         // most security declarations are removed (if linked) but user code might still have some
219                         // and if the attribtues references types then they need to be marked too
220                         if ((provider == null) || !provider.HasSecurityDeclarations)
221                                 return;
222
223                         foreach (var sd in provider.SecurityDeclarations)
224                                 MarkSecurityDeclaration (sd);
225                 }
226
227                 protected virtual void MarkSecurityDeclaration (SecurityDeclaration sd)
228                 {
229                         if (!sd.HasSecurityAttributes)
230                                 return;
231                         
232                         foreach (var sa in sd.SecurityAttributes)
233                                 MarkSecurityAttribute (sa);
234                 }
235
236                 protected virtual void MarkSecurityAttribute (SecurityAttribute sa)
237                 {
238                         TypeReference security_type = sa.AttributeType;
239                         TypeDefinition type = security_type.Resolve ();
240                         if (type == null)
241                                 throw new ResolutionException (security_type);
242                         
243                         MarkType (security_type);
244                         MarkSecurityAttributeProperties (sa, type);
245                         MarkSecurityAttributeFields (sa, type);
246                 }
247
248                 protected void MarkSecurityAttributeProperties (SecurityAttribute sa, TypeDefinition attribute)
249                 {
250                         if (!sa.HasProperties)
251                                 return;
252
253                         foreach (var named_argument in sa.Properties)
254                                 MarkCustomAttributeProperty (named_argument, attribute);
255                 }
256
257                 protected void MarkSecurityAttributeFields (SecurityAttribute sa, TypeDefinition attribute)
258                 {
259                         if (!sa.HasFields)
260                                 return;
261
262                         foreach (var named_argument in sa.Fields)
263                                 MarkCustomAttributeField (named_argument, attribute);
264                 }
265
266                 protected void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
267                 {
268                         if (!ca.HasProperties)
269                                 return;
270
271                         foreach (var named_argument in ca.Properties)
272                                 MarkCustomAttributeProperty (named_argument, attribute);
273                 }
274
275                 protected void MarkCustomAttributeProperty (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute)
276                 {
277                         PropertyDefinition property = GetProperty (attribute, namedArgument.Name);
278                         Annotations.Push (property);
279                         if (property != null)
280                                 MarkMethod (property.SetMethod);
281
282                         MarkIfType (namedArgument.Argument);
283                         Annotations.Pop ();
284                 }
285
286                 PropertyDefinition GetProperty (TypeDefinition type, string propertyname)
287                 {
288                         while (type != null) {
289                                 PropertyDefinition property = type.Properties.FirstOrDefault (p => p.Name == propertyname);
290                                 if (property != null)
291                                         return property;
292
293                                 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
294                         }
295
296                         return null;
297                 }
298
299                 protected void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
300                 {
301                         if (!ca.HasFields)
302                                 return;
303
304                         foreach (var named_argument in ca.Fields)
305                                 MarkCustomAttributeField (named_argument, attribute);
306                 }
307
308                 protected void MarkCustomAttributeField (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute)
309                 {
310                         FieldDefinition field = GetField (attribute, namedArgument.Name);
311                         if (field != null)
312                                 MarkField (field);
313
314                         MarkIfType (namedArgument.Argument);
315                 }
316
317                 FieldDefinition GetField (TypeDefinition type, string fieldname)
318                 {
319                         while (type != null) {
320                                 FieldDefinition field = type.Fields.FirstOrDefault (f => f.Name == fieldname);
321                                 if (field != null)
322                                         return field;
323
324                                 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
325                         }
326
327                         return null;
328                 }
329
330                 void MarkCustomAttributeArguments (CustomAttribute ca)
331                 {
332                         if (!ca.HasConstructorArguments)
333                                 return;
334
335                         foreach (var argument in ca.ConstructorArguments)
336                                 MarkIfType (argument);
337                 }
338
339                 void MarkIfType (CustomAttributeArgument argument)
340                 {
341                         var at = argument.Type;
342                         if (at.IsArray) {
343                                 var et = at.GetElementType ();
344                                 if (et.Namespace != "System" || et.Name != "Type")
345                                         return;
346
347                                 MarkType (et);
348                                 if (argument.Value == null)
349                                         return;
350
351                                 foreach (var cac in (CustomAttributeArgument[]) argument.Value)
352                                         MarkWithResolvedScope ((TypeReference) cac.Value);
353                         } else if (at.Namespace == "System" && at.Name == "Type") {
354                                 MarkType (argument.Type);
355                                 MarkWithResolvedScope ((TypeReference) argument.Value);
356                         }
357                 }
358
359                 // custom attributes encoding means it's possible to have a scope that will point into a PCL facade
360                 // even if we (just before saving) will resolve all type references (bug #26752)
361                 void MarkWithResolvedScope (TypeReference type)
362                 {
363                         if (type == null)
364                                 return;
365
366                         // a GenericInstanceType can could contains generic arguments with scope that
367                         // needs to be updated out of the PCL facade (bug #28823)
368                         var git = (type as GenericInstanceType);
369                         if ((git != null) && git.HasGenericArguments) {
370                                 foreach (var ga in git.GenericArguments)
371                                         MarkWithResolvedScope (ga);
372                         }
373                         // we cannot set the Scope of a TypeSpecification but it's element type can be set
374                         // e.g. System.String[] -> System.String
375                         var ts = (type as TypeSpecification);
376                         if (ts != null) {
377                                 MarkWithResolvedScope (ts.GetElementType ());
378                                 return;
379                         }
380
381                         var td = type.Resolve ();
382                         if (td != null)
383                                 type.Scope = td.Scope;
384                         MarkType (type);
385                 }
386
387                 protected bool CheckProcessed (IMetadataTokenProvider provider)
388                 {
389                         if (Annotations.IsProcessed (provider))
390                                 return true;
391
392                         Annotations.Processed (provider);
393                         return false;
394                 }
395
396                 protected void MarkAssembly (AssemblyDefinition assembly)
397                 {
398                         if (CheckProcessed (assembly))
399                                 return;
400
401                         ProcessModule (assembly);
402
403                         MarkCustomAttributes (assembly);
404                         MarkSecurityDeclarations (assembly);
405
406                         foreach (ModuleDefinition module in assembly.Modules)
407                                 MarkCustomAttributes (module);
408                 }
409
410                 void ProcessModule (AssemblyDefinition assembly)
411                 {
412                         // Pre-mark <Module> if there is any methods as they need to be executed 
413                         // at assembly load time
414                         foreach (TypeDefinition type in assembly.MainModule.Types)
415                         {
416                                 if (type.Name == "<Module>" && type.HasMethods)
417                                 {
418                                         MarkType (type);
419                                         break;
420                                 }
421                         }
422                 }
423
424                 protected void MarkField (FieldReference reference)
425                 {
426 //                      if (IgnoreScope (reference.DeclaringType.Scope))
427 //                              return;
428
429                         if (reference.DeclaringType is GenericInstanceType)
430                                 MarkType (reference.DeclaringType);
431
432                         FieldDefinition field = ResolveFieldDefinition (reference);
433
434                         if (field == null)
435                                 throw new ResolutionException (reference);
436
437                         if (CheckProcessed (field))
438                                 return;
439
440                         MarkType (field.DeclaringType);
441                         MarkType (field.FieldType);
442                         MarkCustomAttributes (field);
443                         MarkMarshalSpec (field);
444
445                         Annotations.Mark (field);
446                 }
447
448                 protected virtual bool IgnoreScope (IMetadataScope scope)
449                 {
450                         AssemblyDefinition assembly = ResolveAssembly (scope);
451                         return Annotations.GetAction (assembly) != AssemblyAction.Link;
452                 }
453
454                 FieldDefinition ResolveFieldDefinition (FieldReference field)
455                 {
456                         FieldDefinition fd = field as FieldDefinition;
457                         if (fd == null)
458                                 fd = field.Resolve ();
459
460                         return fd;
461                 }
462
463                 void MarkScope (IMetadataScope scope)
464                 {
465                         var provider = scope as IMetadataTokenProvider;
466                         if (provider == null)
467                                 return;
468
469                         Annotations.Mark (provider);
470                 }
471
472                 protected virtual void MarkSerializable (TypeDefinition type)
473                 {
474                         MarkDefaultConstructor (type);
475                         MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
476                 }
477
478                 protected virtual TypeDefinition MarkType (TypeReference reference)
479                 {
480                         if (reference == null)
481                                 return null;
482
483                         reference = GetOriginalType (reference);
484
485                         if (reference is GenericParameter)
486                                 return null;
487
488 //                      if (IgnoreScope (reference.Scope))
489 //                              return;
490
491                         TypeDefinition type = ResolveTypeDefinition (reference);
492
493                         if (type == null)
494                                 throw new ResolutionException (reference);
495
496                         if (CheckProcessed (type))
497                                 return null;
498
499                         Annotations.Push (type);
500
501                         MarkScope (type.Scope);
502                         MarkType (type.BaseType);
503                         MarkType (type.DeclaringType);
504                         MarkCustomAttributes (type);
505                         MarkSecurityDeclarations (type);
506
507                         if (IsMulticastDelegate (type)) {
508                                 MarkMethodCollection (type.Methods);
509                         }
510
511                         if (IsSerializable (type))
512                                 MarkSerializable (type);
513
514                         MarkTypeSpecialCustomAttributes (type);
515
516                         MarkGenericParameterProvider (type);
517
518                         // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
519                         if (type.IsValueType || !type.IsAutoLayout)
520                                 MarkFields (type, type.IsEnum);
521
522                         if (type.HasInterfaces) {
523                                 foreach (TypeReference iface in type.Interfaces)
524                                         MarkType (iface);
525                         }
526
527                         if (type.HasMethods) {
528                                 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
529                                 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
530                                 MarkMethodsIf (type.Methods, HasSerializationAttribute);
531                         }
532
533                         DoAdditionalTypeProcessing (type);
534
535                         Annotations.Pop ();
536
537                         Annotations.Mark (type);
538
539                         ApplyPreserveInfo (type);
540
541                         return type;
542                 }
543
544                 // Allow subclassers to mark additional things when marking a method
545                 protected virtual void DoAdditionalTypeProcessing (TypeDefinition method)
546                 {
547                 }
548
549                 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
550                 {
551                         if (!type.HasCustomAttributes)
552                                 return;
553
554                         foreach (CustomAttribute attribute in type.CustomAttributes) {
555                                 switch (attribute.Constructor.DeclaringType.FullName) {
556                                 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
557                                         MarkXmlSchemaProvider (type, attribute);
558                                         break;
559                                 }
560                         }
561                 }
562
563                 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
564                 {
565                         if (!method.HasCustomAttributes)
566                                 return;
567
568                         foreach (CustomAttribute attribute in method.CustomAttributes) {
569                                 switch (attribute.Constructor.DeclaringType.FullName) {
570                                 case "System.Web.Services.Protocols.SoapHeaderAttribute":
571                                         MarkSoapHeader (method, attribute);
572                                         break;
573                                 }
574                         }
575                 }
576
577                 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
578                 {
579                         string method_name;
580                         if (!TryGetStringArgument (attribute, out method_name))
581                                 return;
582
583                         MarkNamedMethod (type, method_name);
584                 }
585
586                 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
587                 {
588                         argument = null;
589
590                         if (attribute.ConstructorArguments.Count < 1)
591                                 return false;
592
593                         argument = attribute.ConstructorArguments [0].Value as string;
594
595                         return argument != null;
596                 }
597
598                 protected int MarkNamedMethod (TypeDefinition type, string method_name)
599                 {
600                         if (!type.HasMethods)
601                                 return 0;
602
603                         int count = 0;
604                         foreach (MethodDefinition method in type.Methods) {
605                                 if (method.Name != method_name)
606                                         continue;
607
608                                 MarkMethod (method);
609                                 count++;
610                         }
611
612                         return count;
613                 }
614
615                 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
616                 {
617                         string member_name;
618                         if (!TryGetStringArgument (attribute, out member_name))
619                                 return;
620
621                         MarkNamedField (method.DeclaringType, member_name);
622                         MarkNamedProperty (method.DeclaringType, member_name);
623                 }
624
625                 void MarkNamedField (TypeDefinition type, string field_name)
626                 {
627                         if (!type.HasFields)
628                                 return;
629
630                         foreach (FieldDefinition field in type.Fields) {
631                                 if (field.Name != field_name)
632                                         continue;
633
634                                 MarkField (field);
635                         }
636                 }
637
638                 void MarkNamedProperty (TypeDefinition type, string property_name)
639                 {
640                         if (!type.HasProperties)
641                                 return;
642
643                         foreach (PropertyDefinition property in type.Properties) {
644                                 if (property.Name != property_name)
645                                         continue;
646
647                                 Annotations.Push (property);
648                                 MarkMethod (property.GetMethod);
649                                 MarkMethod (property.SetMethod);
650                                 Annotations.Pop ();
651                         }
652                 }
653
654                 void MarkGenericParameterProvider (IGenericParameterProvider provider)
655                 {
656                         if (!provider.HasGenericParameters)
657                                 return;
658
659                         foreach (GenericParameter parameter in provider.GenericParameters)
660                                 MarkGenericParameter (parameter);
661                 }
662
663                 void MarkGenericParameter (GenericParameter parameter)
664                 {
665                         MarkCustomAttributes (parameter);
666                         foreach (TypeReference constraint in parameter.Constraints)
667                                 MarkType (constraint);
668                 }
669
670                 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
671                 {
672                         if (!method.IsVirtual)
673                                 return false;
674
675                         var base_list = Annotations.GetBaseMethods (method);
676                         if (base_list == null)
677                                 return false;
678
679                         foreach (MethodDefinition @base in base_list) {
680                                 if (IgnoreScope (@base.DeclaringType.Scope))
681                                         return true;
682
683                                 if (IsVirtualAndHasPreservedParent (@base))
684                                         return true;
685                         }
686
687                         return false;
688                 }
689
690                 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
691
692                 static bool IsSpecialSerializationConstructor (MethodDefinition method)
693                 {
694                         if (!IsConstructor (method))
695                                 return false;
696
697                         var parameters = method.Parameters;
698                         if (parameters.Count != 2)
699                                 return false;
700
701                         return parameters [0].ParameterType.Name == "SerializationInfo" &&
702                                 parameters [1].ParameterType.Name == "StreamingContext";
703                 }
704
705                 delegate bool MethodPredicate (MethodDefinition method);
706
707                 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
708                 {
709                         foreach (MethodDefinition method in methods)
710                                 if (predicate (method)) {
711                                         Annotations.Push (predicate);
712                                         MarkMethod (method);
713                                         Annotations.Pop ();
714                                 }
715                 }
716
717                 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
718
719                 static bool IsDefaultConstructor (MethodDefinition method)
720                 {
721                         return IsConstructor (method) && !method.HasParameters;
722                 }
723
724                 static bool IsConstructor (MethodDefinition method)
725                 {
726                         return method.IsConstructor && !method.IsStatic;
727                 }
728
729                 protected void MarkDefaultConstructor (TypeDefinition type)
730                 {
731                         if ((type == null) || !type.HasMethods)
732                                 return;
733
734                         MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
735                 }
736
737                 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
738
739                 static bool IsStaticConstructor (MethodDefinition method)
740                 {
741                         return method.IsConstructor && method.IsStatic;
742                 }
743
744                 static bool HasSerializationAttribute (MethodDefinition method)
745                 {
746                         if (!method.HasCustomAttributes)
747                                 return false;
748                         foreach (var ca in method.CustomAttributes) {
749                                 var cat = ca.AttributeType;
750                                 if (cat.Namespace != "System.Runtime.Serialization")
751                                         continue;
752                                 switch (cat.Name) {
753                                 case "OnDeserializedAttribute":
754                                 case "OnDeserializingAttribute":
755                                 case "OnSerializedAttribute":
756                                 case "OnSerializingAttribute":
757                                         return true;
758                                 }
759                         }
760                         return false;
761                 }
762
763                 static bool IsSerializable (TypeDefinition td)
764                 {
765                         return (td.Attributes & TypeAttributes.Serializable) != 0;
766                 }
767
768                 static bool IsMulticastDelegate (TypeDefinition td)
769                 {
770                         return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
771                 }
772
773                 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
774                 {
775                         TypeDefinition td = type as TypeDefinition;
776                         if (td == null)
777                                 td = type.Resolve ();
778
779                         return td;
780                 }
781
782                 protected TypeReference GetOriginalType (TypeReference type)
783                 {
784                         while (type is TypeSpecification) {
785                                 GenericInstanceType git = type as GenericInstanceType;
786                                 if (git != null)
787                                         MarkGenericArguments (git);
788
789                                 var mod = type as IModifierType;
790                                 if (mod != null)
791                                         MarkModifierType (mod);
792
793                                 type = ((TypeSpecification) type).ElementType;
794                         }
795
796                         return type;
797                 }
798
799                 void MarkModifierType (IModifierType mod)
800                 {
801                         MarkType (mod.ModifierType);
802                 }
803
804                 void MarkGenericArguments (IGenericInstance instance)
805                 {
806                         foreach (TypeReference argument in instance.GenericArguments)
807                                 MarkType (argument);
808
809                         MarkGenericArgumentConstructors (instance);
810                 }
811
812                 void MarkGenericArgumentConstructors (IGenericInstance instance)
813                 {
814                         var arguments = instance.GenericArguments;
815
816                         var generic_element = GetGenericProviderFromInstance (instance);
817                         if (generic_element == null)
818                                 return;
819
820                         var parameters = generic_element.GenericParameters;
821
822                         if (arguments.Count != parameters.Count)
823                                 return;
824
825                         for (int i = 0; i < arguments.Count; i++) {
826                                 var argument = arguments [i];
827                                 var parameter = parameters [i];
828
829                                 if (!parameter.HasDefaultConstructorConstraint)
830                                         continue;
831
832                                 var argument_definition = ResolveTypeDefinition (argument);
833                                 if (argument_definition == null)
834                                         continue;
835
836                                 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
837                         }
838                 }
839
840                 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
841                 {
842                         var method = instance as GenericInstanceMethod;
843                         if (method != null)
844                                 return ResolveMethodDefinition (method.ElementMethod);
845
846                         var type = instance as GenericInstanceType;
847                         if (type != null)
848                                 return ResolveTypeDefinition (type.ElementType);
849
850                         return null;
851                 }
852
853                 void ApplyPreserveInfo (TypeDefinition type)
854                 {
855                         ApplyPreserveMethods (type);
856
857                         if (!Annotations.IsPreserved (type))
858                                 return;
859
860                         switch (Annotations.GetPreserve (type)) {
861                         case TypePreserve.All:
862                                 MarkFields (type, true);
863                                 MarkMethods (type);
864                                 break;
865                         case TypePreserve.Fields:
866                                 MarkFields (type, true);
867                                 break;
868                         case TypePreserve.Methods:
869                                 MarkMethods (type);
870                                 break;
871                         }
872                 }
873
874                 void ApplyPreserveMethods (TypeDefinition type)
875                 {
876                         var list = Annotations.GetPreservedMethods (type);
877                         if (list == null)
878                                 return;
879
880                         MarkMethodCollection (list);
881                 }
882
883                 void ApplyPreserveMethods (MethodDefinition method)
884                 {
885                         var list = Annotations.GetPreservedMethods (method);
886                         if (list == null)
887                                 return;
888
889                         MarkMethodCollection (list);
890                 }
891
892                 protected void MarkFields (TypeDefinition type, bool includeStatic)
893                 {
894                         if (!type.HasFields)
895                                 return;
896
897                         foreach (FieldDefinition field in type.Fields) {
898                                 if (!includeStatic && field.IsStatic)
899                                         continue;
900                                 MarkField (field);
901                         }
902                 }
903
904                 protected virtual void MarkMethods (TypeDefinition type)
905                 {
906                         if (type.HasMethods)
907                                 MarkMethodCollection (type.Methods);
908                 }
909
910                 void MarkMethodCollection (IEnumerable methods)
911                 {
912                         foreach (MethodDefinition method in methods)
913                                 MarkMethod (method);
914                 }
915
916                 protected virtual MethodDefinition MarkMethod (MethodReference reference)
917                 {
918                         reference = GetOriginalMethod (reference);
919
920                         if (reference.DeclaringType is ArrayType)
921                                 return null;
922
923                         Annotations.Push (reference);
924                         if (reference.DeclaringType is GenericInstanceType)
925                                 MarkType (reference.DeclaringType);
926
927 //                      if (IgnoreScope (reference.DeclaringType.Scope))
928 //                              return;
929
930                         MethodDefinition method = ResolveMethodDefinition (reference);
931
932                         if (method == null) {
933                                 Annotations.Pop ();
934                                 throw new ResolutionException (reference);
935                         }
936
937                         if (Annotations.GetAction (method) == MethodAction.Nothing)
938                                 Annotations.SetAction (method, MethodAction.Parse);
939
940                         EnqueueMethod (method);
941
942                         Annotations.Pop ();
943                         Annotations.AddDependency (method);
944
945                         return method;
946                 }
947
948                 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
949                 {
950                         AssemblyDefinition assembly = _context.Resolve (scope);
951                         MarkAssembly (assembly);
952                         return assembly;
953                 }
954
955                 protected MethodReference GetOriginalMethod (MethodReference method)
956                 {
957                         while (method is MethodSpecification) {
958                                 GenericInstanceMethod gim = method as GenericInstanceMethod;
959                                 if (gim != null)
960                                         MarkGenericArguments (gim);
961
962                                 method = ((MethodSpecification) method).ElementMethod;
963                         }
964
965                         return method;
966                 }
967
968                 MethodDefinition ResolveMethodDefinition (MethodReference method)
969                 {
970                         MethodDefinition md = method as MethodDefinition;
971                         if (md == null)
972                                 md = method.Resolve ();
973
974                         return md;
975                 }
976
977                 protected virtual void ProcessMethod (MethodDefinition method)
978                 {
979                         if (CheckProcessed (method))
980                                 return;
981
982                         Annotations.Push (method);
983                         MarkType (method.DeclaringType);
984                         MarkCustomAttributes (method);
985                         MarkSecurityDeclarations (method);
986
987                         MarkGenericParameterProvider (method);
988
989                         if (IsPropertyMethod (method))
990                                 MarkProperty (GetProperty (method));
991                         else if (IsEventMethod (method))
992                                 MarkEvent (GetEvent (method));
993
994                         if (method.HasParameters) {
995                                 foreach (ParameterDefinition pd in method.Parameters) {
996                                         MarkType (pd.ParameterType);
997                                         MarkCustomAttributes (pd);
998                                         MarkMarshalSpec (pd);
999                                 }
1000                         }
1001
1002                         if (method.HasOverrides) {
1003                                 foreach (MethodReference ov in method.Overrides)
1004                                         MarkMethod (ov);
1005                         }
1006
1007                         MarkMethodSpecialCustomAttributes (method);
1008
1009                         if (method.IsVirtual)
1010                                 _virtual_methods.Add (method);
1011
1012                         MarkBaseMethods (method);
1013
1014                         MarkType (method.ReturnType);
1015                         MarkCustomAttributes (method.MethodReturnType);
1016                         MarkMarshalSpec (method.MethodReturnType);
1017
1018                         if (ShouldParseMethodBody (method))
1019                                 MarkMethodBody (method.Body);
1020
1021                         DoAdditionalMethodProcessing (method);
1022
1023                         Annotations.Mark (method);
1024
1025                         ApplyPreserveMethods (method);
1026                         Annotations.Pop ();
1027                 }
1028
1029                 // Allow subclassers to mark additional things when marking a method
1030                 protected virtual void DoAdditionalMethodProcessing (MethodDefinition method)
1031                 {
1032                 }
1033
1034                 void MarkBaseMethods (MethodDefinition method)
1035                 {
1036                         IList base_methods = Annotations.GetBaseMethods (method);
1037                         if (base_methods == null)
1038                                 return;
1039
1040                         foreach (MethodDefinition base_method in base_methods) {
1041                                 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
1042                                         continue;
1043
1044                                 MarkMethod (base_method);
1045                                 MarkBaseMethods (base_method);
1046                         }
1047                 }
1048
1049                 bool ShouldParseMethodBody (MethodDefinition method)
1050                 {
1051                         if (!method.HasBody)
1052                                 return false;
1053
1054                         AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
1055                         return (Annotations.GetAction (method) == MethodAction.ForceParse ||
1056                                 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
1057                 }
1058
1059                 static internal bool IsPropertyMethod (MethodDefinition md)
1060                 {
1061                         return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
1062                                 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
1063                 }
1064
1065                 static bool IsEventMethod (MethodDefinition md)
1066                 {
1067                         return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
1068                                 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
1069                                 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
1070                 }
1071
1072                 static internal PropertyDefinition GetProperty (MethodDefinition md)
1073                 {
1074                         TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
1075                         foreach (PropertyDefinition prop in declaringType.Properties)
1076                                 if (prop.GetMethod == md || prop.SetMethod == md)
1077                                         return prop;
1078
1079                         return null;
1080                 }
1081
1082                 static EventDefinition GetEvent (MethodDefinition md)
1083                 {
1084                         TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
1085                         foreach (EventDefinition evt in declaringType.Events)
1086                                 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
1087                                         return evt;
1088
1089                         return null;
1090                 }
1091
1092                 protected void MarkProperty (PropertyDefinition prop)
1093                 {
1094                         MarkCustomAttributes (prop);
1095                 }
1096
1097                 protected void MarkEvent (EventDefinition evt)
1098                 {
1099                         MarkCustomAttributes (evt);
1100                         MarkMethodIfNotNull (evt.AddMethod);
1101                         MarkMethodIfNotNull (evt.InvokeMethod);
1102                         MarkMethodIfNotNull (evt.RemoveMethod);
1103                 }
1104
1105                 void MarkMethodIfNotNull (MethodReference method)
1106                 {
1107                         if (method == null)
1108                                 return;
1109
1110                         MarkMethod (method);
1111                 }
1112
1113                 protected virtual void MarkMethodBody (MethodBody body)
1114                 {
1115                         foreach (VariableDefinition var in body.Variables)
1116                                 MarkType (var.VariableType);
1117
1118                         foreach (ExceptionHandler eh in body.ExceptionHandlers)
1119                                 if (eh.HandlerType == ExceptionHandlerType.Catch)
1120                                         MarkType (eh.CatchType);
1121
1122                         foreach (Instruction instruction in body.Instructions)
1123                                 MarkInstruction (instruction);
1124                 }
1125
1126                 protected virtual void MarkInstruction (Instruction instruction)
1127                 {
1128                         switch (instruction.OpCode.OperandType) {
1129                         case OperandType.InlineField:
1130                                 MarkField ((FieldReference) instruction.Operand);
1131                                 break;
1132                         case OperandType.InlineMethod:
1133                                 MarkMethod ((MethodReference) instruction.Operand);
1134                                 break;
1135                         case OperandType.InlineTok:
1136                                 object token = instruction.Operand;
1137                                 if (token is TypeReference)
1138                                         MarkType ((TypeReference) token);
1139                                 else if (token is MethodReference)
1140                                         MarkMethod ((MethodReference) token);
1141                                 else
1142                                         MarkField ((FieldReference) token);
1143                                 break;
1144                         case OperandType.InlineType:
1145                                 MarkType ((TypeReference) instruction.Operand);
1146                                 break;
1147                         default:
1148                                 break;
1149                         }
1150                 }
1151         }
1152 }