/// <summary> /// Weaves method with weaving advices <see cref="IWeavingAdvice"/>. /// </summary> /// <param name="markedMethod">The marked method.</param> /// <param name="context">The context.</param> private void RunWeavingAdvices(MarkedNode markedMethod, WeavingContext context) { var method = markedMethod.Node.Method; var methodName = method.Name; // our special recipe, with weaving advices var weavingAdvicesMarkers = GetAllMarkers(markedMethod.Node, context.WeavingAdviceInterfaceType, context).Select(t => t.Item2).ToArray(); var typeDefinition = markedMethod.Node.Method.DeclaringType; var initialType = TypeLoader.GetType(typeDefinition); var weaverMethodWeavingContext = new WeaverMethodWeavingContext(typeDefinition, initialType, methodName, context, TypeResolver, Logging); foreach (var weavingAdviceMarker in weavingAdvicesMarkers) { Logging.WriteDebug("Weaving method '{0}' using weaving advice '{1}'", method.FullName, weavingAdviceMarker.Type.FullName); var weavingAdviceType = TypeLoader.GetType(weavingAdviceMarker.Type); var weavingAdvice = (IWeavingAdvice)Activator.CreateInstance(weavingAdviceType); if (weavingAdvice is IMethodWeavingAdvice methodWeavingAdvice && !method.IsGetter && !method.IsSetter) { methodWeavingAdvice.Advise(weaverMethodWeavingContext); } } if (weaverMethodWeavingContext.TargetMethodName != methodName) { method.Name = weaverMethodWeavingContext.TargetMethodName; } }
/// <summary> /// Weaves the specified method. /// </summary> /// <param name="markedMethod">The marked method.</param> /// <param name="types">The types.</param> private void WeaveAdvices(MarkedNode markedMethod, Types types) { var method = markedMethod.Node.Method; // sanity check var moduleDefinition = method.Module; if (method.ReturnType.SafeEquivalent(moduleDefinition.SafeImport(typeof(void)))) { var customAttributes = method.CustomAttributes; if (customAttributes.Any(c => c.AttributeType.Name == "AsyncStateMachineAttribute")) { Logger.WriteWarning("Advising async void method '{0}' could confuse async advices. Consider switching its return type to async Task.", method.FullName); } } if (method.IsAbstract) { method.Attributes = (method.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Virtual; Logger.WriteDebug("Weaving abstract method '{0}'", method.FullName); WritePointcutBody(method, null, false); } else if (markedMethod.AbstractTarget) { Logger.WriteDebug("Weaving and abstracting method '{0}'", method.FullName); WritePointcutBody(method, null, true); } else { Logger.WriteDebug("Weaving method '{0}'", method.FullName); var methodName = method.Name; // our special recipe, with weaving advices var weavingAdvicesMarkers = GetAllMarkers(markedMethod.Node, types.WeavingAdviceAttributeType, types).ToArray(); if (weavingAdvicesMarkers.Any()) { var typeDefinition = markedMethod.Node.Method.DeclaringType; var initialType = TypeLoader.GetType(typeDefinition); var weaverMethodWeavingContext = new WeaverMethodWeavingContext(typeDefinition, initialType, methodName, types); foreach (var weavingAdviceMarker in weavingAdvicesMarkers) { var weavingAdviceType = TypeLoader.GetType(weavingAdviceMarker.Type); var weavingAdvice = (IWeavingAdvice)Activator.CreateInstance(weavingAdviceType); var methodWeavingAdvice = weavingAdvice as IMethodWeavingAdvice; if (methodWeavingAdvice != null && !method.IsGetter && !method.IsSetter) { methodWeavingAdvice.Advise(weaverMethodWeavingContext); } } if (weaverMethodWeavingContext.TargetMethodName != methodName) { methodName = method.Name = weaverMethodWeavingContext.TargetMethodName; } } // create inner method const MethodAttributes attributesToKeep = MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.PInvokeImpl | MethodAttributes.UnmanagedExport | MethodAttributes.HasSecurity | MethodAttributes.RequireSecObject; var innerMethodAttributes = method.Attributes & attributesToKeep | (InjectAsPrivate ? MethodAttributes.Private : MethodAttributes.Public); string innerMethodName; if (method.IsGetter) { innerMethodName = GetPropertyInnerGetterName(GetPropertyName(methodName)); } else if (method.IsSetter) { innerMethodName = GetPropertyInnerSetterName(GetPropertyName(methodName)); } else { innerMethodName = GetInnerMethodName(methodName); } var innerMethod = new MethodDefinition(innerMethodName, innerMethodAttributes, method.ReturnType); innerMethod.GenericParameters.AddRange(method.GenericParameters.Select(p => p.Clone(innerMethod))); innerMethod.ImplAttributes = method.ImplAttributes; innerMethod.SemanticsAttributes = method.SemanticsAttributes; innerMethod.Parameters.AddRange(method.Parameters); if (method.IsPInvokeImpl) { innerMethod.PInvokeInfo = method.PInvokeInfo; // must be removed before attributes are updated (otherwise Cecil gets angry) method.PInvokeInfo = null; method.IsPreserveSig = false; method.IsPInvokeImpl = false; } else { innerMethod.Body.InitLocals = method.Body.InitLocals; innerMethod.Body.Instructions.AddRange(method.Body.Instructions); innerMethod.Body.Variables.AddRange(method.Body.Variables); innerMethod.Body.ExceptionHandlers.AddRange(method.Body.ExceptionHandlers); } WritePointcutBody(method, innerMethod, false); lock (method.DeclaringType) method.DeclaringType.Methods.Add(innerMethod); } }