From fdf2f3424b4c7661a3e50a29abe572b748b6f923 Mon Sep 17 00:00:00 2001 From: Holger Kaelberer Date: Tue, 18 Oct 2016 10:57:57 +0200 Subject: [PATCH 1/2] kdwsdl2cpp: Avoid potential type collisions in nested complexTypes So far, for complexTypes nested in elements with the same name a single C++ class has been created. This is wrong in cases where multiple elements with the same name contain complexTypes of different structure because different classes should be created --- kdwsdl2cpp/schema/parser.cpp | 9 +++++++-- unittests/wsdl_document/mywsdl_document.wsdl | 14 ++++++++++++++ .../wsdl_document/test_wsdl_document.cpp | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/kdwsdl2cpp/schema/parser.cpp b/kdwsdl2cpp/schema/parser.cpp index 00dc156d9..6967abc38 100644 --- a/kdwsdl2cpp/schema/parser.cpp +++ b/kdwsdl2cpp/schema/parser.cpp @@ -520,8 +520,13 @@ Element Parser::parseElement(ParserContext *context, //qDebug() << "childName:" << childName.localName(); if (childName.localName() == QLatin1String("complexType")) { ComplexType ct = parseComplexType(context, childElement); - - ct.setName(newElement.name()); + QString name = newElement.name(); + int i = 0; + while (!d->mComplexTypes.complexType(QName(ct.nameSpace(), name)).name().isEmpty()) + name = newElement.name() + QString::number(++i); + if (name != newElement.name() && debugParsing()) + qDebug() << " detected potential type collision in nested complexType, updated name" << newElement.name() << "to" << name; + ct.setName(name); ct.setAnonymous(true); d->mComplexTypes.append(ct); diff --git a/unittests/wsdl_document/mywsdl_document.wsdl b/unittests/wsdl_document/mywsdl_document.wsdl index 9dbda1a08..7cabb1b6c 100644 --- a/unittests/wsdl_document/mywsdl_document.wsdl +++ b/unittests/wsdl_document/mywsdl_document.wsdl @@ -57,6 +57,13 @@ + + + + + + + @@ -137,6 +144,13 @@ + + + + + + + diff --git a/unittests/wsdl_document/test_wsdl_document.cpp b/unittests/wsdl_document/test_wsdl_document.cpp index d0992fc81..6969bfe9a 100644 --- a/unittests/wsdl_document/test_wsdl_document.cpp +++ b/unittests/wsdl_document/test_wsdl_document.cpp @@ -467,6 +467,23 @@ private Q_SLOTS: params.setRepeatedChildren(children); } + // Test repeated names in nested complex types + void testRepeatedNames() + { + // Just test the generated code, two different classes should have been + // created for two structurally different nested complex types of the + // same name: + KDAB__TelegramResponse resp; + class KDAB__RepeatedName repeatedName; + repeatedName.setStringparam1("test1"); + resp.setRepeatedName(repeatedName); + + KDAB__EmployeeNameParams params; + class KDAB__RepeatedName1 repeatedName1; + repeatedName1.setIntparam1(1); + params.setRepeatedName(repeatedName1); + } + void testSoapVersion() { // Prepare response @@ -714,6 +731,7 @@ public slots: "David Ä Faure" "" "000" + "0" "" "" + xmlEnvEnd() + '\n'; // added by QXmlStreamWriter::writeEndDocument @@ -1068,6 +1086,7 @@ void WsdlDocumentTest::testSendTelegram() QByteArray(xmlBegin) + "" "52656365697665642048656c6c6f" "UmVjZWl2ZWQgSGVsbG8=" + "" ""; // m_response, however, has qualified = true (set by the generated code). QVERIFY(xmlBufferCompare(server->lastServerObject()->m_response.toXml(KDSoapValue::LiteralUse, msgNS), expectedResponseXml)); From d4b1958dad0a3d4cdfce3dac58649fe05f22f6ed Mon Sep 17 00:00:00 2001 From: Holger Kaelberer Date: Wed, 26 Oct 2016 08:37:54 +0200 Subject: [PATCH 2/2] kdwsdl2cpp: New types for structurally different complexTypes only --- kdwsdl2cpp/schema/attribute.cpp | 16 ++++++++ kdwsdl2cpp/schema/attribute.h | 6 +++ kdwsdl2cpp/schema/attributegroup.cpp | 11 +++++ kdwsdl2cpp/schema/attributegroup.h | 6 +++ kdwsdl2cpp/schema/complextype.cpp | 21 ++++++++++ kdwsdl2cpp/schema/complextype.h | 6 +++ kdwsdl2cpp/schema/element.cpp | 41 +++++++++++++++++++ kdwsdl2cpp/schema/element.h | 12 ++++++ kdwsdl2cpp/schema/group.cpp | 6 +++ kdwsdl2cpp/schema/parser.cpp | 33 ++++++++++----- kdwsdl2cpp/schema/xsdtype.cpp | 1 + unittests/wsdl_document/mywsdl_document.wsdl | 14 +++++++ .../wsdl_document/test_wsdl_document.cpp | 24 ++++++++--- 13 files changed, 180 insertions(+), 17 deletions(-) diff --git a/kdwsdl2cpp/schema/attribute.cpp b/kdwsdl2cpp/schema/attribute.cpp index cccb18345..2a8000e23 100644 --- a/kdwsdl2cpp/schema/attribute.cpp +++ b/kdwsdl2cpp/schema/attribute.cpp @@ -159,6 +159,22 @@ void Attribute::List::dump() } } +bool operator==(const Attribute& lhs, const Attribute& rhs) +{ + return (// XmlElement: + lhs.isNull() == rhs.isNull() + && lhs.name() == rhs.name() + && lhs.nameSpace() == rhs.nameSpace() + // Attribute: + && lhs.type() == rhs.type() + && lhs.defaultValue() == rhs.defaultValue() + && lhs.fixedValue() == rhs.fixedValue() + && lhs.isQualified() == rhs.isQualified() + && lhs.attributeUse() == rhs.attributeUse() + && lhs.reference() == rhs.reference()); + //Note: Ignoring documentation() +} + } // namespace XSD QDebug operator<<(QDebug dbg, const XSD::Attribute &attr) diff --git a/kdwsdl2cpp/schema/attribute.h b/kdwsdl2cpp/schema/attribute.h index 3c3fc20d4..e1371f849 100644 --- a/kdwsdl2cpp/schema/attribute.h +++ b/kdwsdl2cpp/schema/attribute.h @@ -79,6 +79,12 @@ class SCHEMA_EXPORT Attribute : public XmlElement Private *d; }; +bool operator==(const Attribute& lhs, const Attribute& rhs); +inline bool operator!=(const Attribute& lhs, const Attribute& rhs) +{ + return !(lhs == rhs); +} + } SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::Attribute &attr); diff --git a/kdwsdl2cpp/schema/attributegroup.cpp b/kdwsdl2cpp/schema/attributegroup.cpp index 741d6adf6..3f1c19d6b 100644 --- a/kdwsdl2cpp/schema/attributegroup.cpp +++ b/kdwsdl2cpp/schema/attributegroup.cpp @@ -77,4 +77,15 @@ Attribute::List AttributeGroup::attributes() const return d->mAttributes; } +bool operator==(const AttributeGroup& lhs, const AttributeGroup& rhs) +{ + return (// XmlElement: + lhs.isNull() == rhs.isNull() + && lhs.name() == rhs.name() + && lhs.nameSpace() == rhs.nameSpace() + // AttributeGroup: + && lhs.reference() == rhs.reference() + && lhs.attributes() == rhs.attributes()); +} + } diff --git a/kdwsdl2cpp/schema/attributegroup.h b/kdwsdl2cpp/schema/attributegroup.h index 8535a7df2..fdb80b7af 100644 --- a/kdwsdl2cpp/schema/attributegroup.h +++ b/kdwsdl2cpp/schema/attributegroup.h @@ -51,6 +51,12 @@ class SCHEMA_EXPORT AttributeGroup : public XmlElement Private *d; }; +bool operator==(const AttributeGroup& lhs, const AttributeGroup& rhs); +inline bool operator!=(const AttributeGroup& lhs, const AttributeGroup& rhs) +{ + return !(lhs == rhs); +} + } #endif diff --git a/kdwsdl2cpp/schema/complextype.cpp b/kdwsdl2cpp/schema/complextype.cpp index 03cf095c3..469d94756 100644 --- a/kdwsdl2cpp/schema/complextype.cpp +++ b/kdwsdl2cpp/schema/complextype.cpp @@ -74,6 +74,7 @@ ComplexType::~ComplexType() ComplexType &ComplexType::operator=(const ComplexType &other) { + XSDType::operator=(other); if (this == &other) { return *this; } @@ -265,6 +266,26 @@ ComplexTypeList::iterator ComplexTypeList::findComplexType(const QName &qualifie return end(); } +bool operator==(const ComplexType& lhs, const ComplexType& rhs) +{ + return (// XmlElement: + lhs.isNull() == rhs.isNull() + && lhs.name() == rhs.name() + && lhs.nameSpace() == rhs.nameSpace() + // XsdType: + && lhs.contentModel() == rhs.contentModel() + && lhs.substitutionElementName() == rhs.substitutionElementName() + // ComplexType: + && lhs.baseDerivation() == rhs.baseDerivation() + && lhs.baseTypeName() == rhs.baseTypeName() + && lhs.arrayType() == rhs.arrayType() + && lhs.elements() == rhs.elements() + && lhs.attributes() == rhs.attributes() + && lhs.attributeGroups() == rhs.attributeGroups()); + // Note: Ignoring XmlElement::annotations(), + // ComplexType::documentation(), isAnonymous(), isConflicting(), derivedTypes() +} + } // namespace XSD QDebug operator<<(QDebug dbg, const XSD::ComplexType &type) diff --git a/kdwsdl2cpp/schema/complextype.h b/kdwsdl2cpp/schema/complextype.h index 783e1da87..3ffaf94ad 100644 --- a/kdwsdl2cpp/schema/complextype.h +++ b/kdwsdl2cpp/schema/complextype.h @@ -120,6 +120,12 @@ class SCHEMA_EXPORT ComplexTypeList : public QList iterator findComplexType(const QName &qualifiedName); }; +bool operator==(const ComplexType& lhs, const ComplexType& rhs); +inline bool operator!=(const ComplexType& lhs, const ComplexType& rhs) +{ + return !(lhs == rhs); +} + } // namespace XSD SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::ComplexType &type); diff --git a/kdwsdl2cpp/schema/element.cpp b/kdwsdl2cpp/schema/element.cpp index 6777029db..124db40ee 100644 --- a/kdwsdl2cpp/schema/element.cpp +++ b/kdwsdl2cpp/schema/element.cpp @@ -254,6 +254,47 @@ void ElementList::dump() } } +bool operator==(const Element& lhs, const Element& rhs) +{ + return (// XmlElement: + lhs.isNull() == rhs.isNull() + && lhs.name() == rhs.name() + && lhs.nameSpace() == rhs.nameSpace() + // Element: + && lhs.type() == rhs.type() + && lhs.groupId() == rhs.groupId() + && lhs.minOccurs() == rhs.minOccurs() + && lhs.maxOccurs() == rhs.maxOccurs() + && lhs.defaultValue() == rhs.defaultValue() + && lhs.isQualified() == rhs.isQualified() + && lhs.nillable() == rhs.nillable() + && lhs.occurrence() == rhs.occurrence() + && lhs.reference() == rhs.reference() + && lhs.compositor().type() == rhs.compositor().type() + && lhs.hasSubstitutions() == rhs.hasSubstitutions()); + //Note: Ignoring documentation +} + +bool operator==(const ElementList& lhs, const ElementList& rhs) +{ + if (lhs.count() != rhs.count()) + return false; + + // Ordered vs. unordered composition should be specified for a whole composition, but + // as the Compositor::Type is determined during parsing (per element) + // comparing per element should be semantically identic: + for (int i = 0; i < lhs.count(); i++) { + const Element& e = lhs.at(i); + if (e.compositor().type() == Compositor::Sequence // ordered + && rhs.at(i) != e) + return false; + else if (e.compositor().type() != Compositor::Sequence // unordered + && !rhs.contains(e)) + return false; + } + return true; +} + } // namespace XSD QDebug operator<<(QDebug dbg, const XSD::Element &element) diff --git a/kdwsdl2cpp/schema/element.h b/kdwsdl2cpp/schema/element.h index e0633f517..b330485cc 100644 --- a/kdwsdl2cpp/schema/element.h +++ b/kdwsdl2cpp/schema/element.h @@ -117,6 +117,18 @@ class SCHEMA_EXPORT ElementList : public QList void dump(); }; +bool operator==(const Element& lhs, const Element& rhs); +inline bool operator!=(const Element& lhs, const Element& rhs) +{ + return !(lhs == rhs); +} + +bool operator==(const ElementList& lhs, const ElementList& rhs); +inline bool operator!=(const ElementList& lhs, const ElementList& rhs) +{ + return !(lhs == rhs); +} + } SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::Element &element); diff --git a/kdwsdl2cpp/schema/group.cpp b/kdwsdl2cpp/schema/group.cpp index b0deb513e..14ecf9168 100644 --- a/kdwsdl2cpp/schema/group.cpp +++ b/kdwsdl2cpp/schema/group.cpp @@ -82,6 +82,12 @@ bool Group::isResolved() const return !d->mElements.isEmpty() || d->mReference.isEmpty(); } +bool operator==(const Group& lhs, const Group& rhs) +{ + return (lhs.reference() == rhs.reference() + && lhs.elements() == rhs.elements()); // FIXME: +} + } QDebug operator<<(QDebug dbg, const XSD::Group &group) diff --git a/kdwsdl2cpp/schema/parser.cpp b/kdwsdl2cpp/schema/parser.cpp index 6967abc38..5ea174294 100644 --- a/kdwsdl2cpp/schema/parser.cpp +++ b/kdwsdl2cpp/schema/parser.cpp @@ -520,18 +520,29 @@ Element Parser::parseElement(ParserContext *context, //qDebug() << "childName:" << childName.localName(); if (childName.localName() == QLatin1String("complexType")) { ComplexType ct = parseComplexType(context, childElement); - QString name = newElement.name(); - int i = 0; - while (!d->mComplexTypes.complexType(QName(ct.nameSpace(), name)).name().isEmpty()) - name = newElement.name() + QString::number(++i); - if (name != newElement.name() && debugParsing()) - qDebug() << " detected potential type collision in nested complexType, updated name" << newElement.name() << "to" << name; - ct.setName(name); ct.setAnonymous(true); - d->mComplexTypes.append(ct); - - if (debugParsing()) { - qDebug() << " found nested complexType element, type name is now element name, i.e. " << ct.name() << "newElement.setType" << ct.qualifiedName(); + ct.setName(newElement.name()); + int i = 0; + bool typeExists = false; + ComplexType existingType = d->mComplexTypes.complexType(QName(ct.nameSpace(), ct.name())); + while (existingType != ComplexType()) { + if (existingType == ct) { + if (debugParsing()) + qDebug() << " Nested complexType of name" << ct.name() << "is structurally identical with existing complexType of the same name, skipping this instance..."; + typeExists = true; + break; + } else { + ct.setName(newElement.name() + QString::number(++i)); + existingType = d->mComplexTypes.complexType(QName(ct.nameSpace(), ct.name())); + } + } + if (!typeExists) { + d->mComplexTypes.append(ct); + if (debugParsing()) { + if (newElement.name() != ct.name()) + qDebug() << " Detected type collision for nested complexType, updated name" << newElement.name() << "to" << ct.name(); + qDebug() << " found nested complexType element, type name is now element name, i.e. " << ct.name() << "newElement.setType" << ct.qualifiedName(); + } } newElement.setType(ct.qualifiedName()); } else if (childName.localName() == QLatin1String("simpleType")) { diff --git a/kdwsdl2cpp/schema/xsdtype.cpp b/kdwsdl2cpp/schema/xsdtype.cpp index 27e093e85..544721982 100644 --- a/kdwsdl2cpp/schema/xsdtype.cpp +++ b/kdwsdl2cpp/schema/xsdtype.cpp @@ -60,6 +60,7 @@ XSDType::~XSDType() XSDType &XSDType::operator=(const XSDType &other) { + XmlElement::operator=(other); if (this == &other) { return *this; } diff --git a/unittests/wsdl_document/mywsdl_document.wsdl b/unittests/wsdl_document/mywsdl_document.wsdl index 7cabb1b6c..1d438b163 100644 --- a/unittests/wsdl_document/mywsdl_document.wsdl +++ b/unittests/wsdl_document/mywsdl_document.wsdl @@ -49,6 +49,13 @@ + + + + + + + @@ -159,6 +166,13 @@ + + + + + + + diff --git a/unittests/wsdl_document/test_wsdl_document.cpp b/unittests/wsdl_document/test_wsdl_document.cpp index 6969bfe9a..3c3fb4343 100644 --- a/unittests/wsdl_document/test_wsdl_document.cpp +++ b/unittests/wsdl_document/test_wsdl_document.cpp @@ -473,15 +473,25 @@ private Q_SLOTS: // Just test the generated code, two different classes should have been // created for two structurally different nested complex types of the // same name: + KDAB__TelegramRequest req; + KDAB__RepeatedName repeatedName; + repeatedName.setIntparam1(0); + req.setRepeatedName(repeatedName); + KDAB__TelegramResponse resp; - class KDAB__RepeatedName repeatedName; - repeatedName.setStringparam1("test1"); - resp.setRepeatedName(repeatedName); + KDAB__RepeatedName1 repeatedName1; + repeatedName1.setStringparam1("test1"); + resp.setRepeatedName(repeatedName1); KDAB__EmployeeNameParams params; - class KDAB__RepeatedName1 repeatedName1; - repeatedName1.setIntparam1(1); - params.setRepeatedName(repeatedName1); + class KDAB__RepeatedName repeatedName_sameStructure; + repeatedName_sameStructure.setIntparam1(1); + params.setRepeatedName(repeatedName_sameStructure); + + KDAB__EmployeeCountryResponse resp2; + KDAB__RepeatedName1 repeatedName1_sameStructure; + repeatedName1_sameStructure.setStringparam1("test2"); + resp2.setRepeatedName(repeatedName1_sameStructure); } void testSoapVersion() @@ -1015,6 +1025,7 @@ void WsdlDocumentTest::testServerPostByHand() "" "" "France" + "" "" "\n"; QVERIFY(xmlBufferCompare(response, expected)); @@ -1077,6 +1088,7 @@ void WsdlDocumentTest::testSendTelegram() QByteArray(xmlBegin) + "" "48656c6c6f" "SGVsbG8=" + "0" ""; const QString msgNS = QString::fromLatin1("http://www.kdab.com/xml/MyWsdl/"); // Note that "qualified" is false in m_request, since it was created dynamically by the server -> no namespaces