public LocaVariableCollectionTreeNode( MethodBodyDeclaration body )
     : base( TreeViewImage.Folder, null )
 {
     this.body = body;
     this.Text = "Locals";
     this.EnableLatePopulate();
 }
 public LocaVariableCollectionTreeNode(MethodBodyDeclaration body)
     : base(TreeViewImage.Folder, null)
 {
     this.body = body;
     this.Text = "Locals";
     this.EnableLatePopulate();
 }
 private static bool CheckIfIsLocationBinding(MethodBodyDeclaration methodBody, TransformationAssets assets)
 {
     bool isLocationBinding = methodBody.Method.Name == "SetValue"
                              && methodBody.Method.DeclaringType.IsDerivedFrom(assets.LocationBindingTypeSignature.GetTypeDefinition());
     return isLocationBinding;
 }
            public override void Implement(TransformationContext context)
            {
                TypeDefDeclaration typeDef = (TypeDefDeclaration)context.TargetElement;

                ModuleDeclaration module         = this.AspectWeaver.Module;
                ITypeSignature    baseEntityType = module.Cache.GetType(typeof(BaseEntity));

                // Find the base method.
                IMethod         baseCopyToMethod = null;
                IType           baseTypeCursor   = typeDef;
                MethodSignature methodSignature  =
                    new MethodSignature(module, CallingConvention.HasThis, module.Cache.GetIntrinsic(IntrinsicType.Void),
                                        new[] { baseEntityType }, 0);

                while (baseCopyToMethod == null && baseTypeCursor != null)
                {
                    TypeDefDeclaration baseTypeCursorTypeDef = baseTypeCursor.GetTypeDefinition();

                    baseCopyToMethod =
                        baseTypeCursorTypeDef.Methods.GetMethod("CopyTo",
                                                                methodSignature.Translate(baseTypeCursorTypeDef.Module),
                                                                BindingOptions.OnlyExisting |
                                                                BindingOptions.DontThrowException);

                    baseTypeCursor = baseTypeCursorTypeDef.BaseType;
                }

                if (baseCopyToMethod == null)
                {
                    throw new AssertionFailedException("Could not find a method CopyTo.");
                }

                if (baseCopyToMethod.DeclaringType == typeDef)
                {
                    return;
                }


                // Declare the method.
                MethodDefDeclaration methodDef = new MethodDefDeclaration
                {
                    Name       = "CopyTo",
                    Attributes =
                        (MethodAttributes.Family | MethodAttributes.ReuseSlot |
                         MethodAttributes.Virtual),
                    CallingConvention = CallingConvention.HasThis
                };

                typeDef.Methods.Add(methodDef);
                methodDef.CustomAttributes.Add(this.AspectWeaver.AspectInfrastructureTask.WeavingHelper.GetDebuggerNonUserCodeAttribute());

                // Define parameter.
                methodDef.ReturnParameter = new ParameterDeclaration
                {
                    ParameterType = module.Cache.GetIntrinsic(IntrinsicType.Void),
                    Attributes    = ParameterAttributes.Retval
                };

                ParameterDeclaration cloneParameter =
                    new ParameterDeclaration(0, "clone", baseEntityType);

                methodDef.Parameters.Add(cloneParameter);

                // Define the body
                MethodBodyDeclaration methodBody = new MethodBodyDeclaration();

                methodDef.MethodBody = methodBody;
                InstructionBlock instructionBlock = methodBody.CreateInstructionBlock();

                methodBody.RootInstructionBlock = instructionBlock;
                InstructionSequence sequence = methodBody.CreateInstructionSequence();

                instructionBlock.AddInstructionSequence(sequence, NodePosition.After, null);
                using (InstructionWriter writer = new InstructionWriter())
                {
                    writer.AttachInstructionSequence(sequence);

                    // Cast the argument and store it in a local variable.
                    IType typeSpec = GenericHelper.GetTypeCanonicalGenericInstance(typeDef);
                    LocalVariableSymbol castedCloneLocal = instructionBlock.DefineLocalVariable(typeSpec, "typedClone");
                    writer.EmitInstruction(OpCodeNumber.Ldarg_1);
                    writer.EmitInstructionType(OpCodeNumber.Castclass, typeSpec);
                    writer.EmitInstructionLocalVariable(OpCodeNumber.Stloc, castedCloneLocal);


                    // TODO: support generic base types.


                    // Call the base method.
                    writer.EmitInstruction(OpCodeNumber.Ldarg_0);
                    writer.EmitInstruction(OpCodeNumber.Ldarg_1);
                    writer.EmitInstructionMethod(OpCodeNumber.Call, (IMethod)baseCopyToMethod.Translate(typeDef.Module));

                    // Loop on all fields and clone cloneable ones.
                    TypeRefDeclaration cloneableTypeRef = (TypeRefDeclaration)
                                                          module.Cache.GetType(typeof(ICloneable));
                    MethodRefDeclaration cloneMethodRef = (MethodRefDeclaration)cloneableTypeRef.MethodRefs.GetMethod(
                        "Clone",
                        new MethodSignature(
                            module,
                            CallingConvention.HasThis,
                            module.Cache.GetIntrinsic(
                                IntrinsicType.Object),
                            new ITypeSignature[0], 0),
                        BindingOptions.Default);

                    foreach (FieldDefDeclaration fieldDef in typeDef.Fields)
                    {
                        if ((fieldDef.Attributes & FieldAttributes.Static) != 0)
                        {
                            continue;
                        }

                        if (fieldDef.FieldType == module.Cache.GetIntrinsic(IntrinsicType.String))
                        {
                            continue;
                        }

                        // Does not work?
                        //bool cloneable = fieldDef.FieldType.Inherits(cloneableTypeRef, GenericMap.Empty);
                        bool cloneable = typeof(ICloneable).IsAssignableFrom(fieldDef.FieldType.GetSystemType(null, null));


                        if (cloneable)
                        {
                            IField fieldSpec   = GenericHelper.GetFieldCanonicalGenericInstance(fieldDef);
                            bool   isValueType =
                                fieldSpec.FieldType.BelongsToClassification(TypeClassifications.ValueType).Equals(
                                    NullableBool.True);

                            InstructionSequence nextSequence = null;
                            if (!isValueType)
                            {
                                nextSequence = methodBody.CreateInstructionSequence();
                                writer.EmitInstruction(OpCodeNumber.Ldarg_0);
                                writer.EmitInstructionField(OpCodeNumber.Ldfld, fieldSpec);
                                writer.EmitBranchingInstruction(OpCodeNumber.Brfalse, nextSequence);
                            }
                            writer.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, castedCloneLocal);
                            writer.EmitInstruction(OpCodeNumber.Ldarg_0);
                            writer.EmitInstructionField(OpCodeNumber.Ldfld, fieldSpec);
                            if (isValueType)
                            {
                                writer.EmitInstructionType(OpCodeNumber.Box, fieldSpec.FieldType);
                            }
                            //writer.EmitInstructionType(OpCodeNumber.Castclass, cloneableTypeRef);
                            writer.EmitInstructionMethod(OpCodeNumber.Callvirt, cloneMethodRef);
                            if (isValueType)
                            {
                                writer.EmitInstructionType(OpCodeNumber.Unbox, fieldSpec.FieldType);
                                writer.EmitInstructionType(OpCodeNumber.Ldobj, fieldSpec.FieldType);
                            }
                            else
                            {
                                writer.EmitInstructionType(OpCodeNumber.Castclass, fieldSpec.FieldType);
                            }
                            writer.EmitInstructionField(OpCodeNumber.Stfld, fieldSpec);


                            if (!isValueType)
                            {
                                writer.DetachInstructionSequence();
                                instructionBlock.AddInstructionSequence(nextSequence, NodePosition.After, sequence);
                                sequence = nextSequence;
                                writer.AttachInstructionSequence(sequence);
                            }
                        }
                    }

                    writer.EmitInstruction(OpCodeNumber.Ret);
                    writer.DetachInstructionSequence();
                }
            }
        private static void ImplementSetter(
            PropertyDeclaration property,
            TypeDefDeclaration type,
            IField field,
            MethodAttributes methodAttributes,
            CustomAttributeDeclaration compilerGenerated)
        {
            // Implement setter
            var setter = new MethodDefDeclaration
            {
                Attributes = methodAttributes,
                Name = "set_" + property.Name,
                CallingConvention = CallingConvention.HasThis,
            };
            type.Methods.Add(setter);

            MarkCompilerGenerated(setter, compilerGenerated);
            setter.ReturnParameter = new ParameterDeclaration
            {
                ParameterType = type.Module.Cache.GetIntrinsic(IntrinsicType.Void),
                Attributes = ParameterAttributes.Retval
            };
            setter.Parameters.Add(new ParameterDeclaration(0, "value", property.PropertyType));

            var methodBody = new MethodBodyDeclaration();
            var sequence = methodBody.CreateInstructionSequence();
            var instructionBlock = methodBody.CreateInstructionBlock();
            instructionBlock.AddInstructionSequence(sequence, NodePosition.After, null);
            methodBody.RootInstructionBlock = instructionBlock;
            setter.MethodBody = methodBody;

            var writer = new InstructionWriter();
            writer.AttachInstructionSequence(sequence);
            writer.EmitInstruction(OpCodeNumber.Ldarg_0);
            writer.EmitInstruction(OpCodeNumber.Ldarg_1);
            writer.EmitInstructionField(OpCodeNumber.Stfld, field);
            writer.EmitInstruction(OpCodeNumber.Ret);
            writer.DetachInstructionSequence();

            property.Members.Add(new MethodSemanticDeclaration(MethodSemantics.Setter, setter));
        }
        public static void ImplementRemoveOn(
            this EventDeclaration theEvent,
            TypeDefDeclaration type,
            IField field,
            WeavingHelper weavingHelper = null,
            MethodAttributes methodAttributes =
                MethodAttributes.Public | MethodAttributes.HideBySig
                | MethodAttributes.Virtual | MethodAttributes.Final 
                | MethodAttributes.NewSlot | MethodAttributes.SpecialName)
        {
            var module = type.Module;
            weavingHelper = weavingHelper ?? new WeavingHelper(module);
            var pEWeavingHelper = module.Cache.GetItem(() => new PostEdgeWeaverAssets(module));

            var method = new MethodDefDeclaration {
                Attributes = methodAttributes,
                Name = "remove_" + theEvent.Name,
                CallingConvention = CallingConvention.HasThis
            };
            type.Methods.Add(method);
            weavingHelper.AddCompilerGeneratedAttribute(method.CustomAttributes);
            var parameter = new ParameterDeclaration {
                Name = "value",
                ParameterType = theEvent.EventType,
            };
            method.Parameters.Add(parameter);

            var methodBody = new MethodBodyDeclaration();
            methodBody.EnsureWritableLocalVariables();
            var instructionBlock = methodBody.CreateInstructionBlock();
            var initSequence = methodBody.CreateInstructionSequence();
            var loopSequence = methodBody.CreateInstructionSequence();
            var endSequence = methodBody.CreateInstructionSequence();
            instructionBlock.AddInstructionSequence(initSequence, NodePosition.After, null);
            instructionBlock.AddInstructionSequence(loopSequence, NodePosition.After, initSequence);
            instructionBlock.AddInstructionSequence(endSequence, NodePosition.After, loopSequence);
            methodBody.RootInstructionBlock = instructionBlock;
            method.MethodBody = methodBody;
            methodBody.CreateLocalVariable(theEvent.EventType);
            methodBody.CreateLocalVariable(theEvent.EventType);
            methodBody.CreateLocalVariable(theEvent.EventType);
            methodBody.CreateLocalVariable(module.Cache.GetIntrinsic(typeof(bool)));

            var writer = new InstructionWriter();
            //Initialize
            writer.AttachInstructionSequence(initSequence);

            //PropertyChangedHandler handler = this.PropertyChanged
            writer.EmitInstruction(OpCodeNumber.Ldarg_0);           //Get the this pointer
            writer.EmitInstructionField(OpCodeNumber.Ldfld, field); //Get the event's field
            writer.EmitInstruction(OpCodeNumber.Stloc_0);           //store into the first local variable
            writer.DetachInstructionSequence();

            //Loop
            //do {
            writer.AttachInstructionSequence(loopSequence);

            //PropertyChangedHandler handler2 = handler;
            writer.EmitInstruction(OpCodeNumber.Ldloc_0);
            writer.EmitInstruction(OpCodeNumber.Stloc_1);

            //PropertyChangedHandler handler3 = System.Delegate.Remove(handler2, value)
            writer.EmitInstruction(OpCodeNumber.Ldloc_1);
            writer.EmitInstruction(OpCodeNumber.Ldarg_1);
            writer.EmitInstructionMethod(OpCodeNumber.Call, pEWeavingHelper.DelegateRemoveMethod);
            writer.EmitInstructionType(OpCodeNumber.Castclass, theEvent.EventType);
            writer.EmitInstruction(OpCodeNumber.Stloc_2);

            //handler = System.Threading.Interlocked.CompareExchnage<PropertyChangedEventHandler>(ref this.PropertyChtyChanged, handler3, handler2);
            var compareExchangeMethodT = pEWeavingHelper.CompareExchangeMethod;
            var compareExchangeMethod = compareExchangeMethodT.GetGenericInstance(module, theEvent.EventType);
            writer.EmitInstruction(OpCodeNumber.Ldarg_0);           //Load this
            writer.EmitInstructionField(OpCodeNumber.Ldflda, field);
            writer.EmitInstruction(OpCodeNumber.Ldloc_2);
            writer.EmitInstruction(OpCodeNumber.Ldloc_1);
            writer.EmitInstructionMethod(OpCodeNumber.Call, compareExchangeMethod);
            writer.EmitInstruction(OpCodeNumber.Stloc_0);

            //flag = handler != handler2;
            writer.EmitInstruction(OpCodeNumber.Ldloc_0);
            writer.EmitInstruction(OpCodeNumber.Ldloc_1);
            writer.EmitInstruction(OpCodeNumber.Ceq);
            writer.EmitInstruction(OpCodeNumber.Ldc_I4_0);
            writer.EmitInstruction(OpCodeNumber.Ceq);
            writer.EmitInstruction(OpCodeNumber.Stloc_3);

            //} while (flag);
            writer.EmitInstruction(OpCodeNumber.Ldloc_3);
            writer.EmitBranchingInstruction(OpCodeNumber.Brtrue_S, loopSequence);

            writer.DetachInstructionSequence();

            //End
            writer.AttachInstructionSequence(endSequence);
            writer.EmitInstruction(OpCodeNumber.Ret);               //Exit the method
            writer.DetachInstructionSequence();

            theEvent.Members.Add(new MethodSemanticDeclaration(MethodSemantics.RemoveOn, method));
        }
            public override void Implement(TransformationContext context)
            {
                
                ModuleDeclaration module = this.AspectWeaver.Module;

                TypeDefDeclaration typeDef = (TypeDefDeclaration)context.TargetElement;

                // Declare the method.
                MethodDefDeclaration methodDef = new MethodDefDeclaration
                {
                    Name = "AutoGeneratedValidate",
                    Attributes = (MethodAttributes.Family | MethodAttributes.ReuseSlot | MethodAttributes.Virtual),
                    CallingConvention = CallingConvention.HasThis
                };
                typeDef.Methods.Add(methodDef);
                methodDef.CustomAttributes.Add(this.AspectWeaver.AspectInfrastructureTask.WeavingHelper.GetDebuggerNonUserCodeAttribute());

                // Define parameter.
                methodDef.ReturnParameter = new ParameterDeclaration
                {
                    ParameterType = module.Cache.GetIntrinsic(IntrinsicType.Void),
                    Attributes = ParameterAttributes.Retval
                };

                // Define the body
                MethodBodyDeclaration methodBody = new MethodBodyDeclaration();
                methodDef.MethodBody = methodBody;
                InstructionBlock instructionBlock = methodBody.CreateInstructionBlock();
                methodBody.RootInstructionBlock = instructionBlock;
                InstructionSequence sequence = methodBody.CreateInstructionSequence();
                instructionBlock.AddInstructionSequence(sequence, NodePosition.After, null);

                using (InstructionWriter writer = new InstructionWriter())
                {
                    writer.AttachInstructionSequence( sequence );

                    // Find the base method.
                    IMethod baseValidateMethod = null;
                    IType baseTypeCursor = typeDef.BaseType;
                    MethodSignature methodSignature =
                        new MethodSignature( module, CallingConvention.HasThis, module.Cache.GetIntrinsic( IntrinsicType.Void ),
                                             new ITypeSignature[0], 0 );

                    while ( baseValidateMethod == null )
                    {
                        TypeDefDeclaration baseTypeCursorTypeDef = baseTypeCursor.GetTypeDefinition();

                        baseValidateMethod =
                            baseTypeCursorTypeDef.Methods.GetMethod( "AutoGeneratedValidate",
                                                                     methodSignature.Translate( baseTypeCursorTypeDef.Module ),
                                                                     BindingOptions.OnlyExisting |
                                                                     BindingOptions.DontThrowException );

                        baseTypeCursor = baseTypeCursorTypeDef.BaseType;
                    }

                    // TODO: support generic base types.

                    // Call the base method.
                    writer.EmitInstruction( OpCodeNumber.Ldarg_0 );
                    writer.EmitInstructionMethod( OpCodeNumber.Call, (IMethod) baseValidateMethod.Translate( typeDef.Module ) );

                    // Make an array with the boxed field values.
                    TypeValidationAspect aspect = (TypeValidationAspect) this.AspectWeaverInstance.Aspect;
                    LocalVariableSymbol fieldValuesArrayLocal = instructionBlock.DefineLocalVariable(
                        module.Cache.GetType( typeof(object[]) ), "fieldValues" );
                    writer.EmitInstructionInt32( OpCodeNumber.Ldc_I4, aspect.Validators.Count );
                    writer.EmitInstructionType( OpCodeNumber.Newarr, module.Cache.GetIntrinsic( IntrinsicType.Object ) );
                    writer.EmitInstructionLocalVariable( OpCodeNumber.Stloc, fieldValuesArrayLocal );

                    int i = 0;
                    foreach ( FieldValidationAttribute validator in aspect.Validators )
                    {
                        FieldDefDeclaration fieldDef = typeDef.Fields.GetByName( validator.TargetLocation.Name );
                        IField fieldSpec = GenericHelper.GetFieldCanonicalGenericInstance( fieldDef );

                        writer.EmitInstructionLocalVariable( OpCodeNumber.Ldloc, fieldValuesArrayLocal );
                        writer.EmitInstructionInt32( OpCodeNumber.Ldc_I4, i );
                        writer.EmitInstruction( OpCodeNumber.Ldarg_0 );
                        writer.EmitInstructionField( OpCodeNumber.Ldfld, fieldSpec );
                        writer.EmitConvertToObject( fieldSpec.FieldType );
                        writer.EmitInstruction( OpCodeNumber.Stelem_Ref );

                        i++;
                    }

                    // Get the validator method.
                    IMethod validateMethod = module.Cache.GetItem(
                        () => module.FindMethod(
                                  typeof(TypeValidationAspect).GetMethod( "Validate" ),
                                  BindingOptions.Default ) );

                    // Call the validator.
                    this.AspectWeaverInstance.AspectRuntimeInstanceField.EmitLoadField( writer, null );
                    writer.EmitInstructionLocalVariable( OpCodeNumber.Ldloc, fieldValuesArrayLocal );
                    writer.EmitInstructionMethod( OpCodeNumber.Callvirt, validateMethod );

                    writer.EmitInstruction( OpCodeNumber.Ret );
                    writer.DetachInstructionSequence();
                }
            }
            public override void Implement( TransformationContext context )
            {
                TypeDefDeclaration typeDef = (TypeDefDeclaration) context.TargetElement;

                ModuleDeclaration module = this.AspectWeaver.Module;
                ITypeSignature baseEntityType = module.Cache.GetType( typeof(BaseEntity) );

                // Find the base method.
                IMethod baseCopyToMethod = null;
                IType baseTypeCursor = typeDef;
                MethodSignature methodSignature =
                    new MethodSignature(module, CallingConvention.HasThis, module.Cache.GetIntrinsic(IntrinsicType.Void),
                                         new[] { baseEntityType }, 0);

                while (baseCopyToMethod == null && baseTypeCursor != null)
                {
                    TypeDefDeclaration baseTypeCursorTypeDef = baseTypeCursor.GetTypeDefinition();

                    baseCopyToMethod =
                        baseTypeCursorTypeDef.Methods.GetMethod("CopyTo",
                                                                 methodSignature.Translate(baseTypeCursorTypeDef.Module),
                                                                 BindingOptions.OnlyExisting |
                                                                 BindingOptions.DontThrowException);

                    baseTypeCursor = baseTypeCursorTypeDef.BaseType;
                }

                if (baseCopyToMethod == null)
                    throw new AssertionFailedException("Could not find a method CopyTo.");

                if ( baseCopyToMethod.DeclaringType == typeDef )
                    return;


                // Declare the method.
                MethodDefDeclaration methodDef = new MethodDefDeclaration
                                                     {
                                                         Name = "CopyTo",
                                                         Attributes =
                                                             (MethodAttributes.Family | MethodAttributes.ReuseSlot |
                                                              MethodAttributes.Virtual),
                                                         CallingConvention = CallingConvention.HasThis
                                                     };
                typeDef.Methods.Add( methodDef );
                methodDef.CustomAttributes.Add( this.AspectWeaver.AspectInfrastructureTask.WeavingHelper.GetDebuggerNonUserCodeAttribute() );

                // Define parameter.
                methodDef.ReturnParameter = new ParameterDeclaration
                                                {
                                                    ParameterType = module.Cache.GetIntrinsic( IntrinsicType.Void ),
                                                    Attributes = ParameterAttributes.Retval
                                                };

                ParameterDeclaration cloneParameter =
                    new ParameterDeclaration( 0, "clone", baseEntityType );
                methodDef.Parameters.Add( cloneParameter );

                // Define the body
                MethodBodyDeclaration methodBody = new MethodBodyDeclaration();
                methodDef.MethodBody = methodBody;
                InstructionBlock instructionBlock = methodBody.CreateInstructionBlock();
                methodBody.RootInstructionBlock = instructionBlock;
                InstructionSequence sequence = methodBody.CreateInstructionSequence();
                instructionBlock.AddInstructionSequence( sequence, NodePosition.After, null );
                using (InstructionWriter writer = new InstructionWriter())
                {
                    writer.AttachInstructionSequence( sequence );

                    // Cast the argument and store it in a local variable.
                    IType typeSpec = GenericHelper.GetTypeCanonicalGenericInstance( typeDef );
                    LocalVariableSymbol castedCloneLocal = instructionBlock.DefineLocalVariable( typeSpec, "typedClone" );
                    writer.EmitInstruction( OpCodeNumber.Ldarg_1 );
                    writer.EmitInstructionType( OpCodeNumber.Castclass, typeSpec );
                    writer.EmitInstructionLocalVariable( OpCodeNumber.Stloc, castedCloneLocal );

                  
                    // TODO: support generic base types.


                    // Call the base method.
                    writer.EmitInstruction( OpCodeNumber.Ldarg_0 );
                    writer.EmitInstruction( OpCodeNumber.Ldarg_1 );
                    writer.EmitInstructionMethod( OpCodeNumber.Call, (IMethod) baseCopyToMethod.Translate( typeDef.Module ) );

                    // Loop on all fields and clone cloneable ones.
                    TypeRefDeclaration cloneableTypeRef = (TypeRefDeclaration)
                                                          module.Cache.GetType( typeof(ICloneable) );
                    MethodRefDeclaration cloneMethodRef = (MethodRefDeclaration) cloneableTypeRef.MethodRefs.GetMethod(
                                                                                     "Clone",
                                                                                     new MethodSignature(
                                                                                         module,
                                                                                         CallingConvention.HasThis,
                                                                                         module.Cache.GetIntrinsic(
                                                                                             IntrinsicType.Object ),
                                                                                         new ITypeSignature[0], 0 ),
                                                                                     BindingOptions.Default );

                    foreach ( FieldDefDeclaration fieldDef in typeDef.Fields )
                    {
                        if ( (fieldDef.Attributes & FieldAttributes.Static) != 0 )
                            continue;

                        if ( fieldDef.FieldType == module.Cache.GetIntrinsic( IntrinsicType.String ) )
                            continue;

                        // Does not work?
                        //bool cloneable = fieldDef.FieldType.Inherits(cloneableTypeRef, GenericMap.Empty);
                        bool cloneable = typeof(ICloneable).IsAssignableFrom( fieldDef.FieldType.GetSystemType( null, null ) );


                        if ( cloneable )
                        {
                            IField fieldSpec = GenericHelper.GetFieldCanonicalGenericInstance( fieldDef );
                            bool isValueType =
                                fieldSpec.FieldType.BelongsToClassification( TypeClassifications.ValueType ).Equals(
                                    NullableBool.True );

                            InstructionSequence nextSequence = null;
                            if ( !isValueType )
                            {
                                nextSequence = methodBody.CreateInstructionSequence();
                                writer.EmitInstruction( OpCodeNumber.Ldarg_0 );
                                writer.EmitInstructionField( OpCodeNumber.Ldfld, fieldSpec );
                                writer.EmitBranchingInstruction( OpCodeNumber.Brfalse, nextSequence );
                            }
                            writer.EmitInstructionLocalVariable( OpCodeNumber.Ldloc, castedCloneLocal );
                            writer.EmitInstruction( OpCodeNumber.Ldarg_0 );
                            writer.EmitInstructionField( OpCodeNumber.Ldfld, fieldSpec );
                            if ( isValueType )
                            {
                                writer.EmitInstructionType( OpCodeNumber.Box, fieldSpec.FieldType );
                            }
                            //writer.EmitInstructionType(OpCodeNumber.Castclass, cloneableTypeRef);
                            writer.EmitInstructionMethod( OpCodeNumber.Callvirt, cloneMethodRef );
                            if ( isValueType )
                            {
                                writer.EmitInstructionType( OpCodeNumber.Unbox, fieldSpec.FieldType );
                                writer.EmitInstructionType( OpCodeNumber.Ldobj, fieldSpec.FieldType );
                            }
                            else
                            {
                                writer.EmitInstructionType( OpCodeNumber.Castclass, fieldSpec.FieldType );
                            }
                            writer.EmitInstructionField( OpCodeNumber.Stfld, fieldSpec );


                            if ( !isValueType )
                            {
                                writer.DetachInstructionSequence();
                                instructionBlock.AddInstructionSequence( nextSequence, NodePosition.After, sequence );
                                sequence = nextSequence;
                                writer.AttachInstructionSequence( sequence );
                            }
                        }
                    }

                    writer.EmitInstruction( OpCodeNumber.Ret );
                    writer.DetachInstructionSequence();
                }
            }
Example #9
0
            public override void Implement(TransformationContext context)
            {
                ModuleDeclaration module = this.AspectWeaver.Module;

                TypeDefDeclaration typeDef = (TypeDefDeclaration)context.TargetElement;

                // Declare the method.
                MethodDefDeclaration methodDef = new MethodDefDeclaration
                {
                    Name              = "AutoGeneratedValidate",
                    Attributes        = (MethodAttributes.Family | MethodAttributes.ReuseSlot | MethodAttributes.Virtual),
                    CallingConvention = CallingConvention.HasThis
                };

                typeDef.Methods.Add(methodDef);
                methodDef.CustomAttributes.Add(this.AspectWeaver.AspectInfrastructureTask.WeavingHelper.GetDebuggerNonUserCodeAttribute());

                // Define parameter.
                methodDef.ReturnParameter = new ParameterDeclaration
                {
                    ParameterType = module.Cache.GetIntrinsic(IntrinsicType.Void),
                    Attributes    = ParameterAttributes.Retval
                };

                // Define the body
                MethodBodyDeclaration methodBody = new MethodBodyDeclaration();

                methodDef.MethodBody = methodBody;
                InstructionBlock instructionBlock = methodBody.CreateInstructionBlock();

                methodBody.RootInstructionBlock = instructionBlock;
                InstructionSequence sequence = methodBody.CreateInstructionSequence();

                instructionBlock.AddInstructionSequence(sequence, NodePosition.After, null);

                using (InstructionWriter writer = new InstructionWriter())
                {
                    writer.AttachInstructionSequence(sequence);

                    // Find the base method.
                    IMethod         baseValidateMethod = null;
                    IType           baseTypeCursor     = typeDef.BaseType;
                    MethodSignature methodSignature    =
                        new MethodSignature(module, CallingConvention.HasThis, module.Cache.GetIntrinsic(IntrinsicType.Void),
                                            new ITypeSignature[0], 0);

                    while (baseValidateMethod == null)
                    {
                        TypeDefDeclaration baseTypeCursorTypeDef = baseTypeCursor.GetTypeDefinition();

                        baseValidateMethod =
                            baseTypeCursorTypeDef.Methods.GetMethod("AutoGeneratedValidate",
                                                                    methodSignature.Translate(baseTypeCursorTypeDef.Module),
                                                                    BindingOptions.OnlyExisting |
                                                                    BindingOptions.DontThrowException);

                        baseTypeCursor = baseTypeCursorTypeDef.BaseType;
                    }

                    // TODO: support generic base types.

                    // Call the base method.
                    writer.EmitInstruction(OpCodeNumber.Ldarg_0);
                    writer.EmitInstructionMethod(OpCodeNumber.Call, (IMethod)baseValidateMethod.Translate(typeDef.Module));

                    // Make an array with the boxed field values.
                    TypeValidationAspect aspect = (TypeValidationAspect)this.AspectWeaverInstance.Aspect;
                    LocalVariableSymbol  fieldValuesArrayLocal = instructionBlock.DefineLocalVariable(
                        module.Cache.GetType(typeof(object[])), "fieldValues");
                    writer.EmitInstructionInt32(OpCodeNumber.Ldc_I4, aspect.Validators.Count);
                    writer.EmitInstructionType(OpCodeNumber.Newarr, module.Cache.GetIntrinsic(IntrinsicType.Object));
                    writer.EmitInstructionLocalVariable(OpCodeNumber.Stloc, fieldValuesArrayLocal);

                    int i = 0;
                    foreach (FieldValidationAttribute validator in aspect.Validators)
                    {
                        FieldDefDeclaration fieldDef = typeDef.Fields.GetByName(validator.TargetLocation.Name);
                        IField fieldSpec             = GenericHelper.GetFieldCanonicalGenericInstance(fieldDef);

                        writer.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, fieldValuesArrayLocal);
                        writer.EmitInstructionInt32(OpCodeNumber.Ldc_I4, i);
                        writer.EmitInstruction(OpCodeNumber.Ldarg_0);
                        writer.EmitInstructionField(OpCodeNumber.Ldfld, fieldSpec);
                        writer.EmitConvertToObject(fieldSpec.FieldType);
                        writer.EmitInstruction(OpCodeNumber.Stelem_Ref);

                        i++;
                    }

                    // Get the validator method.
                    IMethod validateMethod = module.Cache.GetItem(
                        () => module.FindMethod(
                            typeof(TypeValidationAspect).GetMethod("Validate"),
                            BindingOptions.Default));

                    // Call the validator.
                    this.AspectWeaverInstance.AspectRuntimeInstanceField.EmitLoadField(writer, null);
                    writer.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, fieldValuesArrayLocal);
                    writer.EmitInstructionMethod(OpCodeNumber.Callvirt, validateMethod);

                    writer.EmitInstruction(OpCodeNumber.Ret);
                    writer.DetachInstructionSequence();
                }
            }