Example #1
0
        internal FieldDefinition ImplementMappingField(PropertyDefinition property)
        {
            // Load the property mapping type.
            TypeReference mappingType = MainModule.Import(typeof(PropertyMapping <>));

            Assert.IsNotNull(mappingType, "{0}: Failed to import type {1}.", Assembly.FullName, mappingType.FullName);

            // Add the property type as generic parameter.
            GenericInstanceType fieldType = new GenericInstanceType(mappingType);

            fieldType.GenericArguments.Add(property.PropertyType);

            // Generate the name of the private backing field.
            string fieldName = "_" + Char.ToLowerInvariant(property.Name[0]) + property.Name.Substring(1) + "Mapping";

            // Implement the field.
            FieldDefinition mappingField = new FieldDefinition(fieldName, FieldAttributes.Family, fieldType);

            Type.Fields.Add(mappingField);

            FieldReference backingField = property.TryGetBackingField();

            if (backingField != null)
            {
                Type.Fields.Remove(backingField.Resolve());
            }

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (!Uri.IsWellFormedUriString(p.Uri, UriKind.Absolute))
            {
                throw new UriFormatException("Annotated URI must be in absolute format.");
            }

            // Finally, implement the field initializers in the constructors of the class.
            foreach (MethodDefinition ctor in Type.GetConstructors())
            {
                // Implementing mapping fields in static constructors results in invalid byte code,
                // since there is no ldarg.0 (this) variable.
                if (ctor.IsStatic)
                {
                    continue;
                }

                MethodGeneratorTask g = new MethodGeneratorTask(ctor);
                g.Instructions.AddRange(GetFieldInitializationInstructions(g.Processor, p, fieldType));
                g.Instructions.AddRange(ctor.Body.Instructions);

                if (g.CanExecute())
                {
                    g.Execute();
                }
            }

            return(mappingField);
        }
Example #2
0
        private bool ImplementPropertyMapping(PropertyDefinition property, MethodDefinition raisePropertyChanged)
        {
            ImplementRdfPropertyTask subtask = new ImplementRdfPropertyTask(Generator, Type);

            FieldDefinition mappingField = subtask.ImplementMappingField(property);

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            MethodGeneratorTask getValueGenerator = subtask.GetGetValueGenerator(p);
            MethodGeneratorTask setValueGenerator = subtask.GetSetValueGenerator(p);

            if (!getValueGenerator.CanExecute())
            {
                string msg = "{0}.{1}: Failed to implement property getter.";
                throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
            }

            if (!setValueGenerator.CanExecute())
            {
                string msg = "{0}.{1}: Failed to implement property setter.";
                throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
            }

            Instruction ret = setValueGenerator.Processor.Create(OpCodes.Ret);

            // Instructions for calling SetValue()
            IList <Instruction> sv = new List <Instruction>(setValueGenerator.Instructions);

            sv.RemoveAt(0);            // Remove the first nop-Instruction..
            sv.RemoveAt(sv.Count - 1); // Remove the ret-Instruction..

            // Instructions for return on equal values.
            MethodReference getValue = Type.TryGetGetValueMethod(Assembly, property.PropertyType);

            IList <Instruction> roe = GetReturnOnEqualsInstructionsForMapping(setValueGenerator.Processor, mappingField, getValue, sv.First(), ret).ToList();

            Assert.Greater(roe.Count, 0, "{0}.{1}: Failed to generate byte code for return on equality.", Type.FullName, property.Name);

            // Instructions for calling RaisePropertyChanged()
            IList <Instruction> rpc = GetRaisePropertyChangedInstructions(setValueGenerator.Processor, property, raisePropertyChanged).ToList();

            Assert.Greater(rpc.Count, 0, "{0}: Failed to generate byte code for calling the RaisePropertyChanged() method.", Type.FullName);

            // Re-write the instructions for the SetValue() method generator.
            setValueGenerator.Processor.Body.MaxStackSize = IsMappedProperty ? 4 : 2;
            setValueGenerator.Instructions.Clear();
            setValueGenerator.Instructions.AddRange(roe);
            setValueGenerator.Instructions.AddRange(sv);
            setValueGenerator.Instructions.AddRange(rpc);
            setValueGenerator.Instructions.Add(ret);
            setValueGenerator.Execute();

            getValueGenerator.Execute();

            return(true);
        }
        public override bool Execute(object parameter = null)
        {
            PropertyDefinition property = parameter as PropertyDefinition;

            if (property == null)
            {
                return(false);
            }

            FieldDefinition mappingField = ImplementMappingField(property);

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (p.Property.GetMethod != null)
            {
                if (p.Property.GetMethod.HasCustomAttribute <CompilerGeneratedAttribute>() || p.Property.GetMethod.IsCompilerControlled)
                {
                    MethodGeneratorTask getValueGenerator = GetGetValueGenerator(p);

                    if (getValueGenerator.CanExecute())
                    {
                        getValueGenerator.Execute();
                    }
                    else
                    {
                        string msg = "{0}.{1}: Failed to implement property getter.";
                        throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
                    }
                }
            }

            if (p.Property.SetMethod != null)
            {
                if (p.Property.SetMethod.HasCustomAttribute <CompilerGeneratedAttribute>() || p.Property.SetMethod.IsCompilerControlled)
                {
                    MethodGeneratorTask setValueGenerator = GetSetValueGenerator(p);

                    if (setValueGenerator.CanExecute())
                    {
                        setValueGenerator.Execute();
                    }
                    else
                    {
                        string msg = "{0}.{1}: Failed to implement property setter.";
                        throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
                    }
                }
            }

            Log.LogMessage("{0}.{1} -> <{2}>", Type.FullName, property.Name, p.Uri);

            return(true);
        }
Example #4
0
        /// <summary>
        /// Implements the .GetTypes method which returns a list of all annotated RDF classes for a given type.
        /// </summary>
        /// <param name="parameter">A type defintion.</param>
        /// <returns><c>true</c> on success, <c>false</c> otherwise.</returns>
        public override bool Execute(object parameter = null)
        {
            List <string> uris = new List <string>();

            // Accumulate the annotated RDF classes.
            foreach (CustomAttribute attribute in Type.TryGetCustomAttribute("RdfClassAttribute"))
            {
                uris.Insert(0, attribute.ConstructorArguments.First().Value.ToString());
            }

            if (uris.Count == 0)
            {
                if (!Type.Methods.Any(m => m.Name == "GetTypes"))
                {
                    string msg = "{0}: Mapped type has no annotated RDF classes and no overridden GetTypes() method.";

                    throw new Exception(string.Format(msg, Type.FullName));
                }

                return(false);
            }

            TypeDefinition[] types       = { Type };
            MethodDefinition getTypes    = null;
            MethodReference  getTypeBase = null;

            // We iterate through the type hierarchy from top to bottom and find the first GetTypes
            // method. That one serves as a template for the override method of the current type in
            // which the instructions are being replaced.
            foreach (TypeDefinition t in types.Union(Type.GetBaseTypes()).Reverse())
            {
                getTypes = t.TryGetInheritedMethod("GetTypes");

                if (getTypes != null && getTypeBase == null)
                {
                    getTypeBase = getTypes;

                    break;
                }
            }

            if (getTypes == null)
            {
                throw new ArgumentException("{0}: Found no GetTypes() method for type.", Type.FullName);
            }

            if (getTypeBase == null)
            {
                throw new ArgumentException(string.Format("{0}: Failed to find virtual base method of {1}", Type.FullName, getTypes.FullName));
            }

            // The override method must be created in the module where the type is defined.
            getTypes = getTypeBase.GetOverrideMethod(MainModule);

            MethodGeneratorTask generator = new MethodGeneratorTask(getTypes);

            generator.Instructions.AddRange(GenerateGetTypesInstructions(generator.Processor, uris));

            if (generator.CanExecute())
            {
                generator.Method.Body.MaxStackSize = 3;
                generator.Method.Body.InitLocals   = true;
                generator.Method.Body.Variables.Add(new VariableDefinition(MainModule.ImportReference(getTypeBase.ReturnType)));
                generator.Method.Body.Variables.Add(new VariableDefinition(ClassArrayType));
                generator.Execute();
                MainModule.ImportReference(ClassType);
            }

            Type.Methods.Add(getTypes);

            foreach (string uri in uris)
            {
                Log.LogMessage("{0} -> <{1}>", Type.FullName, uri);
            }

            return(true);
        }
        internal FieldDefinition ImplementMappingField(PropertyDefinition property)
        {
            // Load the property mapping type.
            TypeReference mappingType = MainModule.ImportReference(ILGenerator.PropertyMapping);

            if (mappingType == null)
            {
                throw new ArgumentException(string.Format("{0}: Failed to import type {1}.", Assembly.FullName, mappingType.FullName));
            }

            // Add the property type as generic parameter.
            GenericInstanceType fieldType = new GenericInstanceType(mappingType);

            fieldType.GenericArguments.Add(property.PropertyType);

            // Generate the name of the private backing field.
            string fieldName = "<" + Char.ToLowerInvariant(property.Name[0]) + property.Name.Substring(1) + ">" + "k__" + "MappingField";

            var mappingField = Type.TryGetField(fieldName);

            if (mappingField == null)
            {
                // Implement the field.
                mappingField = new FieldDefinition(fieldName, FieldAttributes.Family, fieldType);
                Type.Fields.Add(mappingField);
            }

            FieldReference backingField = property.TryGetBackingField();

            if (backingField != null)
            {
                Type.Fields.Remove(backingField.Resolve());
            }

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (!Uri.IsWellFormedUriString(p.Uri, UriKind.Absolute))
            {
                throw new UriFormatException("Annotated URI must be in absolute format.");
            }

            // Finally, implement the field initializers in the constructors of the class.
            foreach (MethodDefinition ctor in Type.GetConstructors())
            {
                // Implementing mapping fields in static constructors results in invalid byte code,
                // since there is no ldarg.0 (this) variable.
                if (ctor.IsStatic)
                {
                    continue;
                }

                MethodGeneratorTask g = new MethodGeneratorTask(ctor);

                List <Instruction> Omit = new List <Instruction>();
                bool alreadyInitialized = false;
                foreach (var x in ctor.Body.Instructions)
                {
                    if (backingField != null && x.Operand == backingField)
                    {
                        p.Initializer = new List <Instruction>();
                        Omit.Add(x);
                        var inst = x;
                        while (inst.Previous.OpCode.Code != Code.Ldarg_0)
                        {
                            inst = inst.Previous;
                            p.Initializer.Insert(0, inst);
                            // Remove this initializiation from constructor
                            Omit.Add(inst);
                        }
                        Omit.Add(inst.Previous);
                    }
                    if (mappingField != null && x.Operand != null && x.Operand is FieldDefinition && (x.Operand as FieldDefinition).FullName == mappingField.FullName)
                    {
                        alreadyInitialized = true;
                        continue;
                    }
                }
                if (alreadyInitialized)
                {
                    continue;
                }

                g.Instructions.AddRange(GetFieldInitializationInstructions(g.Processor, p, fieldType));
                g.Instructions.AddRange(ctor.Body.Instructions.Where((x) => !Omit.Contains(x)));

                if (g.CanExecute())
                {
                    g.Execute();
                }
            }


            return(mappingField);
        }