private void AddDebugAttributes(ModelInfo model) { foreach (var type in model.Types) { type.Using.Add("System.Diagnostics"); type.BaseOnlyAnnotations.Add(CreateDebugDisplay(type)); foreach (var prop in type.Properties) { if (prop is ComputedPropertyInfo) { var computed = (ComputedPropertyInfo) prop; computed.FieldAnnotations.Add("DebuggerBrowsable(DebuggerBrowsableState.Never)"); computed.InvalidFieldAnnotations.Add("DebuggerBrowsable(DebuggerBrowsableState.Never)"); } else if (!type.Immutable) { prop.FieldAnnotations.Add("DebuggerBrowsable(DebuggerBrowsableState.Never)"); } prop.PropGetAnnotations.Add("DebuggerStepThrough"); prop.PropSetAnnotations.Add("DebuggerStepThrough"); if (prop.Getter != null) prop.Getter.Annotations.Add("DebuggerStepThrough"); if (prop.Setter != null) prop.Setter.Annotations.Add("DebuggerStepThrough"); if (prop.LazyInitializer != null) prop.LazyInitializer.Annotations.Add("DebuggerStepThrough"); } } }
private void AddNotifcationInformation(ModelInfo model) { foreach (var type in model.Types) { if (type.Immutable) continue; type.Using.Add("System"); type.Using.Add("System.ComponentModel"); type.Using.Add("org.pescuma.ModelSharp.Lib"); type.Implements.Add("INotifyPropertyChanging"); type.Implements.Add("INotifyChildPropertyChanging"); type.Implements.Add("INotifyPropertyChanged"); type.Implements.Add("INotifyChildPropertyChanged"); } }
private void AddDataContracts(ModelInfo model) { foreach (var type in model.Types) { if (!type.Serializable) continue; type.Using.Add("System.Runtime.Serialization"); if (!string.IsNullOrWhiteSpace(GlobalConfig.SerializationNamespace)) { type.TypeOnlyAnnotations.Add(string.Format( "DataContract(Name = \"{0}\", Namespace = \"{1}\")", type.Name, GlobalConfig.SerializationNamespace)); type.BaseOnlyAnnotations.Add(string.Format("DataContract(Namespace = \"{0}\")", GlobalConfig.SerializationNamespace)); } else { type.TypeOnlyAnnotations.Add(string.Format("DataContract(Name = \"{0}\")", type.Name)); type.BaseOnlyAnnotations.Add("DataContract"); } foreach (var prop in type.Properties) { if (prop is ComputedPropertyInfo) continue; prop.FieldAnnotations.Add( string.Format("DataMember(Name = \"{0}\", Order = {1}, IsRequired = {2})", prop.Name, prop.Order, prop.Required ? "true" : "false")); } } }
private void MakeChangesForImmutable(ModelInfo model) { // Convert all properties to fields foreach (var type in model.Types) { if (!type.Immutable) continue; foreach (var prop in type.Properties) prop.MakeImmutable(); } }
private void ComputePropertyOrder(ModelInfo model) { foreach (var type in model.Types) { int index = 0; foreach (var prop in type.Properties) { if (prop is ComputedPropertyInfo) continue; prop.Order = index++; } } }
private void CopyUsingsToType(ModelInfo model) { foreach (var type in model.Types) { foreach (var ns in model.Using) { type.Using.Add(ns); } } }
private void AddCollectionUsings(ModelInfo model) { foreach (var type in model.Types) { if (type.HasCollections && !type.Immutable) { type.Using.Add("org.pescuma.ModelSharp.Lib"); if (type.HasCollectionWithListenContentType) type.Using.Add("System.Collections.Specialized"); } } }
private void AddClonable(ModelInfo model) { foreach (var type in model.Types) { if (!type.Cloneable) continue; type.Using.Add("System"); type.Implements.Add("ICloneable"); } }
private void AddCopyable(ModelInfo model) { foreach (var type in model.Types) { if (type.Immutable || !type.Cloneable) continue; type.Implements.Add("ICopyable"); } }
private void ComputeTypeInfoForProperties(ModelInfo model) { foreach (var type in model.Types) { foreach (var prop in type.Properties) { prop.TypeInfo = model.GetType(prop.TypeName); if (prop is CollectionInfo) { var col = (CollectionInfo) prop; col.ContentsType.TypeInfo = model.GetType(col.ContentsType.TypeName); } } } }
private void ComputeDependentProperties(ModelInfo model) { foreach (var type in model.Types) { foreach (var prop in type.Properties) { var computed = prop as ComputedPropertyInfo; if (computed == null) continue; foreach (var fullPath in computed.DependsOn) { var dep = fullPath.Split('.').First(); var other = (from p in type.Properties where p.Name == dep select p).FirstOrDefault(); if (other == null) { log.Error("Could not find property referenced on dependsOn: " + fullPath); continue; } var path = string.Join(".", fullPath.Split('.').Skip(1).ToArray()); other.AddDependentProperty(computed, path); } } } }
private bool HasParent(ModelInfo model, TypeInfo type, Func<TypeInfo, bool> filter = null) { // the max value is just to avoid an infinite loop for (int i = 0; i < 10000; i++) { if (type.Extends == null) return false; var baseType = model.GetType(type.Extends); if (baseType == null) return false; if (filter == null || filter(baseType)) return true; type = baseType; } throw new InvalidOperationException("Type hierarchy is too deep. Didn't you made a recursion?"); }
// private void CheckIfCanCloneAllNeededFields(ModelInfo model) // { // foreach (var type in model.Types) // { // if (!type.Cloneable) // continue; // // foreach (var prop in type.Properties) // { // if (!prop.DeepCopy) // continue; // // if (!prop.HasCopyConstructor && prop.CreateExternalCopyMethod("a") == null) // log.Error("Can't deep copy field " + type.Name + "." + prop.Name); // } // } // } private void UpdateExtendsProperties(ModelInfo model) { foreach (var type in model.Types) { if (!HasParent(model, type)) continue; type.BaseClass.IsGenerated = true; type.BaseClass.HasChildPropertyChanged = true; type.BaseClass.HasChildPropertyChanging = true; type.BaseClass.HasPropertyChanged = true; type.BaseClass.HasPropertyChanging = true; type.BaseClass.HasCopyFrom = true; type.BaseClass.HasProperties = true; } }
private void AddUsingsForKnownTypes(ModelInfo model) { foreach (var type in model.Types) { AddUsingsFromKnownTypes(type, type.Extends); foreach (var prop in type.Properties) AddUsingsFromKnownTypes(type, prop.TypeName); } }
private void PosProcessModel(ModelInfo model) { ComputeDependentProperties(model); CopyUsingsToType(model); AddCollectionUsings(model); MakeChangesForImmutable(model); UpdateExtendsProperties(model); ComputeTypeInfoForProperties(model); ComputePropertyOrder(model); AddNotifcationInformation(model); AddDataContracts(model); AddDebugAttributes(model); AddClonable(model); AddCopyable(model); // CheckIfCanCloneAllNeededFields(model); AddUsingsForKnownTypes(model); }
private ModelInfo CreateModel(xml.model model) { NamingConventions conventions = new NamingConventions(); ModelInfo result = new ModelInfo(); if (!string.IsNullOrWhiteSpace(model.projectNamespace)) GlobalConfig.ProjectNamespace = model.projectNamespace; foreach (var modelItem in model.Items) { if (modelItem is config) { var config = (config) modelItem; if (config.serialization != null && !string.IsNullOrWhiteSpace(config.serialization.@namespace)) GlobalConfig.SerializationNamespace = [email protected](); } else if (modelItem is type) { var type = (type) modelItem; var ti = new TypeInfo(type.name, model.@namespace, type.immutable, type.cloneable, type.serializable, type.equals); if (type.deepCopySpecified) ti.DeepCopy = type.deepCopy; if (!string.IsNullOrWhiteSpace(type.doc)) ti.Documentation = type.doc; if (!string.IsNullOrWhiteSpace(type.implements)) { var impls = type.implements.Split(','); foreach (var impl in impls) { var tmp = impl.Trim(); if (!string.IsNullOrWhiteSpace(tmp)) ti.Implements.Add(tmp); } } if (type.extends != null && type.extends.Trim() != "") ti.Extends = type.extends.Trim(); if (type.baseClass != null) { var bc = type.baseClass; if (bc.hasChildPropertyChangedSpecified) ti.BaseClass.HasChildPropertyChanged = bc.hasChildPropertyChanged; if (bc.hasPropertyChangedSpecified) ti.BaseClass.HasPropertyChanged = bc.hasPropertyChanged; if (bc.hasChildPropertyChangingSpecified) ti.BaseClass.HasChildPropertyChanging = bc.hasChildPropertyChanging; if (bc.hasPropertyChangingSpecified) ti.BaseClass.HasPropertyChanging = bc.hasPropertyChanging; if (bc.hasCopyFromSpecified) ti.BaseClass.HasCopyFrom = bc.hasCopyFrom; if (bc.hasPropertiesSpecified) ti.BaseClass.HasProperties = bc.hasProperties; } foreach (var item in type.Items) { if (item is property) { var property = (property) item; var prop = new PropertyInfo(conventions, ti, property.name, property.type, property.required, false); if (property.deepCopySpecified) prop.DeepCopy = property.deepCopy; if (!string.IsNullOrWhiteSpace(property.doc)) prop.Documentation = property.doc; if (!string.IsNullOrWhiteSpace(property.@default)) prop.DefaultValue = property.@default; if (!string.IsNullOrWhiteSpace(property.getter) && ValidateVisibility(property.getter, "getter")) prop.GetterVisibility = property.getter; if (!string.IsNullOrWhiteSpace(property.setter) && ValidateVisibility(property.setter, "setter")) prop.SetterVisibility = property.setter; if (property.receiveInConstructorSpecified && property.receiveInConstructor) prop.ReceiveInConstructor = property.receiveInConstructor; if (property.precisionSpecified) prop.Precision = (double) property.precision; if (prop.Required && !prop.IsPrimitive) prop.Validations.Add(new ValidationInfo("value == null", property.requiredException ?? "new ArgumentNullException(property)", "#pragma warning disable 472\n// ReSharper disable ConditionIsAlwaysTrueOrFalse", "// ReSharper restore ConditionIsAlwaysTrueOrFalse\n#pragma warning restore 472")); prop.AddValidationAttrib(property.validationAttrib, property.validationException); prop.AddValidation(property.validation1, property.validationException); if (property.validation != null) { foreach (var validation in property.validation) { prop.AddValidationAttrib(validation.attrib, validation.exception); prop.AddValidation(validation.test, validation.exception); } } ti.Properties.Add(prop); } else if (item is component) { var component = (component) item; var comp = new ComponentInfo(conventions, ti, component.name, component.type, component.lazy); if (!string.IsNullOrWhiteSpace(component.doc)) comp.Documentation = component.doc; if (!string.IsNullOrWhiteSpace(component.@default)) comp.DefaultValue = component.@default; if (component.receiveInConstructorSpecified && component.receiveInConstructor) comp.ReceiveInConstructor = component.receiveInConstructor; comp.AddValidationAttrib(component.validationAttrib, component.validationException); comp.AddValidation(component.validation1, component.validationException); if (component.validation != null) { foreach (var validation in component.validation) { comp.AddValidationAttrib(validation.attrib, validation.exception); comp.AddValidation(validation.test, validation.exception); } } ti.Properties.Add(comp); } else if (item is collection) { var collection = (collection) item; var col = new CollectionInfo(conventions, ti, collection.name, collection.type, collection.lazy, collection.readOnly); if (collection.deepCopySpecified) col.DeepCopy = collection.deepCopy; if (!string.IsNullOrWhiteSpace(collection.doc)) col.Documentation = collection.doc; if (!string.IsNullOrWhiteSpace(collection.@default)) col.DefaultValue = collection.@default; ti.Properties.Add(col); } else if (item is computedproperty) { var computed = (computedproperty) item; var deps = (from d in computed.dependsOn.Split(',') where d.Trim() != "" select StringUtils.FirstUpper(d.Trim())); var prop = new ComputedPropertyInfo(conventions, ti, computed.name, computed.type, computed.cached, deps, computed.formula); if (!string.IsNullOrWhiteSpace(computed.getter) && ValidateVisibility(computed.getter, "getter")) prop.GetterVisibility = computed.getter; if (!string.IsNullOrWhiteSpace(computed.doc)) prop.Documentation = computed.doc; ti.Properties.Add(prop); } else if (item is @using) { var us = item as @using; ti.Using.Add(us.@namespace); } } result.AddType(ti); } else if (modelItem is @using) { var us = modelItem as @using; result.Using.Add(us.@namespace); } } return result; }