/********* ** Private methods *********/ /// <summary>Rewrite a loaded type definition.</summary> /// <param name="type">The type definition to rewrite.</param> /// <returns>Returns whether the type was modified.</returns> private bool RewriteTypeDefinition(TypeDefinition type) { bool changed = false; changed |= this.RewriteCustomAttributes(type.CustomAttributes); changed |= this.RewriteGenericParameters(type.GenericParameters); foreach (InterfaceImplementation @interface in type.Interfaces) { changed |= this.RewriteTypeReference(@interface.InterfaceType, newType => @interface.InterfaceType = newType); } if (type.BaseType.FullName != "System.Object") { changed |= this.RewriteTypeReference(type.BaseType, newType => type.BaseType = newType); } foreach (MethodDefinition method in type.Methods) { changed |= this.RewriteTypeReference(method.ReturnType, newType => method.ReturnType = newType); changed |= this.RewriteGenericParameters(method.GenericParameters); changed |= this.RewriteCustomAttributes(method.CustomAttributes); foreach (ParameterDefinition parameter in method.Parameters) { changed |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType); } foreach (var methodOverride in method.Overrides) { changed |= this.RewriteMethodReference(methodOverride); } if (method.HasBody) { foreach (VariableDefinition variable in method.Body.Variables) { changed |= this.RewriteTypeReference(variable.VariableType, newType => variable.VariableType = newType); } // rewrite CIL instructions ILProcessor cil = method.Body.GetILProcessor(); Collection <Instruction> instructions = cil.Body.Instructions; bool addedInstructions = false; for (int i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; if (instruction.OpCode.Code == Code.Nop) { continue; } int oldCount = cil.Body.Instructions.Count; changed |= this.RewriteInstruction(instruction, cil, newInstruction => { changed = true; cil.Replace(instruction, newInstruction); instruction = newInstruction; }); if (cil.Body.Instructions.Count > oldCount) { addedInstructions = true; } } // special case: added instructions may cause an instruction to be out of range // of a short jump that references it if (addedInstructions) { foreach (var instruction in instructions) { var longJumpCode = RewriteHelper.GetEquivalentLongJumpCode(instruction.OpCode); if (longJumpCode != null) { instruction.OpCode = longJumpCode.Value; } } changed = true; } } } return(changed); }
/// <summary>Get whether a type has a method whose signature matches the one expected by a method reference.</summary> /// <param name="type">The type to check.</param> /// <param name="reference">The method reference.</param> public static bool HasMatchingSignature(Type type, MethodReference reference) { return(type .GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public) .Any(method => RewriteHelper.HasMatchingSignature(method, reference))); }
/// <summary>Get whether the field is a reference to the expected type and field.</summary> /// <param name="instruction">The IL instruction.</param> /// <param name="fullTypeName">The full type name containing the expected field.</param> /// <param name="fieldName">The name of the expected field.</param> public static bool IsFieldReferenceTo(Instruction instruction, string fullTypeName, string fieldName) { FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); return(RewriteHelper.IsFieldReferenceTo(fieldRef, fullTypeName, fieldName)); }
/// <summary>Rewrite custom attributes if needed.</summary> /// <param name="attributes">The current custom attributes.</param> private bool RewriteCustomAttributes(Collection <CustomAttribute> attributes) { bool rewritten = false; for (int attrIndex = 0; attrIndex < attributes.Count; attrIndex++) { CustomAttribute attribute = attributes[attrIndex]; bool curChanged = false; // attribute type TypeReference newAttrType = null; rewritten |= this.RewriteTypeReference(attribute.AttributeType, newType => { newAttrType = newType; curChanged = true; }); // constructor arguments TypeReference[] argTypes = new TypeReference[attribute.ConstructorArguments.Count]; for (int i = 0; i < argTypes.Length; i++) { var arg = attribute.ConstructorArguments[i]; argTypes[i] = arg.Type; rewritten |= this.RewriteTypeReference(arg.Type, newType => { argTypes[i] = newType; curChanged = true; }); } // swap attribute if (curChanged) { // get constructor MethodDefinition constructor = (newAttrType ?? attribute.AttributeType) .Resolve() .Methods .Where(method => method.IsConstructor) .FirstOrDefault(ctor => RewriteHelper.HasMatchingSignature(ctor, attribute.Constructor)); if (constructor == null) { throw new InvalidOperationException($"Can't rewrite attribute type '{attribute.AttributeType.FullName}' to '{newAttrType?.FullName}', no equivalent constructor found."); } // create new attribute var newAttr = new CustomAttribute(this.Module.ImportReference(constructor)); for (int i = 0; i < argTypes.Length; i++) { newAttr.ConstructorArguments.Add(new CustomAttributeArgument(argTypes[i], attribute.ConstructorArguments[i].Value)); } foreach (var prop in attribute.Properties) { newAttr.Properties.Add(new CustomAttributeNamedArgument(prop.Name, prop.Argument)); } foreach (var field in attribute.Fields) { newAttr.Fields.Add(new CustomAttributeNamedArgument(field.Name, field.Argument)); } // swap attribute attributes[attrIndex] = newAttr; rewritten = true; } } return(rewritten); }