Skip to content

Commit

Permalink
Rename interface property if property renamed in derived class
Browse files Browse the repository at this point in the history
If some class has property with the same name as class, then property renamed to 'xxxProperty'. If some interface has property with a name same as one of derived classes then interface property must be renamed too.
This commit ensures that interface property and properties in all interface implementations renamed too.
  • Loading branch information
AVTit committed May 1, 2020
1 parent adb27ca commit b219658
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 17 deletions.
79 changes: 79 additions & 0 deletions XmlSchemaClassGenerator.Tests/XmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1423,5 +1423,84 @@ public void EnumWithNonUniqueEntriesTest()
Assert.NotNull(xmlEnumAttribute);
Assert.Equal("test_Case", xmlEnumAttribute.Name);
}

[Fact]
public void RenameInterfacePropertyInDerivedClassTest()
{
const string xsd = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema""
elementFormDefault=""qualified"" attributeFormDefault=""unqualified"">
<xs:complexType name=""ClassItemBase"">
<xs:sequence>
<xs:group ref=""Level1""/>
</xs:sequence>
</xs:complexType>
<xs:element name=""ClassItem"">
<xs:complexType>
<xs:complexContent>
<xs:extension base=""ClassItemBase""/>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name=""SomeType1"">
<xs:complexType>
<xs:group ref=""Level1""/>
</xs:complexType>
</xs:element>
<xs:group name=""Level1"">
<xs:choice>
<xs:group ref=""Level2""/>
</xs:choice>
</xs:group>
<xs:group name=""Level2"">
<xs:choice>
<xs:group ref=""Level3""/>
</xs:choice>
</xs:group>
<xs:group name=""Level3"">
<xs:choice>
<xs:element name=""ClassItemBase"" type=""xs:string""/>
</xs:choice>
</xs:group>
</xs:schema>";

var generator = new Generator
{
NamespaceProvider = new NamespaceProvider
{
GenerateNamespace = key => "Test"
},
GenerateInterfaces = true,
AssemblyVisible = true
};
var contents = ConvertXml(nameof(RenameInterfacePropertyInDerivedClassTest), xsd, generator);
var content = Assert.Single(contents);

var assembly = Compiler.Compile(nameof(RenameInterfacePropertyInDerivedClassTest), content);
var classType = assembly.GetType("Test.ClassItem");
Assert.NotNull(classType);
Assert.Single(classType.GetProperties());
Assert.Equal("ClassItemBaseProperty", classType.GetProperties().First().Name);

var level1Interface = assembly.GetType("Test.ILevel1");
Assert.NotNull(level1Interface);
Assert.Empty(level1Interface.GetProperties());

var level2Interface = assembly.GetType("Test.ILevel1");
Assert.NotNull(level2Interface);
Assert.Empty(level2Interface.GetProperties());

var level3Interface = assembly.GetType("Test.ILevel3");
Assert.NotNull(level3Interface);
Assert.Single(level3Interface.GetProperties());
Assert.Equal("ClassItemBaseProperty", level3Interface.GetProperties().First().Name);
}
}
}
60 changes: 52 additions & 8 deletions XmlSchemaClassGenerator/ModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,46 @@ public ModelBuilder(GeneratorConfiguration configuration, XmlSchemaSet set)
var elements = set.GlobalElements.Values.Cast<XmlSchemaElement>().Where(s => s.GetSchema() == schema);
CreateElements(elements);
}

if (configuration.GenerateInterfaces)
{
RenameInterfacePropertiesIfRenamedInDerivedClasses();
}
}

private void RenameInterfacePropertiesIfRenamedInDerivedClasses()
{
foreach (var interfaceModel in Types.Values.OfType<InterfaceModel>())
{
foreach (var interfaceProperty in interfaceModel.Properties)
{
foreach (var implementationClass in interfaceModel.AllDerivedReferenceTypes())
foreach (var implementationClassProperty in implementationClass.Properties)
{
if (implementationClassProperty.Name != implementationClassProperty.OriginalPropertyName
&& implementationClassProperty.OriginalPropertyName == interfaceProperty.Name
)
{
RenameInterfacePropertyInBaseClasses(interfaceModel, implementationClass, interfaceProperty, implementationClassProperty.Name);
interfaceProperty.Name = implementationClassProperty.Name;
}
}
}
}
}

private static void RenameInterfacePropertyInBaseClasses(InterfaceModel interfaceModel, ReferenceTypeModel implementationClass,
PropertyModel interfaceProperty, string newName)
{
foreach (var interfaceModelImplementationClass in interfaceModel.AllDerivedReferenceTypes().Where(c =>
c != implementationClass))
{
foreach (var propertyModel in interfaceModelImplementationClass.Properties.Where(p =>
p.Name == interfaceProperty.Name))
{
propertyModel.Name = newName;
}
}
}

private void ResolveDependencies(XmlSchema schema, List<XmlSchema> dependencyOrder, HashSet<XmlSchema> seenSchemas)
Expand Down Expand Up @@ -217,7 +257,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaGroup group, NamespaceMod
interfaceModel.Properties.AddRange(properties);
var interfaces = items.Select(i => i.XmlParticle).OfType<XmlSchemaGroupRef>()
.Select(i => (InterfaceModel)CreateTypeModel(CodeUtilities.CreateUri(i.SourceUri), Groups[i.RefName], i.RefName));
interfaceModel.Interfaces.AddRange(interfaces);
interfaceModel.AddInterfaces(interfaces);

return interfaceModel;
}
Expand Down Expand Up @@ -249,7 +289,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaAttributeGroup attributeG
interfaceModel.Properties.AddRange(properties);
var interfaces = items.OfType<XmlSchemaAttributeGroupRef>()
.Select(a => (InterfaceModel)CreateTypeModel(CodeUtilities.CreateUri(a.SourceUri), AttributeGroups[a.RefName], a.RefName));
interfaceModel.Interfaces.AddRange(interfaces);
interfaceModel.AddInterfaces(interfaces);

return interfaceModel;
}
Expand Down Expand Up @@ -307,17 +347,19 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaComplexType complexType,
}
else particle = complexType.Particle ?? complexType.ContentTypeParticle;

var items = GetElements(particle, complexType);
var properties = CreatePropertiesForElements(source, classModel, particle, items);
classModel.Properties.AddRange(properties);
var items = GetElements(particle, complexType).ToList();

if (_configuration.GenerateInterfaces)
{
var interfaces = items.Select(i => i.XmlParticle).OfType<XmlSchemaGroupRef>()
.Select(i => (InterfaceModel)CreateTypeModel(CodeUtilities.CreateUri(i.SourceUri), Groups[i.RefName], i.RefName));
classModel.Interfaces.AddRange(interfaces);
.Select(i => (InterfaceModel)CreateTypeModel(CodeUtilities.CreateUri(i.SourceUri), Groups[i.RefName], i.RefName)).ToList();

classModel.AddInterfaces(interfaces);
}

var properties = CreatePropertiesForElements(source, classModel, particle, items);
classModel.Properties.AddRange(properties);

XmlSchemaObjectCollection attributes = null;
if (classModel.BaseClass != null)
{
Expand All @@ -344,7 +386,7 @@ private TypeModel CreateTypeModel(Uri source, XmlSchemaComplexType complexType,
{
var attributeInterfaces = attributes.OfType<XmlSchemaAttributeGroupRef>()
.Select(i => (InterfaceModel)CreateTypeModel(CodeUtilities.CreateUri(i.SourceUri), AttributeGroups[i.RefName], i.RefName));
classModel.Interfaces.AddRange(attributeInterfaces);
classModel.AddInterfaces(attributeInterfaces);
}
}

Expand Down Expand Up @@ -597,6 +639,7 @@ private IEnumerable<PropertyModel> CreatePropertiesForElements(Uri source, TypeM
}

var propertyName = _configuration.NamingProvider.ElementNameFromQualifiedName(element.QualifiedName);
var originalPropertyName = propertyName;
if (propertyName == typeModel.Name)
{
propertyName += "Property"; // member names cannot be the same as their enclosing type
Expand All @@ -607,6 +650,7 @@ private IEnumerable<PropertyModel> CreatePropertiesForElements(Uri source, TypeM
OwningType = typeModel,
XmlSchemaName = element.QualifiedName,
Name = propertyName,
OriginalPropertyName = originalPropertyName,
Type = CreateTypeModel(source, element.ElementSchemaType, elementQualifiedName),
IsNillable = element.IsNillable,
IsNullable = item.MinOccurs < 1.0m || (item.XmlParent is XmlSchemaChoice),
Expand Down
67 changes: 58 additions & 9 deletions XmlSchemaClassGenerator/TypeModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
Expand Down Expand Up @@ -193,17 +194,16 @@ public virtual CodeExpression GetDefaultValueFor(string defaultString, bool attr
}
}

public class InterfaceModel : TypeModel
public class InterfaceModel : ReferenceTypeModel
{
public InterfaceModel(GeneratorConfiguration configuration)
: base(configuration)
{
Properties = new List<PropertyModel>();
Interfaces = new List<InterfaceModel>();
DerivedTypes = new List<ReferenceTypeModel>();
}

public List<PropertyModel> Properties { get; set; }
public List<InterfaceModel> Interfaces { get; set; }
public List<ReferenceTypeModel> DerivedTypes { get; set; }

public override CodeTypeDeclaration Generate()
{
Expand All @@ -224,23 +224,48 @@ public override CodeTypeDeclaration Generate()

return interfaceDeclaration;
}

public IEnumerable<ReferenceTypeModel> AllDerivedReferenceTypes()
{
foreach (var interfaceModelDerivedType in DerivedTypes)
{
yield return interfaceModelDerivedType;
switch (interfaceModelDerivedType)
{
case InterfaceModel derivedInterfaceModel:
{
foreach (var referenceTypeModel in derivedInterfaceModel.AllDerivedReferenceTypes())
{
yield return referenceTypeModel;
}

break;
}
case ClassModel derivedClassModel:
{
foreach (var baseClass in derivedClassModel.GetAllDerivedTypes())
{
yield return baseClass;
}

break;
}
}
}
}
}

public class ClassModel : TypeModel
public class ClassModel : ReferenceTypeModel
{
public bool IsAbstract { get; set; }
public bool IsMixed { get; set; }
public bool IsSubstitution { get; set; }
public XmlQualifiedName SubstitutionName { get; set; }
public TypeModel BaseClass { get; set; }
public List<PropertyModel> Properties { get; set; }
public List<InterfaceModel> Interfaces { get; set; }
public List<ClassModel> DerivedTypes { get; set; }
public ClassModel(GeneratorConfiguration configuration)
: base(configuration)
{
Properties = new List<PropertyModel>();
Interfaces = new List<InterfaceModel>();
DerivedTypes = new List<ClassModel>();
}

Expand Down Expand Up @@ -514,11 +539,35 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
}
}

public class ReferenceTypeModel : TypeModel
{
public ReferenceTypeModel(GeneratorConfiguration configuration)
: base(configuration)
{
Properties = new List<PropertyModel>();
Interfaces = new List<InterfaceModel>();
}

public List<PropertyModel> Properties { get; set; }
public List<InterfaceModel> Interfaces { get; }

public void AddInterfaces(IEnumerable<InterfaceModel> interfaces)
{
foreach (var interfaceModel in interfaces)
{
Interfaces.Add(interfaceModel);
interfaceModel.DerivedTypes.Add(this);
}

}
}

[DebuggerDisplay("{Name}")]
public class PropertyModel
{
public TypeModel OwningType { get; set; }
public string Name { get; set; }
public string OriginalPropertyName { get; set; }
public bool IsAttribute { get; set; }
public TypeModel Type { get; set; }
public bool IsNullable { get; set; }
Expand Down

0 comments on commit b219658

Please sign in to comment.