static bool usePointerForElement(const XSD::Element &elem, const KODE::Class &newClass, const KWSDL::TypeMap &typeMap, bool isList) { const QString typeName = typeMap.localType(elem.type()); const bool polymorphic = isElementPolymorphic(elem, typeMap, isList); if (!isList && isElementOptional(elem) && newClass.name() == typeName) { if (qgetenv("KDSOAP_TYPE_DEBUG").toInt()) { qDebug() << "Making element polymorphic:" << typeName << "in" << newClass.name(); } // Optional "Foo" in class "Foo" - can't just have a value and bool, we need a pointer, to avoid infinite recursion //use == XSD::Attribute::Required; return true; } return polymorphic; }
void Converter::convertSimpleType(const XSD::SimpleType *type, const XSD::SimpleType::List &simpleTypeList) { const QString typeName(mTypeMap.localType(type->qualifiedName())); //qDebug() << "convertSimpleType:" << type->qualifiedName() << typeName; KODE::Class newClass; newClass.setNamespaceAndName(typeName); if (!Settings::self()->exportDeclaration().isEmpty()) { newClass.setExportDeclaration(Settings::self()->exportDeclaration()); } newClass.setNameSpace(Settings::self()->nameSpace()); QString classDocumentation; switch (type->subType()) { case XSD::SimpleType::TypeRestriction: { /** Use setter and getter method for enums as well. */ if (type->facetType() & XSD::SimpleType::ENUM) { classDocumentation = "This class is a wrapper for an enumeration.\n"; NameMapper nameMapper; QStringList enums = type->facetEnums(); for (int i = 0; i < enums.count(); ++i) { enums[ i ] = nameMapper.escape(escapeEnum(enums[ i ])); } newClass.addEnum(KODE::Enum("Type", enums)); classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the enum directly. Example:\n" + "someMethod(" + newClass.name() + "::" + enums.first() + ")."; // member variables KODE::MemberVariable variable("type", "Type"); variable.setInitializer("Type(0)"); newClass.addMemberVariable(variable); // setter method KODE::Function setter("setType", "void"); setter.addArgument("Type type"); setter.setBody(variable.name() + " = type;"); // getter method KODE::Function getter("type", newClass.qualifiedName() + "::Type"); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument("const Type &type"); KODE::Code code; code += variable.name() + " = type;"; conctor.setBody(code); // type operator KODE::Function op("operator Type"); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(conctor); newClass.addFunction(setter); newClass.addFunction(getter); newClass.addFunction(op); } /** A class can't derive from basic types (e.g. int or unsigned char), so we add setter and getter methods to set the value of this class. */ if (type->baseTypeName() != XmlAnyType && !type->baseTypeName().isEmpty() && !(type->facetType() & XSD::SimpleType::ENUM)) { classDocumentation = "This class encapsulates a simple type.\n"; const QName baseName = type->baseTypeName(); const QString baseTypeName = mTypeMap.localType(baseName); Q_ASSERT(!baseTypeName.isEmpty()); QList<QName> parentBasicTypes; parentBasicTypes.append(baseName); QName currentType = baseName; Q_FOREVER { const XSD::SimpleType simpleType = simpleTypeList.simpleType(currentType); if (!simpleType.isNull() && simpleType.isRestriction()) { currentType = simpleType.baseTypeName(); parentBasicTypes.append(currentType); continue; } break; } classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the value directly as a " + mTypeMap.localType(currentType) + '.'; // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName)); newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName)); // member variables KODE::MemberVariable variable("value", baseTypeName); addVariableInitializer(variable); newClass.addMemberVariable(variable); // setter method KODE::Function setter("setValue", "void"); const QString inputType = mTypeMap.localInputType(baseName, QName()); setter.addArgument(inputType + " value"); KODE::Code setterBody; if (type->facetType() != XSD::SimpleType::NONE) { const XSD::SimpleType baseSimpleType = simpleTypeList.simpleType(baseName); setterBody += createRangeCheckCode(type, baseTypeName, "value", newClass, baseSimpleType); setterBody.newLine(); setterBody += "if (!rangeOk)"; setterBody.indent(); setterBody += "qDebug( \"Invalid range in " + newClass.name() + "::" + setter.name() + "()\" );"; setterBody.unindent(); setterBody.newLine(); } setterBody += variable.name() + " = value;"; // ### call setValue in base class? setter.setBody(setterBody); newClass.addFunction(setter); // getter method KODE::Function getter("value", baseTypeName); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); newClass.addFunction(getter); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument(inputType + " value"); conctor.addBodyLine("setValue(value);"); newClass.addFunction(conctor); // even more convenient constructor, for the case of multiple-level simple-type restrictions //qDebug() << typeName << ": baseName=" << baseName << "further up:" << parentBasicTypes; if (parentBasicTypes.count() > 1) { parentBasicTypes.removeLast(); // the top-most one is in "currentType", so it's the input arg. KODE::Function baseCtor(conctor.name()); baseCtor.addArgument(mTypeMap.localInputType(currentType, QName()) + " value"); QString beginLine = "setValue("; QString endLine = ")"; Q_FOREACH (const QName &base, parentBasicTypes) { beginLine += mTypeMap.localType(base) + '('; endLine += ')'; } baseCtor.addBodyLine(beginLine + "value" + endLine + ';'); newClass.addFunction(baseCtor); } // type operator KODE::Function op("operator " + baseTypeName); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(op); }
void Converter::convertComplexType(const XSD::ComplexType *type) { // An empty type is still useful, in document mode: it serializes the element name //if ( type->isEmpty() ) // return; // Skip the Array types we added in Parser::init... if (NSManager::soapEncNamespaces().contains(type->nameSpace())) { return; } const QString className(mTypeMap.localType(type->qualifiedName())); KODE::Class newClass; newClass.setNamespaceAndName(className); if (!Settings::self()->exportDeclaration().isEmpty()) { newClass.setExportDeclaration(Settings::self()->exportDeclaration()); } newClass.setUseSharedData(true, QLatin1String("d_ptr") /*avoid clash with possible d() method */); const bool doDebug = (qgetenv("KDSOAP_TYPE_DEBUG").toInt()); if (doDebug) { qDebug() << "Generating complex type" << className; } // subclass handling if (!type->baseTypeName().isEmpty()) { // this class extends something /** * A class can't subclass basic type (e.g. int, unsigned char), so we * add setValue() and value() methods to access the base type. * * In fact, let's do the same with string */ if (type->baseTypeName().localName() == QLatin1String("Array")) { // this is handled in the attribute section } else { const QName baseName = type->baseTypeName(); const QString typeName = mTypeMap.localType(baseName); const QString inputTypeName = mTypeMap.localInputType(baseName, QName()); // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName)); newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName)); if (mTypeMap.isComplexType(baseName)) { newClass.addBaseClass(typeName); } else { const QString variableName = generateMemberVariable("value", typeName, inputTypeName, newClass, XSD::Attribute::Required, false, false); // convenience constructor KODE::Function conctor(upperlize(newClass.name())); conctor.addArgument(inputTypeName + QLatin1String(" value")); conctor.setBody(variableName + QLatin1String(" = value;")); // type operator KODE::Function op(QLatin1String("operator ") + typeName); op.setBody(QLatin1String("return ") + variableName + QLatin1Char(';')); op.setConst(true); newClass.addFunction(conctor); newClass.addFunction(op); } } } if (!type->documentation().isEmpty()) { newClass.setDocs(type->documentation().simplified()); } QVector<QString> seenElements; // elements in the complex type const XSD::Element::List elements = type->elements(); Q_FOREACH (const XSD::Element &elemIt, elements) { if (elemIt.type().isEmpty()) { qDebug() << "ERROR: Element from" << *type << "with no type:" << elemIt << "(skipping)"; Q_ASSERT(false); continue; } // When having <choice> // <sequence>A,B(opt)</sequence> // B // <sequence>C,B(opt)</sequence> // </choice> // we don't want to emit setB() three times, that's not valid C++ // (testcase in wsdl_document.wsdl TestRepeatedChildren) if (seenElements.contains(elemIt.name())) { continue; } seenElements.append(elemIt.name()); QString typeName = mTypeMap.localType(elemIt.type()); Q_ASSERT(!typeName.isEmpty()); if (typeName != QLatin1String("void")) { // void means empty element, probably just here for later extensions (testcase: SetPasswordResult in salesforce) QString inputTypeName = mTypeMap.localInputType(elemIt.type(), QName()); bool isList = false; if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) { QString itemType = mTypeMap.isPolymorphic(elemIt.type()) ? pointerStorageType(typeName) : typeName; typeName = listTypeFor(itemType, newClass); inputTypeName = QLatin1String("const ") + typeName + QLatin1String("&"); isList = true; } if (type->isArray()) { QString arrayTypeName = mTypeMap.localType(type->arrayType()); Q_ASSERT(!arrayTypeName.isEmpty()); if (mTypeMap.isPolymorphic(type->arrayType())) { arrayTypeName = pointerStorageType(arrayTypeName); } //qDebug() << "array of" << attribute.arrayType() << "->" << arrayTypeName; typeName = listTypeFor(arrayTypeName, newClass); if (!mTypeMap.isBasicType(type->arrayType())) { newClass.addInclude(QString(), arrayTypeName); // add forward declaration } newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList")); inputTypeName = QLatin1String("const ") + typeName + QLatin1Char('&'); isList = true; } XSD::Attribute::AttributeUse use = isElementOptional(elemIt) ? XSD::Attribute::Optional : XSD::Attribute::Required; const bool polymorphic = isElementPolymorphic(elemIt, mTypeMap, isList); const bool usePointer = usePointerForElement(elemIt, newClass, mTypeMap, isList); generateMemberVariable(KODE::Style::makeIdentifier(elemIt.name()), typeName, inputTypeName, newClass, use, usePointer, polymorphic); } // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(elemIt.type())); newClass.addHeaderIncludes(mTypeMap.headerIncludes(elemIt.type())); if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) { newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList")); } } // attributes in the complex type XSD::Attribute::List attributes = type->attributes(); Q_FOREACH (const XSD::Attribute &attribute, attributes) { QString typeName, inputTypeName; typeName = mTypeMap.localType(attribute.type()); if (typeName.isEmpty()) { qDebug() << "ERROR: attribute with unknown type:" << attribute.name() << attribute.type() << "in" << typeName; } inputTypeName = mTypeMap.localInputType(attribute.type(), QName()); //qDebug() << "Attribute" << attribute.name(); generateMemberVariable(KODE::Style::makeIdentifier(attribute.name()), typeName, inputTypeName, newClass, attribute.attributeUse(), false, false); // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(attribute.type())); newClass.addHeaderIncludes(mTypeMap.headerIncludes(attribute.type())); }