PageRenderTime 131ms CodeModel.GetById 123ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

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