public EventInvokerMethod AddOnPropertyChangingMethod(TypeDefinition targetType)
    {
        var propertyChangingField = FindPropertyChangingField(targetType);

        if (propertyChangingField == null)
        {
            return(null);
        }
        if (FoundInterceptor)
        {
            if (targetType.HasGenericParameters)
            {
                var message = string.Format("Error processing '{0}'. Interception is not supported on generic types. To manually work around this problem add a [DoNotNotify] to the class and then manually implement INotifyPropertyChanging for that class and all child classes. If you would like this feature handled automatically please feel free to submit a pull request.", targetType.Name);
                throw new WeavingException(message);
            }
            var methodDefinition = GetMethodDefinition(targetType, propertyChangingField);

            return(new EventInvokerMethod
            {
                MethodReference = InjectInterceptedMethod(targetType, methodDefinition).GetGeneric(),
                IsVisibleFromChildren = true,
                InvokerType = InterceptorType,
            });
        }
        return(new EventInvokerMethod
        {
            MethodReference = InjectMethod(targetType, EventInvokerNames.First(), propertyChangingField).GetGeneric(),
            IsVisibleFromChildren = true,
            InvokerType = InterceptorType,
        });
    }
    MethodDefinition FindEventInvokerMethodDefinition(TypeDefinition type)
    {
        var methodDefinition = type.Methods
                               .Where(x => (x.IsFamily || x.IsFamilyAndAssembly || x.IsPublic || x.IsFamilyOrAssembly) &&
                                      EventInvokerNames.Contains(x.Name))
                               .OrderByDescending(GetInvokerPriority)
                               .FirstOrDefault(IsEventInvokerMethod);

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

        methodDefinition = type.Methods
                           .Where(x => EventInvokerNames.Contains(x.Name))
                           .OrderByDescending(GetInvokerPriority)
                           .FirstOrDefault(IsEventInvokerMethod);

        if (methodDefinition != null &&
            methodDefinition.IsPrivate &&
            methodDefinition.IsFinal &&
            methodDefinition.IsVirtual &&
            methodDefinition.Overrides.Count == 1)
        {
            // Explicitly implemented interfaces should call the interface method instead
            return(methodDefinition.Overrides[0].Resolve());
        }

        return(methodDefinition);
    }
 MethodReference FindExplicitImplementation(TypeDefinition type)
 {
     return(type.GetAllInterfaces()
            .Select(i => i.Resolve())
            .Where(i => i != null && i.IsPublic)
            .SelectMany(i => i.Methods.Where(m => EventInvokerNames.Contains($"{i.FullName}.{m.Name}")))
            .OrderByDescending(GetInvokerPriority)
            .FirstOrDefault(IsEventInvokerMethod));
 }
    MethodDefinition GetMethodDefinition(TypeDefinition targetType, FieldReference propertyChangedField)
    {
        var eventInvokerName = "Inner" + EventInvokerNames.First();
        var methodDefinition = targetType.Methods.FirstOrDefault(x => x.Name == eventInvokerName);

        if (methodDefinition?.Parameters.Count == 1 && methodDefinition.Parameters[0].ParameterType.FullName == "System.String")
        {
            return(methodDefinition);
        }
        return(InjectMethod(targetType, eventInvokerName, propertyChangedField));
    }
    OnChangedMethod CreateOnChangedMethod(TypeNode notifyNode, MethodDefinition methodDefinition, bool isDefaultMethod)
    {
        if (methodDefinition.IsStatic)
        {
            if (!SuppressOnPropertyNameChangedWarning)
            {
                EmitConditionalWarning(methodDefinition, $"The type {notifyNode.TypeDefinition.FullName} has a On_PropertyName_Changed method ({methodDefinition.Name}) which is static.");
            }
            return(null);
        }

        if (methodDefinition.ReturnType.FullName != "System.Void")
        {
            if (!SuppressOnPropertyNameChangedWarning)
            {
                EmitConditionalWarning(methodDefinition, $"The type {notifyNode.TypeDefinition.FullName} has a On_PropertyName_Changed method ({methodDefinition.Name}) that has a non void return value. Ensure the return type void.");
            }
            return(null);
        }

        var typeDefinitions = new Stack <TypeDefinition>();

        typeDefinitions.Push(notifyNode.TypeDefinition);

        var onChangedType = OnChangedTypes.None;

        if (IsNoArgOnChangedMethod(methodDefinition))
        {
            onChangedType = OnChangedTypes.NoArg;
        }
        else if (IsBeforeAfterOnChangedMethod(methodDefinition))
        {
            onChangedType = OnChangedTypes.BeforeAfter;
        }

        if (onChangedType != OnChangedTypes.None)
        {
            ValidateOnChangedMethod(notifyNode, methodDefinition, isDefaultMethod);

            return(new OnChangedMethod
            {
                OnChangedType = onChangedType,
                MethodReference = GetMethodReference(typeDefinitions, methodDefinition),
                IsDefaultMethod = isDefaultMethod
            });
        }

        if (!EventInvokerNames.Contains(methodDefinition.Name) && !SuppressOnPropertyNameChangedWarning)
        {
            EmitConditionalWarning(methodDefinition, $"Unsupported signature for a On_PropertyName_Changed method: {methodDefinition.Name} in {methodDefinition.DeclaringType.FullName}");
        }

        return(null);
    }
Exemple #6
0
    MethodDefinition GetMethodDefinition(TypeDefinition targetType)
    {
        var eventInvokerName = $"Inner{EventInvokerNames.First()}";
        var methodDefinition = targetType.Methods.FirstOrDefault(x => x.Name == eventInvokerName);

        if (methodDefinition?.Parameters.Count == 1 && methodDefinition.Parameters[0].ParameterType.FullName == "System.String")
        {
            return(methodDefinition);
        }
        return(InjectMethod(targetType, eventInvokerName));
    }
Exemple #7
0
    IEnumerable <OnChangedMethod> GetOnChangedMethods(TypeNode notifyNode)
    {
        var methods = notifyNode.TypeDefinition.Methods;

        var onChangedMethods = methods.Where(x => x.Name.StartsWith("On") &&
                                             x.Name.EndsWith("Changed") &&
                                             x.Name != "OnChanged");

        foreach (var methodDefinition in onChangedMethods)
        {
            if (methodDefinition.IsStatic)
            {
                var message = $"The type {notifyNode.TypeDefinition.FullName} has a On_PropertyName_Changed method ({methodDefinition.Name}) which is static.";
                throw new WeavingException(message);
            }

            if (methodDefinition.ReturnType.FullName != "System.Void")
            {
                var message = $"The type {notifyNode.TypeDefinition.FullName} has a On_PropertyName_Changed method ({methodDefinition.Name}) that has a non void return value. Ensure the return type void.";
                throw new WeavingException(message);
            }

            var typeDefinitions = new Stack <TypeDefinition>();
            typeDefinitions.Push(notifyNode.TypeDefinition);

            if (IsNoArgOnChangedMethod(methodDefinition))
            {
                ValidateOnChangedMethod(notifyNode, methodDefinition);

                yield return(new OnChangedMethod
                {
                    OnChangedType = OnChangedTypes.NoArg,
                    MethodReference = GetMethodReference(typeDefinitions, methodDefinition)
                });
            }
            else if (IsBeforeAfterOnChangedMethod(methodDefinition))
            {
                ValidateOnChangedMethod(notifyNode, methodDefinition);

                yield return(new OnChangedMethod
                {
                    OnChangedType = OnChangedTypes.BeforeAfter,
                    MethodReference = GetMethodReference(typeDefinitions, methodDefinition)
                });
            }
            else if (!EventInvokerNames.Contains(methodDefinition.Name))
            {
                EmitConditionalWarning(methodDefinition, $"Unsupported signature for a On_PropertyName_Changed method: {methodDefinition.Name} in {methodDefinition.DeclaringType.FullName}");
            }
        }
    }
Exemple #8
0
 bool FindEventInvokerMethodDefinition(TypeDefinition type, out MethodDefinition methodDefinition)
 {
     methodDefinition = type.Methods
                        .Where(x => (x.IsFamily || x.IsFamilyAndAssembly || x.IsPublic || x.IsFamilyOrAssembly) && EventInvokerNames.Contains(x.Name))
                        .OrderByDescending(definition => definition.Parameters.Count)
                        .FirstOrDefault(x => IsBeforeAfterGenericMethod(x) || IsBeforeAfterMethod(x) || IsSingleStringMethod(x) || IsPropertyChangedArgMethod(x) || IsSenderPropertyChangedArgMethod(x));
     if (methodDefinition == null)
     {
         methodDefinition = type.Methods
                            .Where(x => EventInvokerNames.Contains(x.Name))
                            .OrderByDescending(definition => definition.Parameters.Count)
                            .FirstOrDefault(x => IsBeforeAfterGenericMethod(x) || IsBeforeAfterMethod(x) || IsSingleStringMethod(x) || IsPropertyChangedArgMethod(x) || IsSenderPropertyChangedArgMethod(x));
     }
     return(methodDefinition != null);
 }
Exemple #9
0
 bool FindEventInvokerMethodDefinition(TypeDefinition type, out MethodDefinition methodDefinition)
 {
     methodDefinition = type.Methods
                        .Where(x => (x.IsFamily || x.IsFamilyAndAssembly || x.IsPublic || x.IsFamilyOrAssembly) && EventInvokerNames.Contains(x.Name))
                        .OrderByDescending(definition => definition.Parameters.Count)
                        .FirstOrDefault(x => IsBeforeAfterMethod(x) || IsSingleStringMethod(x) || IsPropertyChangedArgMethod(x));
     if (methodDefinition == null)
     {
         //TODO: when injecting calls to this method should check visibility
         methodDefinition = type.Methods
                            .Where(x => EventInvokerNames.Contains(x.Name))
                            .OrderByDescending(definition => definition.Parameters.Count)
                            .FirstOrDefault(x => IsBeforeAfterMethod(x) || IsSingleStringMethod(x) || IsPropertyChangedArgMethod(x));
     }
     return(methodDefinition != null);
 }
    MethodDefinition FindEventInvokerMethodDefinition(TypeDefinition type)
    {
        var methodDefinition = type.Methods
                               .Where(x => (x.IsFamily || x.IsFamilyAndAssembly || x.IsPublic || x.IsFamilyOrAssembly) && EventInvokerNames.Contains(x.Name))
                               .OrderByDescending(GetInvokerPriority)
                               .FirstOrDefault(IsEventInvokerMethod);

        if (methodDefinition == null)
        {
            methodDefinition = type.Methods
                               .Where(x => EventInvokerNames.Contains(x.Name))
                               .OrderByDescending(GetInvokerPriority)
                               .FirstOrDefault(IsEventInvokerMethod);
        }

        return(methodDefinition);
    }
    MethodDefinition InjectInterceptedMethod(TypeDefinition targetType, MethodDefinition innerOnPropertyChanging)
    {
        var delegateHolderInjector = new DelegateHolderInjector
        {
            TargetTypeDefinition = targetType,
            OnPropertyChangingMethodReference = innerOnPropertyChanging,
            ModuleWeaver = this
        };

        delegateHolderInjector.InjectDelegateHolder();
        var method = new MethodDefinition(EventInvokerNames.First(), GetMethodAttributes(targetType), ModuleDefinition.TypeSystem.Void);

        var propertyName = new ParameterDefinition("propertyName", ParameterAttributes.None, ModuleDefinition.TypeSystem.String);

        method.Parameters.Add(propertyName);
        if (InterceptorType == InvokerTypes.Before)
        {
            var before = new ParameterDefinition("before", ParameterAttributes.None, ModuleDefinition.TypeSystem.Object);
            method.Parameters.Add(before);
        }

        var action = new VariableDefinition("firePropertyChanging", ActionTypeReference);

        method.Body.Variables.Add(action);

        var variableDefinition = new VariableDefinition("delegateHolder", delegateHolderInjector.TypeDefinition);

        method.Body.Variables.Add(variableDefinition);


        var instructions = method.Body.Instructions;

        var last = Instruction.Create(OpCodes.Ret);

        instructions.Add(Instruction.Create(OpCodes.Newobj, delegateHolderInjector.ConstructorDefinition));
        instructions.Add(Instruction.Create(OpCodes.Stloc_1));
        instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
        instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
        instructions.Add(Instruction.Create(OpCodes.Stfld, delegateHolderInjector.PropertyName));
        instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
        instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
        instructions.Add(Instruction.Create(OpCodes.Stfld, delegateHolderInjector.Target));
        instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
        instructions.Add(Instruction.Create(OpCodes.Ldftn, delegateHolderInjector.MethodDefinition));
        instructions.Add(Instruction.Create(OpCodes.Newobj, ActionConstructorReference));
        instructions.Add(Instruction.Create(OpCodes.Stloc_0));
        instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
        instructions.Add(Instruction.Create(OpCodes.Ldloc_0));
        instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
        instructions.Add(Instruction.Create(OpCodes.Ldfld, delegateHolderInjector.PropertyName));
        if (InterceptorType == InvokerTypes.Before)
        {
            instructions.Add(Instruction.Create(OpCodes.Ldarg_2));
            instructions.Add(Instruction.Create(OpCodes.Call, InterceptMethod));
        }
        else
        {
            instructions.Add(Instruction.Create(OpCodes.Call, InterceptMethod));
        }

        instructions.Add(last);
        method.Body.InitLocals = true;

        targetType.Methods.Add(method);
        return(method);
    }