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