/src/LinFu.AOP/MethodRewriter.cs
C# | 97 lines | 46 code | 16 blank | 35 comment | 4 complexity | a2233e848c033e3f53d75dc2c8059f4c MD5 | raw file
1using System.Collections.Generic; 2using LinFu.AOP.Cecil.Interfaces; 3using Mono.Cecil; 4using Mono.Cecil.Cil; 5 6namespace LinFu.AOP.Cecil 7{ 8 /// <summary> 9 /// Provides the basic functionality for the <see cref="IMethodRewriter" /> interface. 10 /// </summary> 11 public abstract class MethodRewriter : IMethodRewriter 12 { 13 private readonly HashSet<TypeDefinition> _modifiedTypes = new HashSet<TypeDefinition>(); 14 15 16 /// <summary> 17 /// Rewrites a target method using the given ILProcessor. 18 /// </summary> 19 /// <param name="method">The target method.</param> 20 /// <param name="IL">The ILProcessor that will be used to rewrite the target method.</param> 21 /// <param name="oldInstructions">The original instructions from the target method body.</param> 22 public void Rewrite(MethodDefinition method, ILProcessor IL, IEnumerable<Instruction> oldInstructions) 23 { 24 var declaringType = method.DeclaringType; 25 var module = declaringType.Module; 26 27 // Interfaces and Enums cannot be modified 28 if (declaringType.IsInterface || declaringType.IsEnum) 29 return; 30 31 ImportReferences(module); 32 33 AddLocals(method); 34 35 if (!_modifiedTypes.Contains(declaringType)) 36 { 37 AddAdditionalMembers(declaringType); 38 _modifiedTypes.Add(declaringType); 39 } 40 41 var newInstructions = new Queue<Instruction>(); 42 foreach (var instruction in oldInstructions) 43 { 44 // Intercept only the load field and the load static field instruction 45 if (!ShouldReplace(instruction, method)) 46 { 47 IL.Append(instruction); 48 continue; 49 } 50 51 Replace(instruction, method, IL); 52 } 53 } 54 55 /// <summary> 56 /// Adds additional members to the host type. 57 /// </summary> 58 /// <param name="host">The host type.</param> 59 public virtual void AddAdditionalMembers(TypeDefinition host) 60 { 61 } 62 63 /// <summary> 64 /// Adds additional references to the target module. 65 /// </summary> 66 /// <param name="module">The host module.</param> 67 public virtual void ImportReferences(ModuleDefinition module) 68 { 69 } 70 71 /// <summary> 72 /// Adds local variables to the <paramref name="hostMethod" />. 73 /// </summary> 74 /// <param name="hostMethod">The target method.</param> 75 public virtual void AddLocals(MethodDefinition hostMethod) 76 { 77 } 78 79 80 /// <summary> 81 /// Determines whether or not the method rewriter should replace the <paramref name="oldInstruction" />. 82 /// </summary> 83 /// <param name="oldInstruction">The instruction that is currently being evaluated.</param> 84 /// <param name="hostMethod">The method that hosts the current instruction.</param> 85 /// <returns><c>true</c> if the method should be replaced; otherwise, it should return <c>false</c>.</returns> 86 protected abstract bool ShouldReplace(Instruction oldInstruction, MethodDefinition hostMethod); 87 88 89 /// <summary> 90 /// Replaces the <paramref name="oldInstruction" /> with a new set of <paramref name="IL" /> instructions.. 91 /// </summary> 92 /// <param name="oldInstruction">The instruction currently being evaluated.</param> 93 /// <param name="hostMethod">The method that contains the target instruction.</param> 94 /// <param name="IL">The ILProcessor for the target method body.</param> 95 protected abstract void Replace(Instruction oldInstruction, MethodDefinition hostMethod, ILProcessor IL); 96 } 97}