private void ProcessProperty(CatelType catelType, CatelTypeProperty modelProperty, CustomAttribute exposeAttribute)
        {
            var modelName             = modelProperty.Name;
            var viewModelPropertyName = (string)exposeAttribute.ConstructorArguments[0].Value;
            var modelPropertyName     = viewModelPropertyName;

            if (exposeAttribute.ConstructorArguments.Count > 1)
            {
                modelPropertyName = (string)(exposeAttribute.ConstructorArguments[1].Value ?? viewModelPropertyName);
            }

            var isReadOnly         = false;
            var isReadOnlyProperty = (from property in exposeAttribute.Properties
                                      where string.Equals(property.Name, "IsReadOnly")
                                      select property).FirstOrDefault();

            if (isReadOnlyProperty.Argument.Value != null)
            {
                isReadOnly = (bool)isReadOnlyProperty.Argument.Value;
            }

            // Check property definition on model
            var modelType          = modelProperty.PropertyDefinition.PropertyType;
            var modelPropertyToMap = modelType.GetProperty(modelPropertyName);

            if (modelPropertyToMap is null)
            {
                FodyEnvironment.WriteError($"Exposed property '{modelPropertyName}' does not exist on model '{modelType.FullName}', make sure to set the right mapping");
                return;
            }

            var modelPropertyType = modelType.ResolveGenericPropertyType(modelPropertyToMap);

            var viewModelPropertyDefinition = new PropertyDefinition(viewModelPropertyName, PropertyAttributes.None, FodyEnvironment.ModuleDefinition.ImportReference(modelPropertyType));

            viewModelPropertyDefinition.DeclaringType = catelType.TypeDefinition;

            catelType.TypeDefinition.Properties.Add(viewModelPropertyDefinition);

            viewModelPropertyDefinition.MarkAsCompilerGenerated(_msCoreReferenceFinder);

            var catelTypeProperty = new CatelTypeProperty(catelType.TypeDefinition, viewModelPropertyDefinition);

            catelTypeProperty.IsReadOnly = isReadOnly;

            var catelPropertyWeaver = new ModelBasePropertyWeaver(catelType, catelTypeProperty, _configuration, _moduleWeaver, _msCoreReferenceFinder);

            catelPropertyWeaver.Execute(true);

            var stringType           = _msCoreReferenceFinder.GetCoreTypeReference("String");
            var stringTypeDefinition = catelType.TypeDefinition.Module.ImportReference(stringType);

            var attributeConstructor      = catelType.TypeDefinition.Module.ImportReference(_viewModelToModelAttributeTypeDefinition.Constructor(false));
            var viewModelToModelAttribute = new CustomAttribute(attributeConstructor);

            viewModelToModelAttribute.ConstructorArguments.Add(new CustomAttributeArgument(stringTypeDefinition, modelName));
            viewModelToModelAttribute.ConstructorArguments.Add(new CustomAttributeArgument(stringTypeDefinition, modelPropertyName));
            viewModelPropertyDefinition.CustomAttributes.Add(viewModelToModelAttribute);
        }
        private void Process(List <CatelType> catelTypes)
        {
            foreach (var catelType in catelTypes)
            {
                FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{catelType.TypeDefinition.FullName}'");

                foreach (var propertyData in catelType.Properties)
                {
                    var body = propertyData.PropertyDefinition.SetMethod.Body;

                    body.SimplifyMacros();

                    switch (catelType.Type)
                    {
                    case CatelTypeType.ViewModel:
                    case CatelTypeType.Model:
                        var modelBasePropertyWeaver = new ModelBasePropertyWeaver(catelType, propertyData, _configuration, _moduleWeaver, _msCoreReferenceFinder);
                        modelBasePropertyWeaver.Execute();
                        break;

                    case CatelTypeType.ObservableObject:
                        var observableObjectPropertyWeaver = new ObservableObjectPropertyWeaver(catelType, propertyData, _moduleWeaver, _msCoreReferenceFinder);
                        observableObjectPropertyWeaver.Execute();
                        break;

                    default:
                        break;
                    }

                    body.InitLocals = true;
                    body.OptimizeMacros();
                }

                if (_configuration.WeaveCalculatedProperties)
                {
                    var onPropertyChangedWeaver = new OnPropertyChangedWeaver(catelType, _msCoreReferenceFinder);
                    onPropertyChangedWeaver.Execute();
                }

                // Note: for now this is disabled. In advanced scenarios (see unit test for ReplacesRaisePropertyChanged_Advanced), it somehow does
                // not correctly replace the "leave_s" operand. The quick watch shows that the method is correctly updated, but the IL *and* the unit test
                // both show incorrect execution
                //var raisePropertyChangedWeaver = new RaisePropertyChangedWeaver(catelType, _msCoreReferenceFinder);
                //raisePropertyChangedWeaver.Execute();
            }
        }