PageRenderTime 20ms CodeModel.GetById 11ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/src/LinFu.AOP/Extensions/NewOperatorInterceptionExtensions.cs

http://github.com/philiplaureano/LinFu
C# | 274 lines | 118 code | 25 blank | 131 comment | 7 complexity | a301d311e11ae797fd3983bd48fe7097 MD5 | raw file
  1using System;
  2using System.Linq;
  3using LinFu.AOP.Cecil.Interfaces;
  4using LinFu.AOP.Interfaces;
  5using Mono.Cecil;
  6
  7namespace LinFu.AOP.Cecil.Extensions
  8{
  9    /// <summary>
 10    ///     An extension class that adds support for intercepting the 'new' operator with LinFu.AOP.
 11    /// </summary>
 12    public static class NewOperatorInterceptionExtensions
 13    {
 14        /// <summary>
 15        ///     Modifies a <paramref name="target" /> to support intercepting all calls to the 'new' operator.
 16        /// </summary>
 17        /// <param name="target">The assembly to be modified.</param>
 18        public static void InterceptAllNewInstances(this AssemblyDefinition target)
 19        {
 20            var typeFilter = GetTypeFilter();
 21            target.InterceptNewInstances(typeFilter);
 22        }
 23
 24        /// <summary>
 25        ///     Modifies a <paramref name="target" /> to support intercepting all calls to the 'new' operator.
 26        /// </summary>
 27        /// <param name="target">The assembly to be modified.</param>
 28        public static void InterceptAllNewInstances(this TypeDefinition target)
 29        {
 30            var typeFilter = GetTypeFilter();
 31            target.InterceptNewInstances(typeFilter);
 32        }
 33
 34        /// <summary>
 35        ///     Modifies a <paramref name="target" /> to support intercepting calls to the 'new' operator.
 36        /// </summary>
 37        /// <param name="target">The assembly to be modified.</param>
 38        /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
 39        /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
 40        /// <remarks>
 41        ///     The type filter determines the concrete types that should be intercepted at runtime.
 42        ///     For example, the following functor code intercepts types named "Foo":
 43        ///     <code>
 44        ///     Func&lt;TypeReference, bool&gt; filter = 
 45        ///     concreteType => concreteType.Name == "Foo";
 46        /// </code>
 47        /// </remarks>
 48        public static void InterceptNewInstances(this TypeDefinition target, Func<TypeReference, bool> typeFilter,
 49            Func<MethodReference, bool> methodFilter)
 50        {
 51            Func<MethodReference, TypeReference, bool> constructorFilter =
 52                (constructor, declaringType) => methodFilter(constructor) && typeFilter(declaringType);
 53
 54            Func<MethodReference, TypeReference, MethodReference, bool> filter =
 55                (ctor, declaringType, declaringMethod) =>
 56                    constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
 57
 58            var redirector = new RedirectNewInstancesToActivator(filter);
 59            target.InterceptNewInstancesWith(redirector, methodFilter);
 60        }
 61
 62
 63        /// <summary>
 64        ///     Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
 65        /// </summary>
 66        /// <param name="target">The assembly to be modified.</param>
 67        /// <param name="constructorFilter">The functor that determines which type instantiations should be intercepted.</param>
 68        /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
 69        /// <remarks>
 70        ///     The type filter determines which concrete types and constructors should be intercepted at runtime.
 71        ///     For example, the following functor code intercepts types named "Foo":
 72        ///     <code>
 73        ///     Func&lt;MethodReference, TypeReference, bool&gt; filter = 
 74        ///     (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
 75        /// </code>
 76        /// </remarks>
 77        public static void InterceptNewInstances(this AssemblyDefinition target,
 78            Func<MethodReference, TypeReference, bool> constructorFilter,
 79            Func<MethodReference, bool> methodFilter)
 80        {
 81            Func<MethodReference, TypeReference, MethodReference, bool> filter =
 82                (ctor, declaringType, declaringMethod) =>
 83                    constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
 84
 85            var redirector = new RedirectNewInstancesToActivator(filter);
 86            target.InterceptNewInstancesWith(redirector, methodFilter);
 87        }
 88
 89        /// <summary>
 90        ///     Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
 91        /// </summary>
 92        /// <param name="target">The assembly to be modified.</param>
 93        /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
 94        /// <remarks>
 95        ///     The type filter determines the concrete types that should be intercepted at runtime.
 96        ///     For example, the following functor code intercepts types named "Foo":
 97        ///     <code>
 98        ///     Func&lt;TypeReference, bool&gt; filter = 
 99        ///     concreteType => concreteType.Name == "Foo";
100        /// </code>
101        /// </remarks>
102        public static void InterceptNewInstances(this AssemblyDefinition target,
103            Func<TypeReference, bool> typeFilter)
104        {
105            target.InterceptNewInstances(typeFilter, m => true);
106        }
107
108        /// <summary>
109        ///     Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
110        /// </summary>
111        /// <param name="target">The assembly to be modified.</param>
112        /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
113        /// <remarks>
114        ///     The type filter determines the concrete types that should be intercepted at runtime.
115        ///     For example, the following functor code intercepts types named "Foo":
116        ///     <code>
117        ///     Func&lt;TypeReference, bool&gt; filter = 
118        ///     concreteType => concreteType.Name == "Foo";
119        /// </code>
120        /// </remarks>
121        public static void InterceptNewInstances(this TypeDefinition target, Func<TypeReference, bool> typeFilter)
122        {
123            target.InterceptNewInstances(typeFilter, m => true);
124        }
125
126        /// <summary>
127        ///     Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
128        /// </summary>
129        /// <param name="target">The item to be modified.</param>
130        /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
131        /// <param name="typeFilter">The filter that determines which types will be modified.</param>
132        /// <remarks>
133        ///     The type filter determines which concrete types and constructors should be intercepted at runtime.
134        ///     For example, the following functor code intercepts types named "Foo":
135        ///     <code>
136        ///     Func&lt;MethodReference, TypeReference, bool&gt; filter = 
137        ///     (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
138        /// </code>
139        /// </remarks>
140        public static void InterceptNewInstances(this AssemblyDefinition target,
141            Func<TypeReference, bool> typeFilter,
142            Func<MethodReference, bool> methodFilter)
143        {
144            Func<MethodReference, TypeReference, bool> constructorFilter =
145                (constructor, declaringType) => methodFilter(constructor) && typeFilter(declaringType);
146
147            Func<MethodReference, TypeReference, MethodReference, bool> filter =
148                (ctor, declaringType, declaringMethod) =>
149                    constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
150
151            var redirector = new RedirectNewInstancesToActivator(filter);
152            target.InterceptNewInstancesWith(redirector, methodFilter);
153        }
154
155
156        /// <summary>
157        ///     Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
158        /// </summary>
159        /// <param name="target">The item to be modified.</param>
160        /// <param name="constructorFilter">The functor that determines which type instantiations should be intercepted.</param>
161        /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
162        /// <remarks>
163        ///     The type filter determines which concrete types and constructors should be intercepted at runtime.
164        ///     For example, the following functor code intercepts types named "Foo":
165        ///     <code>
166        ///     Func&lt;MethodReference, TypeReference, bool&gt; filter = 
167        ///     (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
168        /// </code>
169        /// </remarks>
170        public static void InterceptNewInstances(this TypeDefinition target,
171            Func<MethodReference, TypeReference, bool> constructorFilter,
172            Func<MethodReference, bool> methodFilter)
173        {
174            Func<MethodReference, TypeReference, MethodReference, bool> filter =
175                (ctor, declaringType, declaringMethod) =>
176                    constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
177
178            var redirector = new RedirectNewInstancesToActivator(filter);
179            target.InterceptNewInstancesWith(redirector, methodFilter);
180        }
181
182        /// <summary>
183        ///     Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
184        /// </summary>
185        /// <param name="target">The item to be modified.</param>
186        /// <param name="newInstanceFilter">The filter that will determine which constructor calls should be intercepted.</param>
187        /// <param name="methodFilter">
188        ///     The filter that will determine which host methods should be modified to support new instance
189        ///     interception.
190        /// </param>
191        public static void InterceptNewInstances(this AssemblyDefinition target,
192            INewInstanceFilter newInstanceFilter, IMethodFilter methodFilter)
193        {
194            var redirector = new RedirectNewInstancesToActivator(newInstanceFilter);
195            target.InterceptNewInstancesWith(redirector, methodFilter.ShouldWeave);
196        }
197
198        /// <summary>
199        ///     Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
200        /// </summary>
201        /// <param name="target">The item to be modified.</param>
202        /// <param name="newInstanceFilter">The filter that will determine which constructor calls should be intercepted.</param>
203        /// <param name="methodFilter">
204        ///     The filter that will determine which host methods should be modified to support new instance
205        ///     interception.
206        /// </param>
207        public static void InterceptNewInstances(this TypeDefinition target, INewInstanceFilter newInstanceFilter,
208            IMethodFilter methodFilter)
209        {
210            var redirector = new RedirectNewInstancesToActivator(newInstanceFilter);
211            target.InterceptNewInstancesWith(redirector, methodFilter.ShouldWeave);
212        }
213
214        /// <summary>
215        ///     Modifies the methods in the given <paramref name="target" /> using the custom <see cref="INewObjectWeaver" />
216        ///     instance.
217        /// </summary>
218        /// <param name="target">The host that contains the methods that will be modified.</param>
219        /// <param name="weaver">
220        ///     The custom <see cref="INewObjectWeaver" /> that will replace all calls to the new operator with
221        ///     the custom code emitted by the given weaver.
222        /// </param>
223        /// <param name="filter">The method filter that will determine which methods should be modified.</param>
224        public static void InterceptNewInstancesWith(this AssemblyDefinition target, INewObjectWeaver weaver,
225            Func<MethodReference, bool> filter)
226        {
227            IMethodWeaver interceptNewCalls = new InterceptNewCalls(weaver);
228            var module = target.MainModule;
229            var targetMethods = module.Types.SelectMany(t => t.Methods).Where(m => filter(m)).ToArray();
230            foreach (var targetMethod in targetMethods)
231            {
232                interceptNewCalls.Weave(targetMethod);
233            }
234        }
235
236        /// <summary>
237        ///     Modifies the methods in the given <paramref name="target" /> using the custom <see cref="INewObjectWeaver" />
238        ///     instance.
239        /// </summary>
240        /// <param name="target">The host that contains the methods that will be modified.</param>
241        /// <param name="weaver">
242        ///     The custom <see cref="INewObjectWeaver" /> that will replace all calls to the new operator with
243        ///     the custom code emitted by the given weaver.
244        /// </param>
245        /// <param name="filter">The method filter that will determine which methods should be modified.</param>
246        public static void InterceptNewInstancesWith(this TypeDefinition target, INewObjectWeaver weaver,
247            Func<MethodReference, bool> filter)
248        {
249            var interceptNewCalls = new InterceptNewCalls(weaver);
250            var targetMethods = target.Methods.Where(m => filter(m)).ToArray();
251
252            foreach (var targetMethod in targetMethods)
253            {
254                interceptNewCalls.Weave(targetMethod);
255            }
256        }
257
258        private static Func<TypeReference, bool> GetTypeFilter()
259        {
260            return type =>
261            {
262                var result = !type.IsValueType;
263
264                var module = type.Module;
265                var moduleName = module.Name;
266
267                if (moduleName.StartsWith("LinFu.AOP"))
268                    return false;
269
270                return result;
271            };
272        }
273    }
274}