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