コード例 #1
0
ファイル: AspectWeaver.cs プロジェクト: TheXenocide/MrAdvice
        /// <summary>
        /// Determines whether the specified type reference is aspect.
        /// </summary>
        /// <param name="typeReference">The type reference.</param>
        /// <param name="markerInterface">The aspect marker interface.</param>
        /// <returns></returns>
        private bool IsMarker(ITypeDefOrRef typeReference, ITypeDefOrRef markerInterface)
        {
            lock (_isMarker)
            {
                var key = Tuple.Create(typeReference.FullName, markerInterface.FullName);
                // there is a cache, because the same attribute may be found several time
                // and we're in a hurry, the developper is waiting for his program to start!
                bool isMarker;
                if (_isMarker.TryGetValue(key, out isMarker))
                {
                    return(isMarker);
                }

                // otherwise look for type or implemented interfaces (recursively)
                var typeDef = TypeResolver.Resolve(typeReference);
                if (typeDef == null)
                {
                    return(false);
                }
                var interfaces = typeDef.Interfaces;
                _isMarker[key] = isMarker = typeReference.SafeEquivalent(markerInterface) ||
                                            interfaces.Any(i => IsMarker(i.Interface, markerInterface));
                return(isMarker);
            }
        }
コード例 #2
0
ファイル: AspectWeaver.cs プロジェクト: tom123123123/MrAdvice
        private TypeDef ResolveTypeOrGenericDefinition(ITypeDefOrRef typeDefOrRef)
        {
            var typeDef = typeDefOrRef as TypeDef;

            if (typeDef != null)
            {
                return(typeDef);
            }

            var typeRef = typeDefOrRef as TypeRef;

            if (typeRef != null)
            {
                return(TypeResolver.Resolve(typeRef));
            }

            // tricky part here: assuming this a generic type
            var typeSpec    = (TypeSpec)typeDefOrRef;
            var genericType = typeSpec.TryGetGenericInstSig();

            if (genericType != null)
            {
                return(genericType.GenericType.TypeDef);
            }

            return(null);
        }
コード例 #3
0
ファイル: AspectWeaver.cs プロジェクト: freeman6/MrAdvice
        /// <summary>
        /// Determines whether the advice member is introduction, based on its type.
        /// </summary>
        /// <param name="adviceMemberTypeReference">The type reference.</param>
        /// <param name="introducedFieldType">Type of the introduced field.</param>
        /// <param name="isShared">if set to <c>true</c> the introduced field is shared among advices of the same type.</param>
        /// <param name="context">The context.</param>
        /// <returns>
        ///   <c>true</c> if the specified advice member type reference is introduction; otherwise, <c>false</c>.
        /// </returns>
        private bool IsIntroduction(ITypeDefOrRef adviceMemberTypeReference, out ITypeDefOrRef introducedFieldType, out bool isShared, WeavingContext context)
        {
            introducedFieldType = null;
            isShared            = false;
            var genericAdviceMemberTypeReference = adviceMemberTypeReference.TryGetGenericInstSig();

            if (genericAdviceMemberTypeReference is null)
            {
                return(false);
            }

            var genericAdviceMemberTypeDefinition = TypeResolver.Resolve(genericAdviceMemberTypeReference.GenericType.TypeDefOrRef);

            if (genericAdviceMemberTypeDefinition is null) // in DEBUG or bogus cases, this may not be resolved. Whatever, this is not our field
            {
                return(false);
            }

            if (!genericAdviceMemberTypeDefinition.ImplementsType(context.IntroducedFieldType, TypeResolver))
            {
                return(false);
            }

            introducedFieldType = genericAdviceMemberTypeReference.GenericArguments[0].ToTypeDefOrRef();
            isShared            = genericAdviceMemberTypeDefinition.ImplementsType(context.SharedIntroducedFieldType, TypeResolver);
            return(true);
        }
コード例 #4
0
        /// <summary>
        /// Weaves the info advices for the given type.
        /// </summary>
        /// <param name="infoAdvisedType">Type of the module.</param>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="useWholeAssembly">if set to <c>true</c> [use whole assembly].</param>
        private void WeaveInfoAdvices(TypeDef infoAdvisedType, ModuleDef moduleDefinition, bool useWholeAssembly)
        {
            var invocationType = TypeResolver.Resolve(moduleDefinition, typeof(Invocation));

            if (invocationType == null)
            {
                return;
            }
            var proceedRuntimeInitializersReference = (from m in invocationType.Methods
                                                       where m.IsStatic && m.Name == nameof(Invocation.ProcessInfoAdvices)
                                                       let parameters = m.Parameters
                                                                        where parameters.Count == 1 &&
                                                                        parameters[0].Type.SafeEquivalent(
                                                           moduleDefinition.SafeImport(useWholeAssembly ? typeof(Assembly) : typeof(Type)).ToTypeSig())
                                                                        select m).SingleOrDefault();

            if (proceedRuntimeInitializersReference == null)
            {
                Logging.WriteWarning("Info advice method not found");
                return;
            }

            // the cctor needs to be called after all initialization (in case some info advices collect data)
            infoAdvisedType.Attributes &= ~TypeAttributes.BeforeFieldInit;

            const string cctorMethodName = ".cctor";
            var          staticCtor      = infoAdvisedType.Methods.SingleOrDefault(m => m.Name == cctorMethodName);
            var          newStaticCtor   = staticCtor == null;

            if (newStaticCtor)
            {
                staticCtor = new MethodDefUser(cctorMethodName, MethodSig.CreateStatic(moduleDefinition.CorLibTypes.Void),
                                               (InjectAsPrivate ? MethodAttributes.Private : MethodAttributes.Public)
                                               | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
                staticCtor.Body = new CilBody();
                infoAdvisedType.Methods.Add(staticCtor);
            }

            var instructions = new Instructions(staticCtor.Body.Instructions, staticCtor.Module);

            var proceedMethod = moduleDefinition.SafeImport(proceedRuntimeInitializersReference);

            if (useWholeAssembly)
            {
                instructions.Emit(OpCodes.Call, moduleDefinition.SafeImport(ReflectionUtility.GetMethodInfo(() => Assembly.GetExecutingAssembly())));
            }
            else
            {
                instructions.Emit(OpCodes.Ldtoken, TypeImporter.Import(moduleDefinition, infoAdvisedType.ToTypeSig()));
                // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                var getTypeFromHandleMethodInfo = ReflectionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(new RuntimeTypeHandle()));
                instructions.Emit(OpCodes.Call, moduleDefinition.SafeImport(getTypeFromHandleMethodInfo));
            }
            instructions.Emit(OpCodes.Call, proceedMethod);
            // ret is only emitted if the method is new
            if (newStaticCtor)
            {
                instructions.Emit(OpCodes.Ret);
            }
        }
コード例 #5
0
        /// <summary>
        /// Creates the pointcut rules for a given advice.
        /// </summary>
        /// <param name="adviceType">Type of the advice.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private PointcutSelector CreatePointcutSelector(ITypeDefOrRef adviceType, WeavingContext context)
        {
            var adviceTypeDef = TypeResolver.Resolve(adviceType);
            var rules         = new PointcutSelector();

            foreach (var customAttribute in adviceTypeDef.CustomAttributes)
            {
                rules += CreatePointcutSelector(customAttribute, context);
            }
            return(rules);
        }
コード例 #6
0
ファイル: AspectWeaver.cs プロジェクト: TheXenocide/MrAdvice
        /// <summary>
        /// Gets all attributes that implement the given advice interface
        /// </summary>
        /// <param name="reflectionNode">The reflection node.</param>
        /// <param name="markerInterface">The advice interface.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private IEnumerable <MarkerDefinition> GetAllMarkers(ReflectionNode reflectionNode, ITypeDefOrRef markerInterface, WeavingContext context)
        {
            var markers = reflectionNode.GetAncestorsToChildren()
                          .SelectMany(n => n.CustomAttributes
                                      .Where(a => !a.AttributeType.DefinitionAssembly.IsSystem())
                                      .SelectMany(a => TypeResolver.Resolve(a.AttributeType).GetSelfAndParents())
                                      .Where(t => IsMarker(t, markerInterface)))
                          .Distinct()
                          .Select(t => GetMarkerDefinition(t, context));

            return(markers);
        }
コード例 #7
0
ファイル: AspectWeaver.cs プロジェクト: freeman6/MrAdvice
        private IEnumerable <TypeDef> GetDynamicHandledInterfaces(ModuleDef moduleDefinition)
        {
            var dynamicHandleAttributeType = TypeResolver.Resolve(moduleDefinition, typeof(DynamicHandleAttribute));

            foreach (var interfaceDefinition in moduleDefinition.Types.Where(t => t.IsInterface))
            {
                if (interfaceDefinition.CustomAttributes.Any(c => c.AttributeType.SafeEquivalent(dynamicHandleAttributeType)))
                {
                    yield return(interfaceDefinition);
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Gets the advice handled interfaces.
        /// This is done by analyzing calls in all methods from module
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <returns></returns>
        private IEnumerable <TypeReference> GetAdviceHandledInterfaces(ModuleDefinition moduleDefinition)
        {
            // the first method to look for in the final AdviceExtensions.Handle<>() method
            var adviceExtensionsType = TypeResolver.Resolve(moduleDefinition, typeof(AdviceExtensions));
            var adviceHandleMethod   = adviceExtensionsType.GetMethods().Single(m => m.IsPublic && m.HasGenericParameters && m.Name == nameof(AdviceExtensions.Handle));
            var methodsSearched      = new HashSet <MethodReference>(new MethodReferenceComparer())
            {
                adviceHandleMethod
            };
            var foundHandledInterfaces = new HashSet <TypeReference>(new TypeReferenceComparer());
            var methodsToSearch        = new List <Tuple <MethodDefinition, int> > {
                Tuple.Create(adviceHandleMethod, 0)
            };

            while (methodsToSearch.Count > 0)
            {
                var methodToSearch = methodsToSearch[0];
                methodsToSearch.RemoveAt(0);
                foreach (var t in GetAdviceHandledInterfaces(moduleDefinition, methodToSearch.Item1, methodToSearch.Item2))
                {
                    // if the supposed interface type itself is a generic parameter
                    // this means that the calling method (Item2) is itself a generic parameter
                    // and we have to lookup for calls to this method
                    if (t.Item1.IsGenericParameter)
                    {
                        if (!methodsSearched.Contains(t.Item2))
                        {
                            // ReSharper disable once AccessToForEachVariableInClosure
                            var parameterIndex = t.Item2.GenericParameters.IndexOf(p => p.Name == t.Item1.Name);
                            methodsSearched.Add(t.Item2);
                            methodsToSearch.Add(Tuple.Create(t.Item2, parameterIndex));
                            Logger.WriteDebug("Now looking for references to '{0} [{1}]'", methodToSearch, parameterIndex);
                        }
                    }
                    // only interfaces are processed by now
                    else if (t.Item1.Resolve().IsInterface)
                    {
                        // otherwise, this is a direct call, keep the injected interface name
                        if (!foundHandledInterfaces.Contains(t.Item1))
                        {
                            foundHandledInterfaces.Add(t.Item1);
                            yield return(t.Item1);
                        }
                    }
                }
            }
        }
コード例 #9
0
ファイル: AspectWeaver.cs プロジェクト: TheXenocide/MrAdvice
        private WeavingContext CreateWeavingContext(ModuleDefMD moduleDefinition)
        {
            var context = new WeavingContext
            {
                CompilerGeneratedAttributeType     = moduleDefinition.Import(typeof(CompilerGeneratedAttribute)),
                PriorityAttributeType              = TypeResolver.Resolve(moduleDefinition, typeof(PriorityAttribute)),
                AbstractTargetAttributeType        = TypeResolver.Resolve(moduleDefinition, typeof(AbstractTargetAttribute)),
                AdviceInterfaceType                = TypeResolver.Resolve(moduleDefinition, typeof(IAdvice)),
                WeavingAdviceInterfaceType         = TypeResolver.Resolve(moduleDefinition, typeof(IWeavingAdvice)),
                ExecutionPointAttributeDefaultCtor = moduleDefinition.Import(TypeResolver.Resolve(moduleDefinition, typeof(ExecutionPointAttribute)).FindDefaultConstructor()),
                ExcludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(ExcludePointcutAttribute)),
                IncludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(IncludePointcutAttribute)),
                ExcludeAdviceAttributeType         = TypeResolver.Resolve(moduleDefinition, typeof(ExcludeAdvicesAttribute)),
            };

            return(context);
        }
コード例 #10
0
 private IMethod GetDefaultProceedMethod(ModuleDef module, WeavingContext context)
 {
     if (context.InvocationProceedMethod == null)
     {
         var invocationType = TypeResolver.Resolve(module, typeof(Invocation));
         if (invocationType == null)
         {
             throw new InvalidOperationException();
         }
         var proceedMethodReference = invocationType.Methods.SingleOrDefault(m => m.IsStatic && m.Name == nameof(Invocation.ProceedAdvice2));
         if (proceedMethodReference == null)
         {
             throw new InvalidOperationException();
         }
         context.InvocationProceedMethod = module.SafeImport(proceedMethodReference);
     }
     return(context.InvocationProceedMethod);
 }
コード例 #11
0
ファイル: AspectWeaver.cs プロジェクト: freeman6/MrAdvice
        private WeavingContext CreateWeavingContext(ModuleDef moduleDefinition)
        {
            var context = new WeavingContext
            {
                CompilerGeneratedAttributeType     = moduleDefinition.Import(typeof(CompilerGeneratedAttribute)),
                PriorityAttributeType              = TypeResolver.Resolve(moduleDefinition, typeof(PriorityAttribute)),
                AbstractTargetAttributeType        = TypeResolver.Resolve(moduleDefinition, typeof(AbstractTargetAttribute)),
                AdviceInterfaceType                = TypeResolver.Resolve(moduleDefinition, typeof(IAdvice)),
                WeavingAdviceInterfaceType         = TypeResolver.Resolve(moduleDefinition, typeof(IWeavingAdvice)),
                ExecutionPointAttributeDefaultCtor = moduleDefinition.Import(TypeResolver.Resolve(moduleDefinition, typeof(ExecutionPointAttribute))?.FindDefaultConstructor()),
                ExcludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(ExcludePointcutAttribute)),
                IncludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(IncludePointcutAttribute)),
                ExcludeAdviceAttributeType         = TypeResolver.Resolve(moduleDefinition, typeof(ExcludeAdvicesAttribute)),
                IntroducedFieldType                = TypeResolver.Resolve(moduleDefinition, typeof(IntroducedField <>)),
                SharedIntroducedFieldType          = TypeResolver.Resolve(moduleDefinition, typeof(SharedIntroducedField <>)),
#pragma warning disable 618
                IntroducedFieldsType = TypeResolver.Resolve(moduleDefinition, typeof(IntroducedFieldsRegistry)),
#pragma warning restore 618
            };

            if (context.AdviceInterfaceType is not null)
            {
                if (context.ExecutionPointAttributeDefaultCtor is null)
                {
                    Logging.WriteError("ExecutionPointAttribute default ctor was not found");
                }

                if (context.ExcludePointcutAttributeType is null)
                {
                    Logging.WriteError("ExcludePointcutAttributeType was not found");
                }
                if (context.IncludePointcutAttributeType is null)
                {
                    Logging.WriteError("IncludePointcutAttributeType was not found");
                }
                if (context.ExcludeAdviceAttributeType is null)
                {
                    Logging.WriteError("ExcludeAdviceAttributeType was not found");
                }
            }

            return(context);
        }
コード例 #12
0
        /// <summary>
        /// Weaves the introductions.
        /// Introduces members as requested by aspects
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="context">The context.</param>
        private void WeaveIntroductions(MethodDef method, ModuleDef moduleDefinition, WeavingContext context)
        {
            var typeDefinition         = method.DeclaringType;
            var advices                = GetAllMarkers(new MethodReflectionNode(method, null), context.AdviceInterfaceType, context);
            var markerAttributeCtor    = moduleDefinition.SafeImport(TypeResolver.Resolve(moduleDefinition, typeof(IntroducedFieldAttribute)).FindConstructors().Single());
            var markerAttributeCtorDef = new MemberRefUser(markerAttributeCtor.Module, markerAttributeCtor.Name, markerAttributeCtor.MethodSig, markerAttributeCtor.DeclaringType);

            foreach (var advice in advices)
            {
                var adviceDefinition = advice.Type;
                foreach (var field in adviceDefinition.Fields.Where(f => f.IsPublic))
                {
                    IntroduceMember(method.Module, field.Name, field.FieldType.ToTypeDefOrRef(), field.IsStatic, advice.Type, typeDefinition, markerAttributeCtorDef);
                }
                foreach (var property in adviceDefinition.Properties.Where(p => p.HasAnyPublic()))
                {
                    IntroduceMember(method.Module, property.Name, property.PropertySig.RetType.ToTypeDefOrRef(), !property.PropertySig.HasThis, advice.Type, typeDefinition, markerAttributeCtorDef);
                }
            }
        }
コード例 #13
0
        /// <summary>
        /// Weaves the introductions.
        /// Introduces members as requested by aspects
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="adviceInterface">The advice interface.</param>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="types">The types.</param>
        private void WeaveIntroductions(MethodDefinition method, TypeDefinition adviceInterface, ModuleDefinition moduleDefinition, Types types)
        {
            var typeDefinition      = method.DeclaringType;
            var advices             = GetAllMarkers(new MethodReflectionNode(method), adviceInterface, types);
            var markerAttributeCtor = moduleDefinition.SafeImport(TypeResolver.Resolve(moduleDefinition, typeof(IntroducedFieldAttribute))
                                                                  .GetConstructors().Single());

            foreach (var advice in advices)
            {
                var adviceDefinition = advice.Type.Resolve();
                foreach (var field in adviceDefinition.Fields.Where(f => f.IsPublic))
                {
                    IntroduceMember(method.Module, field.Name, field.FieldType, field.IsStatic, advice.Type, typeDefinition, markerAttributeCtor);
                }
                foreach (var property in adviceDefinition.Properties.Where(p => p.HasAnyPublic()))
                {
                    IntroduceMember(method.Module, property.Name, property.PropertyType, !property.HasThis, advice.Type, typeDefinition, markerAttributeCtor);
                }
            }
        }
コード例 #14
0
        /// <summary>
        /// Weaves the info advices for the given type.
        /// </summary>
        /// <param name="infoAdvisedType">Type of the module.</param>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="useWholeAssembly">if set to <c>true</c> [use whole assembly].</param>
        private void WeaveInfoAdvices(TypeDef infoAdvisedType, ModuleDef moduleDefinition, bool useWholeAssembly)
        {
            var invocationType = TypeResolver.Resolve(moduleDefinition, typeof(Invocation));

            if (invocationType == null)
            {
                return;
            }
            var proceedRuntimeInitializersReference = (from m in invocationType.Methods
                                                       where m.IsStatic && m.Name == nameof(Invocation.ProcessInfoAdvices)
                                                       let parameters = m.Parameters
                                                                        where parameters.Count == 1 &&
                                                                        parameters[0].Type.SafeEquivalent(
                                                           moduleDefinition.SafeImport(useWholeAssembly ? typeof(Assembly) : typeof(Type)).ToTypeSig())
                                                                        select m).SingleOrDefault();

            if (proceedRuntimeInitializersReference == null)
            {
                Logging.WriteWarning("Info advice method not found");
                return;
            }

            var instructions  = GetCctorInstructions(infoAdvisedType);
            var proceedMethod = moduleDefinition.SafeImport(proceedRuntimeInitializersReference);

            if (useWholeAssembly)
            {
                instructions.Emit(OpCodes.Call, moduleDefinition.SafeImport(ReflectionUtility.GetMethodInfo(() => Assembly.GetExecutingAssembly())));
            }
            else
            {
                instructions.Emit(OpCodes.Ldtoken, TypeImporter.Import(moduleDefinition, infoAdvisedType.ToTypeSig()));
                // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                var getTypeFromHandleMethodInfo = ReflectionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(new RuntimeTypeHandle()));
                instructions.Emit(OpCodes.Call, moduleDefinition.SafeImport(getTypeFromHandleMethodInfo));
            }
            instructions.Emit(OpCodes.Call, proceedMethod);
        }
コード例 #15
0
ファイル: AspectWeaver.cs プロジェクト: tom123123123/MrAdvice
        private WeavingContext CreateWeavingContext(ModuleDef moduleDefinition)
        {
            var context = new WeavingContext
            {
                CompilerGeneratedAttributeType     = moduleDefinition.Import(typeof(CompilerGeneratedAttribute)),
                PriorityAttributeType              = TypeResolver.Resolve(moduleDefinition, typeof(PriorityAttribute)),
                AbstractTargetAttributeType        = TypeResolver.Resolve(moduleDefinition, typeof(AbstractTargetAttribute)),
                AdviceInterfaceType                = TypeResolver.Resolve(moduleDefinition, typeof(IAdvice)),
                WeavingAdviceInterfaceType         = TypeResolver.Resolve(moduleDefinition, typeof(IWeavingAdvice)),
                ExecutionPointAttributeDefaultCtor = moduleDefinition.Import(TypeResolver.Resolve(moduleDefinition, typeof(ExecutionPointAttribute))?.FindDefaultConstructor()),
                ExcludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(ExcludePointcutAttribute)),
                IncludePointcutAttributeType       = TypeResolver.Resolve(moduleDefinition, typeof(IncludePointcutAttribute)),
                ExcludeAdviceAttributeType         = TypeResolver.Resolve(moduleDefinition, typeof(ExcludeAdvicesAttribute)),
            };

            if (context.AdviceInterfaceType != null)
            {
                if (context.ExecutionPointAttributeDefaultCtor == null)
                {
                    Logging.WriteError("ExecutionPointAttribute default ctor was not found");
                }

                if (context.ExcludePointcutAttributeType == null)
                {
                    Logging.WriteError("ExcludePointcutAttributeType was not found");
                }
                if (context.IncludePointcutAttributeType == null)
                {
                    Logging.WriteError("IncludePointcutAttributeType was not found");
                }
                if (context.ExcludeAdviceAttributeType == null)
                {
                    Logging.WriteError("ExcludeAdviceAttributeType was not found");
                }
            }

            return(context);
        }
コード例 #16
0
ファイル: AspectWeaver.cs プロジェクト: freeman6/MrAdvice
        /// <summary>
        /// Weaves the specified module definition.
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        public bool Weave(ModuleDefMD moduleDefinition)
        {
            var auditTimer = new AuditTimer();

            try
            {
                // sanity check
                auditTimer.NewZone("Types import");
                // context
                var context = CreateWeavingContext(moduleDefinition);
                if (context.AdviceInterfaceType == null)
                {
                    Logging.WriteWarning("IAdvice interface not found here (not referenced means not used), exiting");
                    return(false);
                }
                // runtime check
                auditTimer.NewZone("Runtime check");
                var targetFramework = GetTargetFramework(moduleDefinition);
                InjectAsPrivate = targetFramework.Silverlight is null && targetFramework.WindowsPhone is null;

                // weave methods (they can be property-related, too)
                auditTimer.NewZone("Weavable methods detection");
                Func <MarkedNode, bool> isWeavable = n => !IsFromComputerGeneratedType(n) && IsWeavable(n);
                var weavingAdvicesMethods          = GetMarkedMethods(moduleDefinition, context.WeavingAdviceInterfaceType, context).Where(isWeavable).ToArray();
                var weavableMethods = GetMarkedMethods(moduleDefinition, context.AdviceInterfaceType, context).Where(isWeavable).ToArray();
                auditTimer.NewZone("Abstract targets");
                var generatedFieldsToBeRemoved = new List <FieldDef>();
                var methodsWithAbstractTarget  = weavableMethods.Where(m => m.AbstractTarget).ToArray();
                if (methodsWithAbstractTarget.Length > 0)
                {
                    generatedFieldsToBeRemoved.AddRange(GetRemovableFields(methodsWithAbstractTarget, context));
                    foreach (var fieldReference in generatedFieldsToBeRemoved)
                    {
                        Logging.WriteDebug("Field {0} to be removed", fieldReference.FullName);
                    }
                }
                auditTimer.NewZone("Methods weaving advice");
                weavingAdvicesMethods.ForAll(i => RunWeavingAdvices(i, context));
                auditTimer.NewZone("Methods weaving");
                weavableMethods.ForAll(m => WeaveMethod(moduleDefinition, m, context));

                auditTimer.NewZone("Weavable interfaces detection");
                var weavableInterfaces = GetAdviceHandledInterfaces(moduleDefinition).Union(GetDynamicHandledInterfaces(moduleDefinition)).ToArray();
                auditTimer.NewZone("Interface methods weaving");
                weavableInterfaces.ForAll(i => WeaveInterface(moduleDefinition, i, context));

                // and then, the info advices
                auditTimer.NewZone("Info advices weaving");
                var infoAdviceInterface = TypeResolver.Resolve(moduleDefinition, typeof(IInfoAdvice));
                moduleDefinition.GetTypes().ForAll(t => WeaveInfoAdvices(moduleDefinition, t, infoAdviceInterface, context));

                auditTimer.NewZone("Abstract targets cleanup");
                foreach (var generatedFieldToBeRemoved in generatedFieldsToBeRemoved)
                {
                    generatedFieldToBeRemoved.DeclaringType.Fields.Remove(generatedFieldToBeRemoved);
                }
                auditTimer.LastZone();

                var report    = auditTimer.GetReport();
                var maxLength = report.Keys.Max(k => k.Length);
                Logging.WriteDebug("--- Timings --------------------------");
                foreach (var reportPart in report)
                {
                    Logging.WriteDebug("{0} : {1}ms", reportPart.Key.PadRight(maxLength), (int)reportPart.Value.TotalMilliseconds);
                }
                Logging.WriteDebug("--------------------------------------");

                var thisAssembly = GetType().Assembly;
                var thisVersion  = thisAssembly.GetCustomAttribute <AssemblyVersionAttribute>()?.Version
                                   ?? thisAssembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion;
                var thisTargetFramework = TargetFramework.FromLiteral(thisAssembly.GetCustomAttribute <TargetFrameworkAttribute>()?.FrameworkName);
                Logging.Write("MrAdvice {3}/{4} weaved module '{0}' (targeting framework {2}) in {1}ms",
                              moduleDefinition.Assembly.FullName, (int)report.Sum(r => r.Value.TotalMilliseconds), targetFramework.ToString(),
                              thisVersion, thisTargetFramework);

                return(true);
            }
            catch (Exception e)
            {
                Logging.WriteError("Internal error during {0}: {1}", auditTimer.CurrentZoneName, e);
                Logging.WriteError("Please complain, whine, cry, yell at https://github.com/ArxOne/MrAdvice/issues/new");
                return(false);
            }
        }
コード例 #17
0
ファイル: AspectWeaver.cs プロジェクト: freeman6/MrAdvice
        /// <summary>
        /// Gets the advice handled interfaces.
        /// This is done by analyzing calls in all methods from module
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <returns></returns>
        private IEnumerable <TypeDef> GetAdviceHandledInterfaces(ModuleDef moduleDefinition)
        {
            // the first method to look for in the final AdviceExtensions.Handle<>() method
            var adviceExtensionsType = TypeResolver.Resolve(moduleDefinition, typeof(AdviceExtensions));
            var adviceHandleMethod   = adviceExtensionsType.Methods.Single(m => m.IsPublic && m.HasGenericParameters && m.Name == nameof(AdviceExtensions.Handle));
            var methodsSearched      = new HashSet <MethodDef>(new MethodReferenceComparer())
            {
                adviceHandleMethod
            };
            var foundHandledInterfaces = new HashSet <ITypeDefOrRef>(new TypeReferenceComparer());
            var methodsToSearch        = new List <Tuple <MethodDef, int> > {
                Tuple.Create(adviceHandleMethod, 0)
            };

            while (methodsToSearch.Count > 0)
            {
                var methodToSearch = methodsToSearch[0];
                methodsToSearch.RemoveAt(0);
                foreach (var t in GetAdviceHandledInterfaces(moduleDefinition, methodToSearch.Item1, methodToSearch.Item2))
                {
                    // if the supposed interface type itself is a generic parameter
                    // this means that the calling method (Item2) is itself a generic parameter
                    // and we have to lookup for calls to this method
                    if (t.Item1.ContainsGenericParameter)
                    {
                        if (!methodsSearched.Contains(t.Item2))
                        {
                            // ReSharper disable once AccessToForEachVariableInClosure
                            var parameterIndex = t.Item2.GenericParameters.IndexOf(p => p.Name == t.Item1.TypeName);
                            methodsSearched.Add(t.Item2);
                            methodsToSearch.Add(Tuple.Create(t.Item2, parameterIndex));
                            Logging.WriteDebug("Now looking for references to '{0} [{1}]'", methodToSearch.Item1.ToString(), parameterIndex);
                        }
                    }
                    // only interfaces are processed by now
                    else
                    {
                        var interfaceDef = t.Item1 as TypeDef;
                        if (interfaceDef is null)
                        {
                            if (t.Item1 is TypeRef interfaceRef)
                            {
                                interfaceDef = TypeResolver.Resolve(interfaceRef);
                            }
                        }
                        if (interfaceDef is null)
                        {
                            Logging.WriteError("Can not identify {0} as valid weavable interface. If you feel this is unfair --> https://github.com/ArxOne/MrAdvice/issues/new", t.Item1.ToString());
                            continue;
                        }
                        if (interfaceDef.IsInterface)
                        {
                            // otherwise, this is a direct call, keep the injected interface name
                            if (!foundHandledInterfaces.Contains(t.Item1))
                            {
                                foundHandledInterfaces.Add(t.Item1);
                                yield return(interfaceDef);
                            }
                        }
                        else
                        {
                            Logging.WriteError("Only interfaces can be weaved with Handle<>() extension method and {0} it not an interface (but I’m glad you asked)", interfaceDef.FullName);
                        }
                    }
                }
            }
        }
コード例 #18
0
        /// <summary>
        /// Writes the pointcut body.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="innerMethod">The inner method.</param>
        /// <param name="abstractedTarget">if set to <c>true</c> [abstracted target].</param>
        /// <exception cref="System.InvalidOperationException">
        /// </exception>
        private void WritePointcutBody(MethodDefinition method, MethodDefinition innerMethod, bool abstractedTarget)
        {
            var moduleDefinition = method.Module;

            // now empty the old one and make it call the inner method...
            if (method.Body == null)
            {
                method.Body = new MethodBody(method);
            }
            method.Body.InitLocals = true;
            method.Body.Instructions.Clear();
            method.Body.Variables.Clear();
            method.Body.ExceptionHandlers.Clear();
            var instructions = new Instructions(method.Body.Instructions, method.Module);

            var isStatic = method.Attributes.HasFlag(MethodAttributes.Static);

            // parameters
            VariableDefinition parametersVariable = null;

            if (method.Parameters.Count > 0)
            {
                parametersVariable = new VariableDefinition("parameters", moduleDefinition.SafeImport(typeof(object[])));
                method.Body.Variables.Add(parametersVariable);

                instructions.EmitLdc(method.Parameters.Count);
                instructions.Emit(OpCodes.Newarr, moduleDefinition.SafeImport(typeof(object)));
                instructions.EmitStloc(parametersVariable);
                // setups parameters array
                for (int parameterIndex = 0; parameterIndex < method.Parameters.Count; parameterIndex++)
                {
                    var parameter = method.Parameters[parameterIndex];
                    // we don't care about output parameters
                    if (!parameter.IsOut)
                    {
                        instructions.EmitLdloc(parametersVariable); // array
                        instructions.EmitLdc(parameterIndex);       // array index
                        instructions.EmitLdarg(parameter);          // loads given parameter...
                        var parameterType = parameter.ParameterType;
                        if (parameter.ParameterType.IsByReference)  // ...if ref, loads it as referenced value
                        {
                            parameterType = parameter.ParameterType.GetElementType();
                            instructions.EmitLdind(parameterType);
                        }
                        instructions.EmitBoxIfNecessary(parameterType); // ... and boxes it
                        instructions.Emit(OpCodes.Stelem_Ref);
                    }
                }
            }

            // if method has generic parameters, we also pass them to Proceed method
            VariableDefinition genericParametersVariable = null;
            // on static methods from genetic type, we also record the generic parameters type
            //var typeGenericParametersCount = isStatic ? method.DeclaringType.GenericParameters.Count : 0;
            var typeGenericParametersCount = method.DeclaringType.GenericParameters.Count;

            if (typeGenericParametersCount > 0 || method.HasGenericParameters)
            {
                //IL_0001: ldtoken !!T
                //IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
                genericParametersVariable = new VariableDefinition("genericParameters", moduleDefinition.SafeImport(typeof(Type[])));
                method.Body.Variables.Add(genericParametersVariable);

                instructions.EmitLdc(typeGenericParametersCount + method.GenericParameters.Count);
                instructions.Emit(OpCodes.Newarr, moduleDefinition.SafeImport(typeof(Type)));
                instructions.EmitStloc(genericParametersVariable);

                var genericParameters = new List <GenericParameter>();
                for (int typeGenericParameterIndex = 0; typeGenericParameterIndex < typeGenericParametersCount; typeGenericParameterIndex++)
                {
                    genericParameters.Add(method.DeclaringType.GenericParameters[typeGenericParameterIndex]);
                }
                genericParameters.AddRange(method.GenericParameters);

                for (int genericParameterIndex = 0; genericParameterIndex < genericParameters.Count; genericParameterIndex++)
                {
                    instructions.EmitLdloc(genericParametersVariable); // array
                    instructions.EmitLdc(genericParameterIndex);       // array index
                    instructions.Emit(OpCodes.Ldtoken, genericParameters[genericParameterIndex]);
                    // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                    instructions.Emit(OpCodes.Call, ReflectionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(new RuntimeTypeHandle())));
                    instructions.Emit(OpCodes.Stelem_Ref);
                }
            }

            // null or instance
            instructions.Emit(isStatic ? OpCodes.Ldnull : OpCodes.Ldarg_0);
            // to fix peverify 0x80131854
            if (!isStatic && method.IsConstructor)
            {
                instructions.Emit(OpCodes.Castclass, typeof(object));
            }

            // parameters
            if (parametersVariable != null)
            {
                instructions.EmitLdloc(parametersVariable);
            }
            else
            {
                instructions.Emit(OpCodes.Ldnull);
            }

            // methods...
            // ... target
            // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
            instructions.Emit(OpCodes.Call, ReflectionUtility.GetMethodInfo(() => MethodBase.GetCurrentMethod()));

            // ... inner... If provided
            if (innerMethod != null)
            {
                // if type is generic, this is a bit more complex, because we need to pass the type
                if (method.DeclaringType.HasGenericParameters)
                {
                    // we want to reuse the MethodBase.GetCurrentMethod() result
                    // so it is stored into a variable, whose property DeclaringType is invoked later
                    var currentMethodVariable = new VariableDefinition("currentMethod", moduleDefinition.SafeImport(typeof(MethodBase)));
                    method.Body.Variables.Add(currentMethodVariable);
                    instructions.EmitStloc(currentMethodVariable);
                    instructions.EmitLdloc(currentMethodVariable);

                    instructions.Emit(OpCodes.Ldtoken, innerMethod);
                    instructions.EmitLdloc(currentMethodVariable);
                    instructions.Emit(OpCodes.Callvirt, ReflectionUtility.GetMethodInfo((Type t) => t.DeclaringType));
                    instructions.Emit(OpCodes.Callvirt, ReflectionUtility.GetMethodInfo((Type t) => t.TypeHandle));
                    // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                    instructions.Emit(OpCodes.Call, ReflectionUtility.GetMethodInfo(() => MethodBase.GetMethodFromHandle(new RuntimeMethodHandle(), new RuntimeTypeHandle())));
                }
                else
                {
                    instructions.Emit(OpCodes.Ldtoken, innerMethod);
                    // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                    instructions.Emit(OpCodes.Call, ReflectionUtility.GetMethodInfo(() => MethodBase.GetMethodFromHandle(new RuntimeMethodHandle())));
                }
            }
            else
            {
                instructions.Emit(OpCodes.Ldnull);
            }

            // abstracted target
            instructions.Emit(abstractedTarget ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);

            if (genericParametersVariable != null)
            {
                instructions.EmitLdloc(genericParametersVariable);
            }
            else
            {
                instructions.Emit(OpCodes.Ldnull);
            }

            // invoke the method
            var invocationType = TypeResolver.Resolve(moduleDefinition, typeof(Invocation));

            if (invocationType == null)
            {
                throw new InvalidOperationException();
            }
            var proceedMethodReference = invocationType.GetMethods().SingleOrDefault(m => m.IsStatic && m.Name == nameof(Invocation.ProceedAdvice));

            if (proceedMethodReference == null)
            {
                throw new InvalidOperationException();
            }
            var proceedMethod = moduleDefinition.SafeImport(proceedMethodReference);

            instructions.Emit(OpCodes.Call, proceedMethod);

            // get return value
            if (!method.ReturnType.SafeEquivalent(moduleDefinition.SafeImport(typeof(void))))
            {
                instructions.EmitUnboxOrCastIfNecessary(method.ReturnType);
            }
            else
            {
                instructions.Emit(OpCodes.Pop); // if no return type, ignore Proceed() result
            }
            // loads back out/ref parameters
            for (int parameterIndex = 0; parameterIndex < method.Parameters.Count; parameterIndex++)
            {
                var parameter = method.Parameters[parameterIndex];
                if (parameter.ParameterType.IsByReference)
                {
                    instructions.EmitLdarg(parameter);             // loads given parameter (it is a ref)
                    instructions.EmitLdloc(parametersVariable);    // array
                    instructions.EmitLdc(parameterIndex);          // array index
                    instructions.Emit(OpCodes.Ldelem_Ref);         // now we have boxed out/ref value
                    var parameterElementType = parameter.ParameterType.GetElementType();
                    if (parameterElementType.HasGenericParameters) // a generic type requires the correct inner type
                    {
                        var referenceParameterType = (ByReferenceType)parameter.ParameterType;
                        parameterElementType = (GenericInstanceType)referenceParameterType.ElementType;
                    }
                    instructions.EmitUnboxOrCastIfNecessary(parameterElementType);
                    instructions.EmitStind(parameterElementType); // result is stored in ref parameter
                }
            }

            // and return
            instructions.Emit(OpCodes.Ret);
        }
コード例 #19
0
        /// <summary>
        /// Weaves the specified module definition.
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        public void Weave(ModuleDefinition moduleDefinition)
        {
            var auditTimer = new AuditTimer();
            var stopwatch  = new Stopwatch();

            stopwatch.Start();

            // sanity check
            auditTimer.NewZone("IAdvice location");
            var adviceInterface = TypeResolver.Resolve(moduleDefinition, typeof(IAdvice));

            if (adviceInterface == null)
            {
                Logger.WriteWarning("IAdvice interface not found here (not referenced means not used), exiting");
                return;
            }

            // context
            var types = new Types
            {
                CompilerGeneratedAttributeType = moduleDefinition.Import(typeof(CompilerGeneratedAttribute)),
                PriorityAttributeType          = TypeResolver.Resolve(moduleDefinition, typeof(PriorityAttribute)),
                AbstractTargetAttributeType    = TypeResolver.Resolve(moduleDefinition, typeof(AbstractTargetAttribute)),
                WeavingAdviceAttributeType     = TypeResolver.Resolve(moduleDefinition, typeof(IWeavingAdvice))
            };

            // runtime check
            auditTimer.NewZone("Runtime check");
            var targetFramework = GetTargetFramework(moduleDefinition);

            InjectAsPrivate = targetFramework.Silverlight == null && targetFramework.WindowsPhone == null;

            //Logger.WriteDebug("t1: {0}ms", (int)stopwatch.ElapsedMilliseconds);

            // weave methods (they can be property-related, too)
            auditTimer.NewZone("Weavable methods detection");
            var weavableMethods = GetMarkedMethods(moduleDefinition, adviceInterface, types).Where(IsWeavable).ToArray();

            auditTimer.NewZone("Abstract targets");
            var generatedFieldsToBeRemoved = new List <FieldReference>();
            var methodsWithAbstractTarget  = weavableMethods.Where(m => m.AbstractTarget).ToArray();

            if (methodsWithAbstractTarget.Length > 0)
            {
                generatedFieldsToBeRemoved.AddRange(GetRemovableFields(methodsWithAbstractTarget, types));
                foreach (var fieldReference in generatedFieldsToBeRemoved)
                {
                    Logger.WriteDebug("Field {0} to be removed", fieldReference.FullName);
                }
            }
            auditTimer.NewZone("Methods weaving");
            weavableMethods.AsParallel().ForAll(m => WeaveMethod(moduleDefinition, m, adviceInterface, types));

            auditTimer.NewZone("Weavable interfaces detection");
            var weavableInterfaces = GetAdviceHandledInterfaces(moduleDefinition).ToArray();

            auditTimer.NewZone("Interface methods weaving");
            weavableInterfaces.AsParallel().ForAll(i => WeaveInterface(moduleDefinition, i));

            //Logger.WriteDebug("t2: {0}ms", (int)stopwatch.ElapsedMilliseconds);

            // and then, the info advices
            auditTimer.NewZone("Info advices weaving");
            var infoAdviceInterface = TypeResolver.Resolve(moduleDefinition, typeof(IInfoAdvice));

            moduleDefinition.GetTypes()
            .AsParallel()
            .ForAll(t => WeaveInfoAdvices(moduleDefinition, t, infoAdviceInterface, types));

            auditTimer.NewZone("Abstract targets cleanup");
            foreach (var generatedFieldToBeRemoved in generatedFieldsToBeRemoved)
            {
                generatedFieldToBeRemoved.DeclaringType.Resolve().Fields.Remove(generatedFieldToBeRemoved.Resolve());
            }

            auditTimer.LastZone();

            //Logger.WriteDebug("t3: {0}ms", (int)stopwatch.ElapsedMilliseconds);

            var report    = auditTimer.GetReport();
            var maxLength = report.Keys.Max(k => k.Length);

            Logger.WriteDebug("--- Timings --------------------------");
            foreach (var reportPart in report)
            {
                Logger.WriteDebug("{0} : {1}ms", reportPart.Key.PadRight(maxLength),
                                  (int)reportPart.Value.TotalMilliseconds);
            }
            Logger.WriteDebug("--------------------------------------");

            Logger.Write("MrAdvice {3} weaved module '{0}' (targeting framework {2}) in {1}ms",
                         moduleDefinition.Assembly.FullName, (int)stopwatch.ElapsedMilliseconds, targetFramework, Product.Version);
        }
コード例 #20
0
        /// <summary>
        /// Weaves the interface.
        /// What we do here is:
        /// - creating a class (which is named after the interface name)
        /// - this class implements all interface members
        /// - all members invoke Invocation.ProcessInterfaceMethod
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="interfaceType">Type of the interface.</param>
        /// <param name="context">The context.</param>
        private void WeaveInterface(ModuleDefMD moduleDefinition, TypeDef interfaceType, WeavingContext context)
        {
            var importedInterfaceType = moduleDefinition.Import(interfaceType);

            Logging.WriteDebug("Weaving interface '{0}'", interfaceType.FullName);
            TypeDef implementationType;
            TypeDef advisedInterfaceType;

            lock (moduleDefinition)
            {
                // ensure we're creating the interface only once
                var implementationTypeName      = GetImplementationTypeName(interfaceType.Name);
                var implementationTypeNamespace = interfaceType.Namespace;
                if (moduleDefinition.GetTypes().Any(t => t.Namespace == implementationTypeNamespace && t.Name == implementationTypeName))
                {
                    return;
                }

                // now, create the implementation type
                var typeAttributes = (InjectAsPrivate ? TypeAttributes.NotPublic : TypeAttributes.Public) | TypeAttributes.Class |
                                     TypeAttributes.BeforeFieldInit;
                advisedInterfaceType = TypeResolver.Resolve(moduleDefinition, typeof(AdvisedInterface));
                // TODO: this should work using TypeImporter.Import
                var advisedInterfaceTypeReference = moduleDefinition.Import(advisedInterfaceType);
                implementationType = new TypeDefUser(implementationTypeNamespace, implementationTypeName, advisedInterfaceTypeReference)
                {
                    Attributes = typeAttributes
                };
                implementationType.Interfaces.Add(new InterfaceImplUser(importedInterfaceType));

                lock (moduleDefinition)
                    moduleDefinition.Types.Add(implementationType);
            }

            // create empty .ctor. This .NET mofo wants it!
            var baseEmptyConstructor = moduleDefinition.SafeImport(advisedInterfaceType.FindConstructors().Single());
            const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
                                                    MethodAttributes.RTSpecialName;
            var method = new MethodDefUser(".ctor", baseEmptyConstructor.MethodSig, ctorAttributes);

            method.Body = new CilBody();
            method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
            method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, baseEmptyConstructor));
            method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
            implementationType.Methods.Add(method);

            // create implementation methods
            foreach (var currentInterfaceType in interfaceType.GetAllInterfaces(TypeResolver))
            {
                foreach (var interfaceMethod in currentInterfaceType.Methods.Where(m => !m.IsSpecialName))
                {
                    WeaveInterfaceMethod(interfaceMethod, implementationType, true, context);
                }

                // create implementation properties
                foreach (var interfaceProperty in currentInterfaceType.Properties)
                {
                    var implementationProperty = new PropertyDefUser(interfaceProperty.Name, interfaceProperty.PropertySig);
                    implementationType.Properties.Add(implementationProperty);
                    if (interfaceProperty.GetMethod != null)
                    {
                        implementationProperty.GetMethod = WeaveInterfaceMethod(interfaceProperty.GetMethod, implementationType, InjectAsPrivate, context);
                    }
                    if (interfaceProperty.SetMethod != null)
                    {
                        implementationProperty.SetMethod = WeaveInterfaceMethod(interfaceProperty.SetMethod, implementationType, InjectAsPrivate, context);
                    }
                }

                // create implementation events
                foreach (var interfaceEvent in currentInterfaceType.Events)
                {
                    var implementationEvent = new EventDefUser(interfaceEvent.Name, interfaceEvent.EventType);
                    implementationType.Events.Add(implementationEvent);
                    if (interfaceEvent.AddMethod != null)
                    {
                        implementationEvent.AddMethod = WeaveInterfaceMethod(interfaceEvent.AddMethod, implementationType, InjectAsPrivate, context);
                    }
                    if (interfaceEvent.RemoveMethod != null)
                    {
                        implementationEvent.RemoveMethod = WeaveInterfaceMethod(interfaceEvent.RemoveMethod, implementationType, InjectAsPrivate, context);
                    }
                }
            }
        }
コード例 #21
0
        /// <summary>
        /// Weaves the interface.
        /// What we do here is:
        /// - creating a class (wich is named after the interface name)
        /// - this class implements all interface members
        /// - all members invoke Invocation.ProcessInterfaceMethod
        /// </summary>
        /// <param name="moduleDefinition">The module definition.</param>
        /// <param name="interfaceType">Type of the interface.</param>
        private void WeaveInterface(ModuleDefinition moduleDefinition, TypeReference interfaceType)
        {
            Logger.WriteDebug("Weaving interface '{0}'", interfaceType.FullName);
            TypeDefinition implementationType;
            TypeDefinition advisedInterfaceType;
            TypeDefinition interfaceTypeDefinition;

            lock (moduleDefinition)
            {
                // ensure we're creating the interface only once
                var implementationTypeName      = GetImplementationTypeName(interfaceType.Name);
                var implementationTypeNamespace = interfaceType.Namespace;
                if (moduleDefinition.GetTypes().Any(t => t.Namespace == implementationTypeNamespace && t.Name == implementationTypeName))
                {
                    return;
                }

                // now, create the implementation type
                interfaceTypeDefinition = interfaceType.Resolve();
                var typeAttributes = (InjectAsPrivate ? TypeAttributes.NotPublic : TypeAttributes.Public) | TypeAttributes.Class | TypeAttributes.BeforeFieldInit;
                advisedInterfaceType = TypeResolver.Resolve(moduleDefinition, typeof(AdvisedInterface));
                var advisedInterfaceTypeReference = moduleDefinition.SafeImport(advisedInterfaceType);
                implementationType = new TypeDefinition(implementationTypeNamespace, implementationTypeName, typeAttributes, advisedInterfaceTypeReference);

                lock (moduleDefinition)
                    moduleDefinition.Types.Add(implementationType);
            }

            implementationType.Interfaces.Add(interfaceType);

            // create empty .ctor. This .NET mofo wants it!
            var baseEmptyConstructor = moduleDefinition.SafeImport(advisedInterfaceType.Resolve().GetConstructors().Single());
            const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
            var method = new MethodDefinition(".ctor", ctorAttributes, moduleDefinition.TypeSystem.Void);

            method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
            method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, baseEmptyConstructor));
            method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
            implementationType.Methods.Add(method);

            // create implementation methods
            foreach (var interfaceMethod in interfaceTypeDefinition.GetMethods().Where(m => !m.IsSpecialName))
            {
                WeaveInterfaceMethod(interfaceMethod, implementationType, true);
            }

            // create implementation properties
            foreach (var interfaceProperty in interfaceTypeDefinition.Properties)
            {
                var implementationProperty = new PropertyDefinition(interfaceProperty.Name, PropertyAttributes.None, interfaceProperty.PropertyType);
                implementationType.Properties.Add(implementationProperty);
                if (interfaceProperty.GetMethod != null)
                {
                    implementationProperty.GetMethod = WeaveInterfaceMethod(interfaceProperty.GetMethod, implementationType, InjectAsPrivate);
                }
                if (interfaceProperty.SetMethod != null)
                {
                    implementationProperty.SetMethod = WeaveInterfaceMethod(interfaceProperty.SetMethod, implementationType, InjectAsPrivate);
                }
            }

            // create implementation events
            foreach (var interfaceEvent in interfaceTypeDefinition.Events)
            {
                var implementationEvent = new EventDefinition(interfaceEvent.Name, EventAttributes.None, moduleDefinition.SafeImport(interfaceEvent.EventType));
                implementationType.Events.Add(implementationEvent);
                if (interfaceEvent.AddMethod != null)
                {
                    implementationEvent.AddMethod = WeaveInterfaceMethod(interfaceEvent.AddMethod, implementationType, InjectAsPrivate);
                }
                if (interfaceEvent.RemoveMethod != null)
                {
                    implementationEvent.RemoveMethod = WeaveInterfaceMethod(interfaceEvent.RemoveMethod, implementationType, InjectAsPrivate);
                }
            }
        }