/src/LinFu.AOP/MethodRewriter.cs

http://github.com/philiplaureano/LinFu · C# · 97 lines · 46 code · 16 blank · 35 comment · 4 complexity · a2233e848c033e3f53d75dc2c8059f4c MD5 · raw file

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