/src/LinFu.AOP/MethodWeaver.cs

http://github.com/philiplaureano/LinFu · C# · 123 lines · 66 code · 21 blank · 36 comment · 10 complexity · f11d655e3bce986d2a8d932acc64339b MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using LinFu.AOP.Cecil.Interfaces;
  4. using Mono.Cecil;
  5. namespace LinFu.AOP.Cecil
  6. {
  7. /// <summary>
  8. /// Represents the default implementation of the <see cref="IMethodWeaver" /> interface.
  9. /// </summary>
  10. public class MethodWeaver : IMethodWeaver
  11. {
  12. private readonly Func<MethodReference, bool> _filter;
  13. private readonly IInstructionProvider _instructionProvider;
  14. private readonly IMethodRewriter _rewriter;
  15. private readonly HashSet<MethodReference> _visitedMethods = new HashSet<MethodReference>();
  16. /// <summary>
  17. /// Initializes a new instance of the MethodWeaver class.
  18. /// </summary>
  19. /// <param name="rewriter">The <see cref="IMethodRewriter" /> instance that will modify the existing method.</param>
  20. /// <param name="filter">The filter that determines which methods should be modified.</param>
  21. public MethodWeaver(IMethodRewriter rewriter, Func<MethodReference, bool> filter)
  22. : this(rewriter, new InstructionProvider(), filter)
  23. {
  24. }
  25. /// <summary>
  26. /// Initializes a new instance of the MethodWeaver class.
  27. /// </summary>
  28. /// <param name="rewriter">The <see cref="IMethodRewriter" /> instance that will modify the existing method.</param>
  29. /// <param name="instructionProvider">The provider that will obtain the original instructions for the target method.</param>
  30. /// <param name="filter">The filter that determines which methods should be modified.</param>
  31. public MethodWeaver(IMethodRewriter rewriter, IInstructionProvider instructionProvider,
  32. Func<MethodReference, bool> filter)
  33. {
  34. _filter = filter;
  35. _rewriter = rewriter;
  36. _instructionProvider = instructionProvider;
  37. }
  38. /// <summary>
  39. /// Determines whether or not a method should be modified.
  40. /// </summary>
  41. /// <param name="item">The target method.</param>
  42. /// <returns><c>true</c> if the method should be modified; otherwise, it returns <c>false</c>.</returns>
  43. public bool ShouldWeave(MethodDefinition item)
  44. {
  45. if (_visitedMethods.Contains(item))
  46. return false;
  47. if (_rewriter == null)
  48. return false;
  49. if (!_filter(item))
  50. return false;
  51. return !item.IsAbstract;
  52. }
  53. /// <summary>
  54. /// Modifies a target method.
  55. /// </summary>
  56. /// <param name="method">The target method.</param>
  57. public void Weave(MethodDefinition method)
  58. {
  59. var body = method.Body;
  60. var IL = body.GetILProcessor();
  61. // Skip empty methods
  62. var instructionCount = body.Instructions.Count;
  63. if (instructionCount == 0)
  64. return;
  65. Rewrite(method);
  66. _visitedMethods.Add(method);
  67. }
  68. /// <summary>
  69. /// Adds additional members to the target type.
  70. /// </summary>
  71. /// <param name="host">The target type to be modified.</param>
  72. public void AddAdditionalMembers(TypeDefinition host)
  73. {
  74. if (_rewriter == null)
  75. return;
  76. _rewriter.AddAdditionalMembers(host);
  77. }
  78. /// <summary>
  79. /// Imports additional references into the given module.
  80. /// </summary>
  81. /// <param name="module">The module that will store the additional references.</param>
  82. public void ImportReferences(ModuleDefinition module)
  83. {
  84. if (_rewriter == null)
  85. return;
  86. _rewriter.ImportReferences(module);
  87. }
  88. /// <summary>
  89. /// Rewrites an existing method.
  90. /// </summary>
  91. /// <param name="method">The method that needs to be modified.</param>
  92. private void Rewrite(MethodDefinition method)
  93. {
  94. var body = method.Body;
  95. var IL = body.GetILProcessor();
  96. var oldInstructions = _instructionProvider.GetInstructions(method);
  97. body.Instructions.Clear();
  98. _rewriter.AddLocals(method);
  99. _rewriter.Rewrite(method, IL, oldInstructions);
  100. }
  101. }
  102. }