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