// // MarkStep.cs // // Author: // Jb Evain (jbevain@gmail.com) // // (C) 2006 Jb Evain // (C) 2007 Novell, Inc. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; namespace Mono.Linker.Steps { public class MarkStep : IStep { protected LinkContext _context; protected Queue _methods; protected ArrayList _virtual_methods; public AnnotationStore Annotations { get { return _context.Annotations; } } public MarkStep () { _methods = new Queue (); _virtual_methods = new ArrayList (); } public virtual void Process (LinkContext context) { _context = context; Initialize (); Process (); } void Initialize () { foreach (AssemblyDefinition assembly in _context.GetAssemblies ()) InitializeAssembly (assembly); } protected virtual void InitializeAssembly (AssemblyDefinition assembly) { MarkAssembly (assembly); foreach (TypeDefinition type in assembly.MainModule.Types) { if (!Annotations.IsMarked (type)) continue; InitializeType (type); } } void InitializeType (TypeDefinition type) { MarkType (type); if (type.HasFields) InitializeFields (type); if (type.HasMethods) InitializeMethods (type.Methods); if (type.HasNestedTypes) { foreach (var nested in type.NestedTypes) { if (Annotations.IsMarked (nested)) InitializeType (nested); } } } void InitializeFields (TypeDefinition type) { foreach (FieldDefinition field in type.Fields) if (Annotations.IsMarked (field)) MarkField (field); } void InitializeMethods (ICollection methods) { foreach (MethodDefinition method in methods) if (Annotations.IsMarked (method)) EnqueueMethod (method); } void Process () { if (QueueIsEmpty ()) throw new InvalidOperationException ("No entry methods"); while (!QueueIsEmpty ()) { ProcessQueue (); ProcessVirtualMethods (); } } void ProcessQueue () { while (!QueueIsEmpty ()) { MethodDefinition method = (MethodDefinition) _methods.Dequeue (); Annotations.Push (method); ProcessMethod (method); Annotations.Pop (); } } bool QueueIsEmpty () { return _methods.Count == 0; } protected virtual void EnqueueMethod (MethodDefinition method) { _methods.Enqueue (method); } void ProcessVirtualMethods () { foreach (MethodDefinition method in _virtual_methods) { Annotations.Push (method); ProcessVirtualMethod (method); Annotations.Pop (); } } void ProcessVirtualMethod (MethodDefinition method) { IList overrides = Annotations.GetOverrides (method); if (overrides == null) return; foreach (MethodDefinition @override in overrides) ProcessOverride (@override); } void ProcessOverride (MethodDefinition method) { if (!Annotations.IsMarked (method.DeclaringType)) return; if (Annotations.IsProcessed (method)) return; if (Annotations.IsMarked (method)) return; MarkMethod (method); ProcessVirtualMethod (method); } void MarkMarshalSpec (IMarshalInfoProvider spec) { if (!spec.HasMarshalInfo) return; var marshaler = spec.MarshalInfo as CustomMarshalInfo; if (marshaler == null) return; MarkType (marshaler.ManagedType); } void MarkCustomAttributes (ICustomAttributeProvider provider) { if (!provider.HasCustomAttributes) return; foreach (CustomAttribute ca in provider.CustomAttributes) MarkCustomAttribute (ca); } protected virtual void MarkCustomAttribute (CustomAttribute ca) { Annotations.Push (ca); MarkMethod (ca.Constructor); MarkCustomAttributeArguments (ca); TypeReference constructor_type = ca.Constructor.DeclaringType; TypeDefinition type = constructor_type.Resolve (); if (type == null) { Annotations.Pop (); throw new ResolutionException (constructor_type); } MarkCustomAttributeProperties (ca, type); MarkCustomAttributeFields (ca, type); Annotations.Pop (); } protected void MarkSecurityDeclarations (ISecurityDeclarationProvider provider) { // most security declarations are removed (if linked) but user code might still have some // and if the attribtues references types then they need to be marked too if ((provider == null) || !provider.HasSecurityDeclarations) return; foreach (var sd in provider.SecurityDeclarations) MarkSecurityDeclaration (sd); } protected virtual void MarkSecurityDeclaration (SecurityDeclaration sd) { if (!sd.HasSecurityAttributes) return; foreach (var sa in sd.SecurityAttributes) MarkSecurityAttribute (sa); } protected virtual void MarkSecurityAttribute (SecurityAttribute sa) { TypeReference security_type = sa.AttributeType; TypeDefinition type = security_type.Resolve (); if (type == null) throw new ResolutionException (security_type); MarkType (security_type); MarkSecurityAttributeProperties (sa, type); MarkSecurityAttributeFields (sa, type); } protected void MarkSecurityAttributeProperties (SecurityAttribute sa, TypeDefinition attribute) { if (!sa.HasProperties) return; foreach (var named_argument in sa.Properties) MarkCustomAttributeProperty (named_argument, attribute); } protected void MarkSecurityAttributeFields (SecurityAttribute sa, TypeDefinition attribute) { if (!sa.HasFields) return; foreach (var named_argument in sa.Fields) MarkCustomAttributeField (named_argument, attribute); } protected void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute) { if (!ca.HasProperties) return; foreach (var named_argument in ca.Properties) MarkCustomAttributeProperty (named_argument, attribute); } protected void MarkCustomAttributeProperty (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute) { PropertyDefinition property = GetProperty (attribute, namedArgument.Name); Annotations.Push (property); if (property != null) MarkMethod (property.SetMethod); MarkIfType (namedArgument.Argument); Annotations.Pop (); } PropertyDefinition GetProperty (TypeDefinition type, string propertyname) { while (type != null) { PropertyDefinition property = type.Properties.FirstOrDefault (p => p.Name == propertyname); if (property != null) return property; type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; } return null; } protected void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute) { if (!ca.HasFields) return; foreach (var named_argument in ca.Fields) MarkCustomAttributeField (named_argument, attribute); } protected void MarkCustomAttributeField (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute) { FieldDefinition field = GetField (attribute, namedArgument.Name); if (field != null) MarkField (field); MarkIfType (namedArgument.Argument); } FieldDefinition GetField (TypeDefinition type, string fieldname) { while (type != null) { FieldDefinition field = type.Fields.FirstOrDefault (f => f.Name == fieldname); if (field != null) return field; type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; } return null; } void MarkCustomAttributeArguments (CustomAttribute ca) { if (!ca.HasConstructorArguments) return; foreach (var argument in ca.ConstructorArguments) MarkIfType (argument); } void MarkIfType (CustomAttributeArgument argument) { var at = argument.Type; if (at.IsArray) { var et = at.GetElementType (); if (et.Namespace != "System" || et.Name != "Type") return; MarkType (et); if (argument.Value == null) return; foreach (var cac in (CustomAttributeArgument[]) argument.Value) MarkWithResolvedScope ((TypeReference) cac.Value); } else if (at.Namespace == "System" && at.Name == "Type") { MarkType (argument.Type); MarkWithResolvedScope ((TypeReference) argument.Value); } } // custom attributes encoding means it's possible to have a scope that will point into a PCL facade // even if we (just before saving) will resolve all type references (bug #26752) void MarkWithResolvedScope (TypeReference type) { if (type == null) return; // a GenericInstanceType can could contains generic arguments with scope that // needs to be updated out of the PCL facade (bug #28823) var git = (type as GenericInstanceType); if ((git != null) && git.HasGenericArguments) { foreach (var ga in git.GenericArguments) MarkWithResolvedScope (ga); } // we cannot set the Scope of a TypeSpecification but it's element type can be set // e.g. System.String[] -> System.String var ts = (type as TypeSpecification); if (ts != null) { MarkWithResolvedScope (ts.GetElementType ()); return; } var td = type.Resolve (); if (td != null) type.Scope = td.Scope; MarkType (type); } protected bool CheckProcessed (IMetadataTokenProvider provider) { if (Annotations.IsProcessed (provider)) return true; Annotations.Processed (provider); return false; } protected void MarkAssembly (AssemblyDefinition assembly) { if (CheckProcessed (assembly)) return; ProcessModule (assembly); MarkCustomAttributes (assembly); MarkSecurityDeclarations (assembly); foreach (ModuleDefinition module in assembly.Modules) MarkCustomAttributes (module); } void ProcessModule (AssemblyDefinition assembly) { // Pre-mark if there is any methods as they need to be executed // at assembly load time foreach (TypeDefinition type in assembly.MainModule.Types) { if (type.Name == "" && type.HasMethods) { MarkType (type); break; } } } protected void MarkField (FieldReference reference) { // if (IgnoreScope (reference.DeclaringType.Scope)) // return; if (reference.DeclaringType is GenericInstanceType) MarkType (reference.DeclaringType); FieldDefinition field = ResolveFieldDefinition (reference); if (field == null) throw new ResolutionException (reference); if (CheckProcessed (field)) return; MarkType (field.DeclaringType); MarkType (field.FieldType); MarkCustomAttributes (field); MarkMarshalSpec (field); Annotations.Mark (field); } protected virtual bool IgnoreScope (IMetadataScope scope) { AssemblyDefinition assembly = ResolveAssembly (scope); return Annotations.GetAction (assembly) != AssemblyAction.Link; } FieldDefinition ResolveFieldDefinition (FieldReference field) { FieldDefinition fd = field as FieldDefinition; if (fd == null) fd = field.Resolve (); return fd; } void MarkScope (IMetadataScope scope) { var provider = scope as IMetadataTokenProvider; if (provider == null) return; Annotations.Mark (provider); } protected virtual void MarkSerializable (TypeDefinition type) { MarkDefaultConstructor (type); MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate); } protected virtual TypeDefinition MarkType (TypeReference reference) { if (reference == null) return null; reference = GetOriginalType (reference); if (reference is GenericParameter) return null; // if (IgnoreScope (reference.Scope)) // return; TypeDefinition type = ResolveTypeDefinition (reference); if (type == null) throw new ResolutionException (reference); if (CheckProcessed (type)) return null; Annotations.Push (type); MarkScope (type.Scope); MarkType (type.BaseType); MarkType (type.DeclaringType); MarkCustomAttributes (type); MarkSecurityDeclarations (type); if (IsMulticastDelegate (type)) { MarkMethodCollection (type.Methods); } if (IsSerializable (type)) MarkSerializable (type); MarkTypeSpecialCustomAttributes (type); MarkGenericParameterProvider (type); // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit if (type.IsValueType || !type.IsAutoLayout) MarkFields (type, type.IsEnum); if (type.HasInterfaces) { foreach (var iface in type.Interfaces) MarkType (iface.InterfaceType); } if (type.HasMethods) { MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent); MarkMethodsIf (type.Methods, IsStaticConstructorPredicate); MarkMethodsIf (type.Methods, HasSerializationAttribute); } DoAdditionalTypeProcessing (type); Annotations.Pop (); Annotations.Mark (type); ApplyPreserveInfo (type); return type; } // Allow subclassers to mark additional things when marking a method protected virtual void DoAdditionalTypeProcessing (TypeDefinition method) { } void MarkTypeSpecialCustomAttributes (TypeDefinition type) { if (!type.HasCustomAttributes) return; foreach (CustomAttribute attribute in type.CustomAttributes) { switch (attribute.Constructor.DeclaringType.FullName) { case "System.Xml.Serialization.XmlSchemaProviderAttribute": MarkXmlSchemaProvider (type, attribute); break; } } } void MarkMethodSpecialCustomAttributes (MethodDefinition method) { if (!method.HasCustomAttributes) return; foreach (CustomAttribute attribute in method.CustomAttributes) { switch (attribute.Constructor.DeclaringType.FullName) { case "System.Web.Services.Protocols.SoapHeaderAttribute": MarkSoapHeader (method, attribute); break; } } } void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute) { string method_name; if (!TryGetStringArgument (attribute, out method_name)) return; MarkNamedMethod (type, method_name); } static bool TryGetStringArgument (CustomAttribute attribute, out string argument) { argument = null; if (attribute.ConstructorArguments.Count < 1) return false; argument = attribute.ConstructorArguments [0].Value as string; return argument != null; } protected int MarkNamedMethod (TypeDefinition type, string method_name) { if (!type.HasMethods) return 0; int count = 0; foreach (MethodDefinition method in type.Methods) { if (method.Name != method_name) continue; MarkMethod (method); count++; } return count; } void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute) { string member_name; if (!TryGetStringArgument (attribute, out member_name)) return; MarkNamedField (method.DeclaringType, member_name); MarkNamedProperty (method.DeclaringType, member_name); } void MarkNamedField (TypeDefinition type, string field_name) { if (!type.HasFields) return; foreach (FieldDefinition field in type.Fields) { if (field.Name != field_name) continue; MarkField (field); } } void MarkNamedProperty (TypeDefinition type, string property_name) { if (!type.HasProperties) return; foreach (PropertyDefinition property in type.Properties) { if (property.Name != property_name) continue; Annotations.Push (property); MarkMethod (property.GetMethod); MarkMethod (property.SetMethod); Annotations.Pop (); } } void MarkGenericParameterProvider (IGenericParameterProvider provider) { if (!provider.HasGenericParameters) return; foreach (GenericParameter parameter in provider.GenericParameters) MarkGenericParameter (parameter); } void MarkGenericParameter (GenericParameter parameter) { MarkCustomAttributes (parameter); foreach (TypeReference constraint in parameter.Constraints) MarkType (constraint); } bool IsVirtualAndHasPreservedParent (MethodDefinition method) { if (!method.IsVirtual) return false; var base_list = Annotations.GetBaseMethods (method); if (base_list == null) return false; foreach (MethodDefinition @base in base_list) { if (IgnoreScope (@base.DeclaringType.Scope)) return true; if (IsVirtualAndHasPreservedParent (@base)) return true; } return false; } static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor); static bool IsSpecialSerializationConstructor (MethodDefinition method) { if (!IsConstructor (method)) return false; var parameters = method.Parameters; if (parameters.Count != 2) return false; return parameters [0].ParameterType.Name == "SerializationInfo" && parameters [1].ParameterType.Name == "StreamingContext"; } delegate bool MethodPredicate (MethodDefinition method); void MarkMethodsIf (ICollection methods, MethodPredicate predicate) { foreach (MethodDefinition method in methods) if (predicate (method)) { Annotations.Push (predicate); MarkMethod (method); Annotations.Pop (); } } static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor); static bool IsDefaultConstructor (MethodDefinition method) { return IsConstructor (method) && !method.HasParameters; } static bool IsConstructor (MethodDefinition method) { return method.IsConstructor && !method.IsStatic; } protected void MarkDefaultConstructor (TypeDefinition type) { if ((type == null) || !type.HasMethods) return; MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate); } static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor); static bool IsStaticConstructor (MethodDefinition method) { return method.IsConstructor && method.IsStatic; } static bool HasSerializationAttribute (MethodDefinition method) { if (!method.HasCustomAttributes) return false; foreach (var ca in method.CustomAttributes) { var cat = ca.AttributeType; if (cat.Namespace != "System.Runtime.Serialization") continue; switch (cat.Name) { case "OnDeserializedAttribute": case "OnDeserializingAttribute": case "OnSerializedAttribute": case "OnSerializingAttribute": return true; } } return false; } static bool IsSerializable (TypeDefinition td) { return (td.Attributes & TypeAttributes.Serializable) != 0; } static bool IsMulticastDelegate (TypeDefinition td) { return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate"; } protected TypeDefinition ResolveTypeDefinition (TypeReference type) { TypeDefinition td = type as TypeDefinition; if (td == null) td = type.Resolve (); return td; } protected TypeReference GetOriginalType (TypeReference type) { while (type is TypeSpecification) { GenericInstanceType git = type as GenericInstanceType; if (git != null) MarkGenericArguments (git); var mod = type as IModifierType; if (mod != null) MarkModifierType (mod); type = ((TypeSpecification) type).ElementType; } return type; } void MarkModifierType (IModifierType mod) { MarkType (mod.ModifierType); } void MarkGenericArguments (IGenericInstance instance) { foreach (TypeReference argument in instance.GenericArguments) MarkType (argument); MarkGenericArgumentConstructors (instance); } void MarkGenericArgumentConstructors (IGenericInstance instance) { var arguments = instance.GenericArguments; var generic_element = GetGenericProviderFromInstance (instance); if (generic_element == null) return; var parameters = generic_element.GenericParameters; if (arguments.Count != parameters.Count) return; for (int i = 0; i < arguments.Count; i++) { var argument = arguments [i]; var parameter = parameters [i]; if (!parameter.HasDefaultConstructorConstraint) continue; var argument_definition = ResolveTypeDefinition (argument); if (argument_definition == null) continue; MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters); } } IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance) { var method = instance as GenericInstanceMethod; if (method != null) return ResolveMethodDefinition (method.ElementMethod); var type = instance as GenericInstanceType; if (type != null) return ResolveTypeDefinition (type.ElementType); return null; } void ApplyPreserveInfo (TypeDefinition type) { ApplyPreserveMethods (type); if (!Annotations.IsPreserved (type)) return; switch (Annotations.GetPreserve (type)) { case TypePreserve.All: MarkFields (type, true); MarkMethods (type); break; case TypePreserve.Fields: MarkFields (type, true); break; case TypePreserve.Methods: MarkMethods (type); break; } } void ApplyPreserveMethods (TypeDefinition type) { var list = Annotations.GetPreservedMethods (type); if (list == null) return; MarkMethodCollection (list); } void ApplyPreserveMethods (MethodDefinition method) { var list = Annotations.GetPreservedMethods (method); if (list == null) return; MarkMethodCollection (list); } protected void MarkFields (TypeDefinition type, bool includeStatic) { if (!type.HasFields) return; foreach (FieldDefinition field in type.Fields) { if (!includeStatic && field.IsStatic) continue; MarkField (field); } } protected virtual void MarkMethods (TypeDefinition type) { if (type.HasMethods) MarkMethodCollection (type.Methods); } void MarkMethodCollection (IEnumerable methods) { foreach (MethodDefinition method in methods) MarkMethod (method); } protected virtual MethodDefinition MarkMethod (MethodReference reference) { reference = GetOriginalMethod (reference); if (reference.DeclaringType is ArrayType) return null; Annotations.Push (reference); if (reference.DeclaringType is GenericInstanceType) MarkType (reference.DeclaringType); // if (IgnoreScope (reference.DeclaringType.Scope)) // return; MethodDefinition method = ResolveMethodDefinition (reference); if (method == null) { Annotations.Pop (); throw new ResolutionException (reference); } if (Annotations.GetAction (method) == MethodAction.Nothing) Annotations.SetAction (method, MethodAction.Parse); EnqueueMethod (method); Annotations.Pop (); Annotations.AddDependency (method); return method; } AssemblyDefinition ResolveAssembly (IMetadataScope scope) { AssemblyDefinition assembly = _context.Resolve (scope); MarkAssembly (assembly); return assembly; } protected MethodReference GetOriginalMethod (MethodReference method) { while (method is MethodSpecification) { GenericInstanceMethod gim = method as GenericInstanceMethod; if (gim != null) MarkGenericArguments (gim); method = ((MethodSpecification) method).ElementMethod; } return method; } MethodDefinition ResolveMethodDefinition (MethodReference method) { MethodDefinition md = method as MethodDefinition; if (md == null) md = method.Resolve (); return md; } protected virtual void ProcessMethod (MethodDefinition method) { if (CheckProcessed (method)) return; Annotations.Push (method); MarkType (method.DeclaringType); MarkCustomAttributes (method); MarkSecurityDeclarations (method); MarkGenericParameterProvider (method); if (IsPropertyMethod (method)) MarkProperty (GetProperty (method)); else if (IsEventMethod (method)) MarkEvent (GetEvent (method)); if (method.HasParameters) { foreach (ParameterDefinition pd in method.Parameters) { MarkType (pd.ParameterType); MarkCustomAttributes (pd); MarkMarshalSpec (pd); } } if (method.HasOverrides) { foreach (MethodReference ov in method.Overrides) MarkMethod (ov); } MarkMethodSpecialCustomAttributes (method); if (method.IsVirtual) _virtual_methods.Add (method); MarkBaseMethods (method); MarkType (method.ReturnType); MarkCustomAttributes (method.MethodReturnType); MarkMarshalSpec (method.MethodReturnType); if (ShouldParseMethodBody (method)) MarkMethodBody (method.Body); DoAdditionalMethodProcessing (method); Annotations.Mark (method); ApplyPreserveMethods (method); Annotations.Pop (); } // Allow subclassers to mark additional things when marking a method protected virtual void DoAdditionalMethodProcessing (MethodDefinition method) { } void MarkBaseMethods (MethodDefinition method) { IList base_methods = Annotations.GetBaseMethods (method); if (base_methods == null) return; foreach (MethodDefinition base_method in base_methods) { if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface) continue; MarkMethod (base_method); MarkBaseMethods (base_method); } } bool ShouldParseMethodBody (MethodDefinition method) { if (!method.HasBody) return false; AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope); return (Annotations.GetAction (method) == MethodAction.ForceParse || (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse)); } static internal bool IsPropertyMethod (MethodDefinition md) { return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 || (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0; } static bool IsEventMethod (MethodDefinition md) { return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 || (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 || (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0; } static internal PropertyDefinition GetProperty (MethodDefinition md) { TypeDefinition declaringType = (TypeDefinition) md.DeclaringType; foreach (PropertyDefinition prop in declaringType.Properties) if (prop.GetMethod == md || prop.SetMethod == md) return prop; return null; } static EventDefinition GetEvent (MethodDefinition md) { TypeDefinition declaringType = (TypeDefinition) md.DeclaringType; foreach (EventDefinition evt in declaringType.Events) if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md) return evt; return null; } protected void MarkProperty (PropertyDefinition prop) { MarkCustomAttributes (prop); } protected void MarkEvent (EventDefinition evt) { MarkCustomAttributes (evt); MarkMethodIfNotNull (evt.AddMethod); MarkMethodIfNotNull (evt.InvokeMethod); MarkMethodIfNotNull (evt.RemoveMethod); } void MarkMethodIfNotNull (MethodReference method) { if (method == null) return; MarkMethod (method); } protected virtual void MarkMethodBody (MethodBody body) { foreach (VariableDefinition var in body.Variables) MarkType (var.VariableType); foreach (ExceptionHandler eh in body.ExceptionHandlers) if (eh.HandlerType == ExceptionHandlerType.Catch) MarkType (eh.CatchType); foreach (Instruction instruction in body.Instructions) MarkInstruction (instruction); } protected virtual void MarkInstruction (Instruction instruction) { switch (instruction.OpCode.OperandType) { case OperandType.InlineField: MarkField ((FieldReference) instruction.Operand); break; case OperandType.InlineMethod: MarkMethod ((MethodReference) instruction.Operand); break; case OperandType.InlineTok: object token = instruction.Operand; if (token is TypeReference) MarkType ((TypeReference) token); else if (token is MethodReference) MarkMethod ((MethodReference) token); else MarkField ((FieldReference) token); break; case OperandType.InlineType: MarkType ((TypeReference) instruction.Operand); break; default: break; } } } }