Example #1
0
        private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint)
        {
            var builder = new MethodInterceptorBuilder(this, method, extensionPoint);

            var taskReturnType = Context.TaskTType.MakeGenericInstanceType(TypeSystem.ObjectReference);
            var proceed        = new MethodDefinition("Proceed", MethodAttributes.Public, taskReturnType);

            proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType));
            builder.Proceed = proceed;
            builder.Build();

            proceed.Body.Emit(il =>
            {
                builder.EmitCallOriginal(il);

                // Before we return, we need to wrap the original `Task<T>` into a `Task<object>`
                var unwrappedReturnType = ((GenericInstanceType)method.ReturnType).GenericArguments[0];
                var typedInvoke         = asyncInvokerWrap.MakeGenericMethod(unwrappedReturnType);
                il.Emit(OpCodes.Call, typedInvoke);

                il.Emit(OpCodes.Ret);
            });

            return(builder);
        }
Example #2
0
        private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint)
        {
            LogInfo($"ImplementProceed: {method.ReturnType}");

            var builder = new MethodInterceptorBuilder(this, method, extensionPoint);

            var proceed = new MethodDefinition("Proceed", MethodAttributes.Public, TypeSystem.ObjectReference);

            proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType));
            builder.Proceed = proceed;
            builder.Build();

            proceed.Body.Emit(il =>
            {
                builder.EmitCallOriginal(il);

                if (method.ReturnType.CompareTo(TypeSystem.VoidReference))
                {
                    // Void methods won't leave anything on the stack, but the proceed method is expected to return a value
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    // If it's a value type, box it
                    il.EmitBoxIfNeeded(method.ReturnType);
                }

                il.Emit(OpCodes.Ret);
            });

            return(builder);
        }
        public void Weave(IMemberDefinition member, ExtensionPointAttribute extensionPoint)
        {
//            Debugger.Launch();

            var             attributeField = CacheAttributeInstance(member, extensionPoint);
            FieldDefinition memberInfoField;

            if (member is TypeDefinition)
            {
                memberInfoField = null;
            }
            else
            {
                memberInfoField = member.CacheMemberInfo();
            }

            var type = member is TypeDefinition definition ? definition : member.DeclaringType;

            type.EmitToConstructor(il =>
            {
                il.LoadField(attributeField);
                il.Emit(OpCodes.Ldarg_0);
                if (member is TypeDefinition)
                {
                    il.LoadType(type);
                }
                else
                {
                    il.LoadField(memberInfoField);
                }
                il.EmitCall(instanceInitializerInitialize);
            });
        }
Example #4
0
        public void Weave(PropertyDefinition property, ExtensionPointAttribute extensionPoint)
        {
            var type = property.DeclaringType;

            LogInfo($"Weaving property get interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{property.Name}");

            var propertyInfoField = property.CachePropertyInfo();
            var attributeField    = CacheAttributeInstance(property, propertyInfoField, extensionPoint);

            var method           = property.GetMethod;
            var proceedReference = ImplementProceedGet(method, extensionPoint.AttributeType);

            // Re-implement method
            method.Body.Emit(il =>
            {
                ImplementGetBody(attributeField, propertyInfoField, method, il, proceedReference);
            });
        }
Example #5
0
        public void Weave(MethodDefinition method, ExtensionPointAttribute extensionPoint)
        {
            if (!Context.TaskType.IsAssignableFrom(method.ReturnType))
            {
                return;
            }

            LogInfo($"Weaving async method interceptor {extensionPoint.AttributeType.FullName} at {method.Describe()}");

            var methodInfoField = method.CacheMethodInfo();
            var attributeField  = CacheAttributeInstance(method, methodInfoField, extensionPoint);
            var builder         = ImplementProceed(method, extensionPoint);

            // Re-implement method
            method.Body.Emit(il =>
            {
                ImplementBody(method, il, attributeField, methodInfoField, builder);
            });
        }
Example #6
0
        public void Weave(MethodDefinition method, ExtensionPointAttribute extensionPoint)
        {
            // We don't want to intercept both async and non-async when the interceptor implements both interfaces
            if (Context.TaskType.IsAssignableFrom(method.ReturnType) && asyncMethodInterceptorInterface.IsAssignableFrom(extensionPoint.AttributeType))
            {
                return;
            }

            LogInfo($"Weaving method interceptor {extensionPoint.AttributeType.FullName} at {method.Describe()}");

            var methodInfoField = method.CacheMethodInfo();
            var attributeField  = CacheAttributeInstance(method, methodInfoField, extensionPoint);
            var builder         = ImplementProceed(method, extensionPoint);

            // Re-implement method
            method.Body.Emit(il =>
            {
                ImplementBody(method, il, attributeField, methodInfoField, builder);
            });
        }
Example #7
0
        public void Weave(EventDefinition @event, ExtensionPointAttribute extensionPoint, bool isAdd)
        {
            var type = @event.DeclaringType;

            LogInfo($"Weaving event add interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{@event.Name}");

            var eventInfoField = @event.CacheEventInfo();
            var attributeField = CacheAttributeInstance(@event, eventInfoField, extensionPoint);

            LogInfo("Setter is intercepted");

            var method           = isAdd ? @event.AddMethod : @event.RemoveMethod;
            var proceedReference = ImplementProceedSet(method, extensionPoint.AttributeType);

            // Re-implement method
            method.Body.Emit(il =>
            {
                ImplementBody(@event, attributeField, eventInfoField, method, il, proceedReference, isAdd ? addEventHandler : removeEventHandler);
            });
        }
        public void Weave(PropertyDefinition property, ExtensionPointAttribute extensionPoint)
        {
//            if (property.DeclaringType != interceptor.DeclaringType)
//                Debugger.Launch();
            var type = property.DeclaringType;

            LogInfo($"Weaving property interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{property.Name}");

            var propertyInfoField = property.CachePropertyInfo();
            var attributeField    = CacheAttributeInstance(property, propertyInfoField, extensionPoint);

            LogInfo("Setter is intercepted");

            var method           = property.SetMethod;
            var proceedReference = ImplementProceedSet(method, extensionPoint.AttributeType);

            // Re-implement method
            method.Body.Emit(il =>
            {
                ImplementSetBody(property, attributeField, propertyInfoField, method, il, proceedReference);
            });
        }
Example #9
0
        public void Weave(IMemberDefinition member, ExtensionPointAttribute extensionPoint)
        {
            var type           = member is TypeDefinition definition ? definition : member.DeclaringType;
            var attributeField = CacheAttributeInstance(member, extensionPoint);

            var attributeType = extensionPoint.AttributeType.Resolve();

            foreach (var property in attributeType.Properties)
            {
                if (property.PropertyType.IsGenericInstance && property.PropertyType.GetElementType().CompareTo(injectedFieldType))
                {
                    var propertyType         = ((GenericInstanceType)property.PropertyType).GenericArguments[0];
                    var fieldName            = GenerateUniqueName(member, attributeType, property.Name);
                    var injectFieldAttribute = property.GetCustomAttributes(injectFieldAttributeType).SingleOrDefault();
                    var isStatic             = injectFieldAttribute != null && (bool)injectFieldAttribute.ConstructorArguments[0].Value;
                    var fieldAttributes      = FieldAttributes.Private;
                    if (isStatic)
                    {
                        fieldAttributes |= FieldAttributes.Static;
                    }
                    var field = new FieldDefinition(fieldName, fieldAttributes, propertyType);
                    type.Fields.Add(field);

                    // Generate accessors
                    var getMethodName = GenerateUniqueName(member, attributeType, $"{property.Name}Getter");
                    var getMethod     = new MethodDefinition(getMethodName, MethodAttributes.Private | MethodAttributes.Static, propertyType);
                    getMethod.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference));
                    getMethod.Body            = new MethodBody(getMethod);
                    getMethod.Body.InitLocals = true;
                    getMethod.Body.Emit(il =>
                    {
                        if (!isStatic)
                        {
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Castclass, type);
                        }
                        il.LoadField(field);
                        il.Emit(OpCodes.Ret);
                    });
                    type.Methods.Add(getMethod);

                    var setMethodName = GenerateUniqueName(member, attributeType, $"{property.Name}Setter");
                    var setMethod     = new MethodDefinition(setMethodName, MethodAttributes.Private | MethodAttributes.Static, TypeSystem.VoidReference);
                    setMethod.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference));
                    setMethod.Parameters.Add(new ParameterDefinition(propertyType));
                    setMethod.Body            = new MethodBody(setMethod);
                    setMethod.Body.InitLocals = true;
                    setMethod.Body.Emit(il =>
                    {
                        if (!isStatic)
                        {
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Castclass, type);
                        }
                        il.Emit(OpCodes.Ldarg_1);
                        il.SaveField(field);
                        il.Emit(OpCodes.Ret);
                    });
                    type.Methods.Add(setMethod);

                    type.EmitToStaticConstructor(il =>
                    {
                        var genericInjectedFieldType = injectedFieldType.MakeGenericInstanceType(propertyType);
                        var injectedFieldConstructor = ModuleDefinition.FindConstructor(genericInjectedFieldType).Bind(genericInjectedFieldType);

                        il.LoadField(attributeField);       // Instance on which to set the InjectedField

                        // Instantiate the InjectedField
                        il.EmitLocalMethodDelegate(getMethod, Context.Func2Type, TypeSystem.ObjectReference, propertyType);
                        il.EmitLocalMethodDelegate(setMethod, Context.ActionTypes[2], TypeSystem.ObjectReference, propertyType);
                        il.Emit(OpCodes.Newobj, injectedFieldConstructor);

                        il.EmitCall(property.SetMethod);
                    });
                }
            }
        }
Example #10
0
        public override void Execute()
        {
//            Debugger.Launch();

            var soMeta = ModuleDefinition.FindAssembly("Someta");

            CecilExtensions.LogInfo    = LogInfo;
            CecilExtensions.LogWarning = LogWarning;
            CecilExtensions.LogError   = LogError;
            CecilExtensions.Initialize(ModuleDefinition, TypeSystem, soMeta);

            var extensionPointInterface          = ModuleDefinition.FindType("Someta", "IExtensionPoint", soMeta);
            var stateExtensionPointInterface     = ModuleDefinition.FindType("Someta", "IStateExtensionPoint`1", soMeta, "T");
            var stateExtensionPointInterfaceBase = ModuleDefinition.FindType("Someta", "IStateExtensionPoint", soMeta);
            var propertyGetInterceptorInterface  = ModuleDefinition.FindType("Someta", "IPropertyGetInterceptor", soMeta);
            var propertySetInterceptorInterface  = ModuleDefinition.FindType("Someta", "IPropertySetInterceptor", soMeta);
            var eventAddInterceptorInterface     = ModuleDefinition.FindType("Someta", "IEventAddInterceptor", soMeta);
            var eventRemoveInterceptorInterface  = ModuleDefinition.FindType("Someta", "IEventRemoveInterceptor", soMeta);
            var methodInterceptorInterface       = ModuleDefinition.FindType("Someta", "IMethodInterceptor", soMeta);
            var asyncMethodInterceptorInterface  = ModuleDefinition.FindType("Someta", "IAsyncMethodInterceptor", soMeta);
            var nonPublicAccessInterface         = ModuleDefinition.FindType("Someta", "INonPublicAccess", soMeta);
            var asyncInvoker       = ModuleDefinition.FindType("Someta.Helpers", "AsyncInvoker", soMeta);
            var asyncInvokerWrap   = ModuleDefinition.FindMethod(asyncInvoker, "Wrap");
            var asyncInvokerUnwrap = ModuleDefinition.FindMethod(asyncInvoker, "Unwrap");
            var instanceInitializerInterfaceBase = ModuleDefinition.FindType("Someta", "IInstanceInitializer", soMeta);
            var instanceInitializerInterface     = ModuleDefinition.FindType("Someta", "IInstanceInitializer`1", soMeta, "T");
//            var interceptorScopeAttribute = ModuleDefinition.FindType("Someta", "InterceptorScopeAttribute", soMeta);
//            var requireScopeInterceptorInterface = ModuleDefinition.FindType("Someta", "IRequireScopeInterceptor", soMeta);

            var extensionPointScopesClass           = ModuleDefinition.FindType("Someta", "ExtensionPointScopes", soMeta);
            var extensionPointScopesClassDefinition = extensionPointScopesClass.Resolve();
//            var interceptorScopeInterface = interceptorScopesClassDefinition.NestedTypes.Single(x => x.Name == "Scope");
            var extensionPointScopePropertyInterface = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Property");
            var extensionPointScopeMethodInterface   = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Method");
            var extensionPointScopeClassInterface    = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Class");

            var propertyGetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>();
            var propertySetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>();
            var eventAddInterceptions    = new List <(EventDefinition, ExtensionPointAttribute)>();
            var eventRemoveInterceptions = new List <(EventDefinition, ExtensionPointAttribute)>();
            var methodInterceptions      = new List <(MethodDefinition, ExtensionPointAttribute)>();
            var asyncMethodInterceptions = new List <(MethodDefinition, ExtensionPointAttribute)>();
            var classEnhancers           = new List <(TypeDefinition, ExtensionPointAttribute)>();
            var stateInterceptions       = new List <(IMemberDefinition, ExtensionPointAttribute)>();
            var instanceInitializers     = new List <(IMemberDefinition, ExtensionPointAttribute)>();

            var propertyGetInterceptorWeaver = new PropertyGetInterceptorWeaver(CecilExtensions.Context, propertyGetInterceptorInterface);
            var propertySetInterceptorWeaver = new PropertySetInterceptorWeaver(CecilExtensions.Context, propertySetInterceptorInterface);
            var eventInterceptorWeaver       = new EventInterceptorWeaver(CecilExtensions.Context);
            var methodInterceptorWeaver      = new MethodInterceptorWeaver(CecilExtensions.Context, methodInterceptorInterface, asyncMethodInterceptorInterface);
            var asyncMethodInterceptorWeaver = new AsyncMethodInterceptorWeaver(CecilExtensions.Context, asyncMethodInterceptorInterface, asyncInvokerWrap, asyncInvokerUnwrap);
            var classEnhancerWeaver          = new ClassEnhancerWeaver(CecilExtensions.Context);
            var stateWeaver = new StateWeaver(CecilExtensions.Context);
            var instanceInitializerWeaver = new InstanceInitializerWeaver(CecilExtensions.Context);

            // unscopedInterface: If present, and if genericTypes is empty (meaning no specific scope was specified),
            // unscopedInterface will be checked as a fallback.
            bool HasScope(ExtensionPointAttribute interceptor, TypeReference interfaceType, ExtensionPointScope scope, TypeReference unscopedInterface = null)
            {
                var genericTypes = interceptor.AttributeType.FindGenericInterfaces(interfaceType).ToArray();

                foreach (var genericType in genericTypes)
                {
                    var           argument       = genericType.GenericArguments[0];
                    TypeReference scopeInterface = null;
                    switch (scope)
                    {
                    case ExtensionPointScope.Class:
                        scopeInterface = extensionPointScopeClassInterface;
                        break;

                    case ExtensionPointScope.Property:
                        scopeInterface = extensionPointScopePropertyInterface;
                        break;

                    case ExtensionPointScope.Method:
                        scopeInterface = extensionPointScopeMethodInterface;
                        break;
                    }

                    if (argument.CompareTo(scopeInterface))
                    {
                        return(true);
                    }
                }

                // If no scope was specified, we consider the scope satisfied if an unscoped version is satisfied
                // Furthermore, the scope must match the member type.
                var isScopeMatchedWithMember = interceptor.Scope == scope;

                return(unscopedInterface != null && genericTypes.Length == 0 && unscopedInterface.IsAssignableFrom(interceptor.AttributeType) && isScopeMatchedWithMember);
            }

            // Inventory candidate classes
            var allTypes = ModuleDefinition.GetAllTypes();
            var assemblyInterceptorAttributes = ModuleDefinition.Assembly
                                                .GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                                .ToArray();

            ExtensionPointAttribute[] assemblyInterceptors;

            // If we have any assembly-level interceptors, we create a special state class to hold the attribute instances (since attributes
            // can contain state, but getting attributes through reflection always returns a new instance.
            if (assemblyInterceptorAttributes.Any())
            {
//                Debugger.Launch();
                var assemblyState = new TypeDefinition("Someta", "AssemblyState", TypeAttributes.Public, TypeSystem.ObjectReference);
                ModuleDefinition.Types.Add(assemblyState);

/*
 *              var constructorWithTarget = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, TypeSystem.VoidReference);
 *              constructorWithTarget.Body.Emit(il =>
 *              {
 *                  il.Emit(OpCodes.Ret);
 *              });
 *              assemblyState.Methods.Add(constructorWithTarget);
 */

                CecilExtensions.Context.AssemblyState = assemblyState;
                assemblyInterceptors = assemblyInterceptorAttributes
                                       .Select(x => new ExtensionPointAttribute(assemblyState, ModuleDefinition.Assembly, x, ModuleDefinition.Assembly.CustomAttributes.IndexOf(x), ExtensionPointScope.Assembly))
                                       .ToArray();

                foreach (var interceptor in assemblyInterceptors)
                {
                    var fieldName      = interceptor.AttributeType.FullName.Replace(".", "$");
                    var attributeField = new FieldDefinition(fieldName, FieldAttributes.Static | FieldAttributes.Public, interceptor.AttributeType);
                    var index          = ModuleDefinition.Assembly.CustomAttributes.IndexOf(interceptor.Attribute);
                    assemblyState.Fields.Add(attributeField);

                    assemblyState.EmitToStaticConstructor(il =>
                    {
                        il.EmitGetAssemblyAttributeByIndex(index, interceptor.AttributeType);
                        il.SaveField(attributeField);
                    });
                }
            }
            else
            {
                assemblyInterceptors = new ExtensionPointAttribute[0];
            }

//            var moduleInterceptors = ModuleDefinition
//                .GetCustomAttributesIncludingSubtypes(extensionPointInterface)
//                .Select(x => new ExtensionPointAttribute(null, ModuleDefinition, x, ModuleDefinition.CustomAttributes.IndexOf(x), ExtensionPointScope.Module))
//                .ToArray();
//            var assemblyAndModuleInterceptors = assemblyInterceptors.Concat(moduleInterceptors).ToArray();
            foreach (var type in allTypes)
            {
                // We can get into recursion scenarios if we allow extension points on extension points.  For now, let's naively prohibit this
                if (extensionPointInterface.IsAssignableFrom(type))
                {
                    continue;
                }

                var classInterceptors = type
                                        .GetCustomAttributesInAncestry(extensionPointInterface)
                                        .Select(x => new ExtensionPointAttribute(x.DeclaringType, x.DeclaringType, x.Attribute, x.DeclaringType.CustomAttributes.IndexOf(x.Attribute), ExtensionPointScope.Class))
                                        .Concat(assemblyInterceptors /*.Select(x => new ExtensionPointAttribute(type, x.DeclaringMember, x.Attribute, x.Index, x.Scope))*/)
                                        .ToArray();

                foreach (var classInterceptor in classInterceptors)
                {
                    LogInfo($"Found class interceptor {classInterceptor.AttributeType}");
                    if (nonPublicAccessInterface.IsAssignableFrom(classInterceptor.AttributeType))
                    {
                        LogInfo($"Discovered class enhancer {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        classEnhancers.Add((type, classInterceptor));
                    }
                    if (HasScope(classInterceptor, stateExtensionPointInterface, ExtensionPointScope.Class, stateExtensionPointInterfaceBase))
                    {
                        LogInfo($"Discovered class state interceptor {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        stateInterceptions.Add((type, classInterceptor));
                    }
                    if (HasScope(classInterceptor, instanceInitializerInterface, ExtensionPointScope.Class, instanceInitializerInterfaceBase))
                    {
                        LogInfo($"Discovered instance initializer {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        instanceInitializers.Add((type, classInterceptor));
                    }
                }

                foreach (var property in type.Properties)
                {
                    var interceptors = property.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, property, x, property.CustomAttributes.IndexOf(x), ExtensionPointScope.Property))
                                       .Concat(classInterceptors);
                    foreach (var interceptor in interceptors)
                    {
                        if (propertyGetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered property get interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            propertyGetInterceptions.Add((property, interceptor));
                        }
                        if (propertySetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered property set interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            propertySetInterceptions.Add((property, interceptor));
                        }
                        if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Property, stateExtensionPointInterfaceBase))
                        {
                            LogInfo($"Discovered property state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            stateInterceptions.Add((property, interceptor));
                        }
                        if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Property, instanceInitializerInterfaceBase))
                        {
                            LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}");
                            instanceInitializers.Add((property, interceptor));
                        }
                    }
                }

                foreach (var @event in type.Events)
                {
//                    Debugger.Launch();
                    var interceptors = @event.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, @event, x, @event.CustomAttributes.IndexOf(x), ExtensionPointScope.Event))
                                       .Concat(classInterceptors);

                    foreach (var interceptor in interceptors)
                    {
                        if (eventAddInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered event add interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}");
                            eventAddInterceptions.Add((@event, interceptor));
                        }
                        if (eventRemoveInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered event remove interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}");
                            eventRemoveInterceptions.Add((@event, interceptor));
                        }
                    }
                }

                foreach (var method in type.Methods.Where(x => !x.IsConstructor))
                {
                    var interceptors = method.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, method, x, method.CustomAttributes.IndexOf(x), ExtensionPointScope.Method))
                                       .Concat(classInterceptors);
                    foreach (var interceptor in interceptors)
                    {
                        if (methodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            methodInterceptions.Add((method, interceptor));
                        }
                        if (asyncMethodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered async method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            asyncMethodInterceptions.Add((method, interceptor));
                        }
                        if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Method, stateExtensionPointInterfaceBase))
                        {
                            LogInfo($"Discovered method state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            stateInterceptions.Add((method, interceptor));
                        }
                        if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Method, instanceInitializerInterfaceBase))
                        {
                            LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}");
                            instanceInitializers.Add((method, interceptor));
                        }
                    }
                }
            }

            foreach (var(property, interceptor) in propertyGetInterceptions)
            {
                propertyGetInterceptorWeaver.Weave(property, interceptor);
            }

            foreach (var(property, interceptor) in propertySetInterceptions)
            {
                propertySetInterceptorWeaver.Weave(property, interceptor);
            }

            foreach (var(@event, interceptor) in eventAddInterceptions)
            {
                eventInterceptorWeaver.Weave(@event, interceptor, isAdd: true);
            }

            foreach (var(@event, interceptor) in eventRemoveInterceptions)
            {
                eventInterceptorWeaver.Weave(@event, interceptor, isAdd: false);
            }

            foreach (var(method, interceptor) in methodInterceptions)
            {
                methodInterceptorWeaver.Weave(method, interceptor);
            }

            foreach (var(method, interceptor) in asyncMethodInterceptions)
            {
                asyncMethodInterceptorWeaver.Weave(method, interceptor);
            }

            foreach (var(type, interceptor) in classEnhancers)
            {
                classEnhancerWeaver.Weave(type, interceptor);
            }

            foreach (var(member, interceptor) in stateInterceptions)
            {
                stateWeaver.Weave(member, interceptor);
            }

            foreach (var(type, interceptor) in instanceInitializers)
            {
                instanceInitializerWeaver.Weave(type, interceptor);
            }
        }
Example #11
0
        public void Weave(TypeDefinition type, ExtensionPointAttribute extensionPoint)
        {
//            Debugger.Launch();

            LogInfo($"Weaving class enhancer {extensionPoint.AttributeType.FullName} at {type.FullName}");
//            interceptor.

            // For now, we don't want to impact subclasses since there's no current use case for that.  If that changes,
            // we'll revisit.
            if (type != extensionPoint.DeclaringType)
            {
                return;
            }

            var attributeField = CacheAttributeInstance(type, extensionPoint);

            foreach (var interceptorProperty in extensionPoint.AttributeType.Resolve().Properties)
            {
                var injectAccess = interceptorProperty.CustomAttributes.SingleOrDefault(x => x.AttributeType.CompareTo(injectAccessAttribute));
                if (injectAccess != null)
                {
//                    Debugger.Launch();
                    var key = (string)injectAccess.ConstructorArguments.Single().Value;

                    // Find target method.  First try using attributes:
                    var targetMethod = type.Methods.SingleOrDefault(x => x.CustomAttributes
                                                                    .Any(y => injectTargetAttribute.IsAssignableFrom(y.AttributeType) && (string)y.ConstructorArguments[0].Value == key));
                    if (targetMethod == null)
                    {
                        targetMethod = type.Methods.Single(x => x.Name == key);    // Todo: won't work for overloads
                    }
                    // Generate a private static method that forms the accessor that will be assigned
                    // to this property on the associated interceptor in a static initializer.
                    var accessor = new MethodDefinition($"<>__{key}$Accessor", MethodAttributes.Private | MethodAttributes.Static, targetMethod.ReturnType);
                    accessor.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference));
                    foreach (var parameter in targetMethod.Parameters)
                    {
                        accessor.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
                    }

//                    var delegateType = new TypeDefinition(type.Namespace, accessor.Name + "Type", TypeAttributes.NestedPrivate, Context.DelegateType);
//                    delegateType.Methods.Add(new MethodDefinition("Invoke", MethodAttributes.Public, ))

                    accessor.Body            = new MethodBody(accessor);
                    accessor.Body.InitLocals = true;
                    accessor.Body.Emit(il =>
                    {
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Castclass, type);

                        for (var i = 1; i <= targetMethod.Parameters.Count; i++)
                        {
                            il.EmitArgument(accessor, i);
                        }
                        il.EmitCall(targetMethod);
                        il.Emit(OpCodes.Ret);
                    });
                    type.Methods.Add(accessor);

                    // Now set up the static initializer to assign this to the interceptor property
                    type.EmitToStaticConstructor(il =>
                    {
                        var isVoid        = targetMethod.ReturnType.CompareTo(TypeSystem.VoidReference);
                        var delegateType  = (isVoid ? Context.ActionTypes : Context.FuncTypes)[targetMethod.Parameters.Count + 1];
                        var typeArguments = new List <TypeReference>();
                        typeArguments.Add(TypeSystem.ObjectReference);
                        typeArguments.AddRange(targetMethod.Parameters.Select(x => x.ParameterType));
                        if (!isVoid)
                        {
                            typeArguments.Add(targetMethod.ReturnType);
                        }

                        il.LoadField(attributeField);
                        il.EmitLocalMethodDelegate(accessor, delegateType, typeArguments.ToArray());
                        il.EmitCall(interceptorProperty.SetMethod);
                    });
                }
            }
        }
Example #12
0
 public MethodInterceptorBuilder(BaseWeaver weaver, MethodDefinition method, ExtensionPointAttribute extensionPoint)
 {
     this.weaver         = weaver;
     this.method         = method;
     this.extensionPoint = extensionPoint;
 }