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