diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/typesystemparser.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystemparser.cpp | 595 |
1 files changed, 378 insertions, 217 deletions
diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 5440de5c0..d2648d0b4 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -56,23 +56,28 @@ static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote- static inline QString textAttribute() { return QStringLiteral("text"); } static inline QString nameAttribute() { return QStringLiteral("name"); } static inline QString sinceAttribute() { return QStringLiteral("since"); } +static inline QString untilAttribute() { return QStringLiteral("until"); } static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); } static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); } static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); } static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); } static inline QString extensibleAttribute() { return QStringLiteral("extensible"); } +static inline QString fileNameAttribute() { return QStringLiteral("file-name"); } static inline QString flagsAttribute() { return QStringLiteral("flags"); } static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); } static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); } static inline QString formatAttribute() { return QStringLiteral("format"); } +static inline QString generateUsingAttribute() { return QStringLiteral("generate-using"); } static inline QString classAttribute() { return QStringLiteral("class"); } static inline QString generateAttribute() { return QStringLiteral("generate"); } +static inline QString generateGetSetDefAttribute() { return QStringLiteral("generate-getsetdef"); } static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); } static inline QString indexAttribute() { return QStringLiteral("index"); } static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); } static inline QString locationAttribute() { return QStringLiteral("location"); } static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); } static inline QString modifierAttribute() { return QStringLiteral("modifier"); } +static inline QString overloadNumberAttribute() { return QStringLiteral("overload-number"); } static inline QString ownershipAttribute() { return QStringLiteral("owner"); } static inline QString packageAttribute() { return QStringLiteral("package"); } static inline QString positionAttribute() { return QStringLiteral("position"); } @@ -81,6 +86,7 @@ static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral static inline QString removeAttribute() { return QStringLiteral("remove"); } static inline QString renameAttribute() { return QStringLiteral("rename"); } static inline QString readAttribute() { return QStringLiteral("read"); } +static inline QString targetLangNameAttribute() { return QStringLiteral("target-lang-name"); } static inline QString writeAttribute() { return QStringLiteral("write"); } static inline QString replaceAttribute() { return QStringLiteral("replace"); } static inline QString toAttribute() { return QStringLiteral("to"); } @@ -92,6 +98,7 @@ static inline QString sourceAttribute() { return QStringLiteral("source"); } static inline QString streamAttribute() { return QStringLiteral("stream"); } static inline QString xPathAttribute() { return QStringLiteral("xpath"); } static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); } +static inline QString visibleAttribute() { return QStringLiteral("visible"); } static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); } static inline QString noAttributeValue() { return QStringLiteral("no"); } @@ -145,7 +152,7 @@ static QString extractSnippet(const QString &code, const QString &snippetLabel) } else if (useLine) result += line.toString() + QLatin1Char('\n'); } - return result; + return CodeSnipAbstract::fixSpaces(result); } template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive> @@ -203,13 +210,8 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, languageFromAttribute, TypeSystem::NoLanguage) { {u"all", TypeSystem::All}, // sorted! - {u"constructors", TypeSystem::Constructors}, - {u"destructor-function", TypeSystem::DestructorFunction}, - {u"interface", TypeSystem::Interface}, - {u"library-initializer", TypeSystem::PackageInitializer}, {u"native", TypeSystem::NativeCode}, // em algum lugar do cpp {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe - {u"shell-declaration", TypeSystem::ShellDeclaration}, {u"target", TypeSystem::TargetLangCode} // em algum lugar do cpp }; ENUM_LOOKUP_BINARY_SEARCH() @@ -268,10 +270,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive, { {u"beginning", TypeSystem::CodeSnipPositionBeginning}, {u"end", TypeSystem::CodeSnipPositionEnd}, - {u"declaration", TypeSystem::CodeSnipPositionDeclaration}, - {u"prototype-initialization", TypeSystem::CodeSnipPositionPrototypeInitialization}, - {u"constructor-initialization", TypeSystem::CodeSnipPositionConstructorInitialization}, - {u"constructor", TypeSystem::CodeSnipPositionConstructor} + {u"declaration", TypeSystem::CodeSnipPositionDeclaration} }; ENUM_LOOKUP_LINEAR_SEARCH() @@ -293,7 +292,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, }; ENUM_LOOKUP_LINEAR_SEARCH() -ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive, +ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive, containerTypeFromAttribute, ContainerTypeEntry::NoContainer) { {u"list", ContainerTypeEntry::ListContainer}, @@ -368,6 +367,7 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, {u"object-type", StackElement::ObjectTypeEntry}, {u"parent", StackElement::ParentOwner}, {u"primitive-type", StackElement::PrimitiveTypeEntry}, + {u"property", StackElement::Property}, {u"reference-count", StackElement::ReferenceCount}, {u"reject-enum-value", StackElement::RejectEnumValue}, {u"rejection", StackElement::Rejection}, @@ -380,6 +380,7 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, {u"replace-type", StackElement::ReplaceType}, {u"smart-pointer-type", StackElement::SmartPointerTypeEntry}, {u"suppress-warning", StackElement::SuppressedWarning}, + {u"system-include", StackElement::SystemInclude}, {u"target-to-native", StackElement::TargetToNative}, {u"template", StackElement::Template}, {u"typedef-type", StackElement::TypedefTypeEntry}, @@ -388,6 +389,17 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, }; ENUM_LOOKUP_BINARY_SEARCH() +ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, + visibilityFromAttribute, TypeSystem::Visibility::Unspecified) +{ + {u"no", TypeSystem::Visibility::Invisible}, + {u"false", TypeSystem::Visibility::Invisible}, + {u"auto", TypeSystem::Visibility::Auto}, + {u"yes", TypeSystem::Visibility::Visible}, + {u"true", TypeSystem::Visibility::Visible}, +}; +ENUM_LOOKUP_LINEAR_SEARCH() + static int indexOfAttribute(const QXmlStreamAttributes &atts, QStringView name) { @@ -493,7 +505,7 @@ QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name) TypeSystemParser::TypeSystemParser(TypeDatabase *database, bool generate) : m_database(database), - m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) + m_generate(generate ? TypeEntry::GenerateCode : TypeEntry::GenerateForSubclass) { } @@ -511,14 +523,14 @@ static QString msgReaderMessage(const QXmlStreamReader &reader, { QString message; QTextStream str(&message); - str << type << ": "; const QString fileName = readerFileName(reader); if (fileName.isEmpty()) str << "<stdin>:"; else str << QDir::toNativeSeparators(fileName) << ':'; + // Use a tab separator like SourceLocation for suppression detection str << reader.lineNumber() << ':' << reader.columnNumber() - << ": " << what; + << ":\t" << type << ": " << what; return message; } @@ -573,17 +585,6 @@ static inline attribute.value()); } -static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString()) -{ - QString result; - QTextStream str(&result); - str << "Invalid version \"" << version << '"'; - if (!package.isEmpty()) - str << "\" specified for package " << package; - str << '.'; - return result; -} - static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes, QString *errorMessage) { @@ -634,9 +635,21 @@ bool TypeSystemParser::parse(QXmlStreamReader &reader) { m_error.clear(); m_currentPath.clear(); + m_currentFile.clear(); + m_smartPointerInstantiations.clear(); + const bool result = parseXml(reader) && setupSmartPointerInstantiations(); + m_smartPointerInstantiations.clear(); + return result; +} + +bool TypeSystemParser::parseXml(QXmlStreamReader &reader) +{ const QString fileName = readerFileName(reader); - if (!fileName.isEmpty()) - m_currentPath = QFileInfo(fileName).absolutePath(); + if (!fileName.isEmpty()) { + QFileInfo fi(fileName); + m_currentPath = fi.absolutePath(); + m_currentFile = fi.absoluteFilePath(); + } m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath)); reader.setEntityResolver(m_entityResolver.data()); @@ -677,6 +690,62 @@ bool TypeSystemParser::parse(QXmlStreamReader &reader) return true; } +// Split a type list potentially with template types +// "A<B,C>,D" -> ("A<B,C>", "D") +static QStringList splitTypeList(const QString &s) +{ + QStringList result; + int templateDepth = 0; + int lastPos = 0; + const int size = s.size(); + for (int i = 0; i < size; ++i) { + switch (s.at(i).toLatin1()) { + case '<': + ++templateDepth; + break; + case '>': + --templateDepth; + break; + case ',': + if (templateDepth == 0) { + result.append(s.mid(lastPos, i - lastPos).trimmed()); + lastPos = i + 1; + } + break; + } + } + if (lastPos < size) + result.append(s.mid(lastPos, size - lastPos).trimmed()); + return result; +} + +bool TypeSystemParser::setupSmartPointerInstantiations() +{ + for (auto it = m_smartPointerInstantiations.cbegin(), + end = m_smartPointerInstantiations.cend(); it != end; ++it) { + auto smartPointerEntry = it.key(); + const auto instantiationNames = splitTypeList(it.value()); + SmartPointerTypeEntry::Instantiations instantiations; + instantiations.reserve(instantiationNames.size()); + for (const auto &instantiationName : instantiationNames) { + const auto types = m_database->findCppTypes(instantiationName); + if (types.isEmpty()) { + m_error = + msgCannotFindTypeEntryForSmartPointer(instantiationName, + smartPointerEntry->name()); + return false; + } + if (types.size() > 1) { + m_error = msgAmbiguousTypesFound(instantiationName, types); + return false; + } + instantiations.append(types.constFirst()); + } + smartPointerEntry->setInstantiations(instantiations); + } + return true; +} + bool TypeSystemParser::endElement(const QStringRef &localName) { if (m_ignoreDepth) { @@ -704,7 +773,7 @@ bool TypeSystemParser::endElement(const QStringRef &localName) switch (m_current->type) { case StackElement::Root: - if (m_generate == TypeEntry::GenerateAll) { + if (m_generate == TypeEntry::GenerateCode) { TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions); TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods); for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) { @@ -719,18 +788,26 @@ bool TypeSystemParser::endElement(const QStringRef &localName) case StackElement::InterfaceTypeEntry: case StackElement::NamespaceTypeEntry: { auto *centry = static_cast<ComplexTypeEntry *>(m_current->entry); - centry->setAddedFunctions(m_contextStack.top()->addedFunctions); - centry->setFunctionModifications(m_contextStack.top()->functionMods); - centry->setFieldModifications(m_contextStack.top()->fieldMods); - centry->setCodeSnips(m_contextStack.top()->codeSnips); - centry->setDocModification(m_contextStack.top()->docModifications); - - if (centry->designatedInterface()) { - centry->designatedInterface()->setCodeSnips(m_contextStack.top()->codeSnips); - centry->designatedInterface()->setFunctionModifications(m_contextStack.top()->functionMods); - } + auto top = m_contextStack.top(); + centry->setAddedFunctions(top->addedFunctions); + centry->setFunctionModifications(top->functionMods); + centry->setFieldModifications(top->fieldMods); + centry->setCodeSnips(top->codeSnips); + centry->setDocModification(top->docModifications); } break; + + case StackElement::TypedefTypeEntry: { + auto *centry = static_cast<TypedefEntry *>(m_current->entry)->target(); + auto top = m_contextStack.top(); + centry->setAddedFunctions(centry->addedFunctions() + top->addedFunctions); + centry->setFunctionModifications(centry->functionModifications() + top->functionMods); + centry->setFieldModifications(centry->fieldModifications() + top->fieldMods); + centry->setCodeSnips(centry->codeSnips() + top->codeSnips); + centry->setDocModification(centry->docModifications() + top->docModifications); + } + break; + case StackElement::AddFunction: { // Leaving add-function: Assign all modifications to the added function StackElementContext *top = m_contextStack.top(); @@ -811,7 +888,7 @@ bool TypeSystemParser::endElement(const QStringRef &localName) break; default: break; // nada - }; + } break; default: break; @@ -887,7 +964,7 @@ bool TypeSystemParser::characters(const String &ch) break; default: Q_ASSERT(false); - }; + } return true; } } @@ -958,7 +1035,6 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue) { -#ifdef QTBUG_69389_FIXED if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0 || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) { return true; @@ -967,16 +1043,6 @@ static bool convertBoolean(QStringView value, const QString &attributeName, bool || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) { return false; } -#else - if (QtPrivate::compareStrings(value, trueAttributeValue(), Qt::CaseInsensitive) == 0 - || QtPrivate::compareStrings(value, yesAttributeValue(), Qt::CaseInsensitive) == 0) { - return true; - } - if (QtPrivate::compareStrings(value, falseAttributeValue(), Qt::CaseInsensitive) == 0 - || QtPrivate::compareStrings(value, noAttributeValue(), Qt::CaseInsensitive) == 0) { - return false; - } -#endif const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") .arg(value) .arg(attributeName, @@ -1010,19 +1076,23 @@ static bool convertRemovalAttribute(QStringView remove, Modification& mod, QStri return false; } -static void getNamePrefixRecursive(StackElement* element, QStringList& names) -{ - if (!element->parent || !element->parent->entry) - return; - getNamePrefixRecursive(element->parent, names); - names << element->parent->entry->name(); -} - -static QString getNamePrefix(StackElement* element) +// Check whether an entry should be dropped, allowing for dropping the module +// name (match 'Class' and 'Module.Class'). +static bool shouldDropTypeEntry(const TypeDatabase *db, + const StackElement *element, + QString name) { - QStringList names; - getNamePrefixRecursive(element, names); - return names.join(QLatin1Char('.')); + for (auto e = element->parent; e ; e = e->parent) { + if (e->entry) { + if (e->entry->type() == TypeEntry::TypeSystemType) { + if (db->shouldDropTypeEntry(name)) // Unqualified + return true; + } + name.prepend(QLatin1Char('.')); + name.prepend(e->entry->name()); + } + } + return db->shouldDropTypeEntry(name); } // Returns empty string if there's no error. @@ -1040,8 +1110,24 @@ static QString checkSignatureError(const QString& signature, const QString& tag) return QString(); } -void TypeSystemParser::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const +inline const TypeEntry *TypeSystemParser::currentParentTypeEntry() const +{ + return m_current ? m_current->entry : nullptr; +} + +bool TypeSystemParser::checkRootElement() { + const bool ok = currentParentTypeEntry() != nullptr; + if (!ok) + m_error = msgNoRootTypeSystemEntry(); + return ok; +} + +void TypeSystemParser::applyCommonAttributes(const QXmlStreamReader &reader, TypeEntry *type, + QXmlStreamAttributes *attributes) const +{ + type->setSourceLocation(SourceLocation(m_currentFile, + reader.lineNumber())); type->setCodeGeneration(m_generate); const int revisionIndex = indexOfAttribute(*attributes, u"revision"); @@ -1050,31 +1136,36 @@ void TypeSystemParser::applyCommonAttributes(TypeEntry *type, QXmlStreamAttribut } FlagsTypeEntry * - TypeSystemParser::parseFlagsEntry(const QXmlStreamReader &, - EnumTypeEntry *enumEntry, - const QString &name, QString flagName, + TypeSystemParser::parseFlagsEntry(const QXmlStreamReader &reader, + EnumTypeEntry *enumEntry, QString flagName, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since); + if (!checkRootElement()) + return nullptr; + auto ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + enumEntry->name() + QLatin1Char('>'), + since, + currentParentTypeEntry()->typeSystemTypeEntry()); ftype->setOriginator(enumEntry); ftype->setTargetLangPackage(enumEntry->targetLangPackage()); - // Try to get the guess the qualified flag name - const int lastSepPos = name.lastIndexOf(colonColon()); - if (lastSepPos >= 0 && !flagName.contains(colonColon())) - flagName.prepend(name.left(lastSepPos + 2)); + // Try toenumEntry get the guess the qualified flag name + if (!flagName.contains(colonColon())) { + auto eq = enumEntry->qualifier(); + if (!eq.isEmpty()) + flagName.prepend(eq + colonColon()); + } ftype->setOriginalName(flagName); - applyCommonAttributes(ftype, attributes); - QString n = ftype->originalName(); + applyCommonAttributes(reader, ftype, attributes); - QStringList lst = n.split(colonColon()); + QStringList lst = flagName.split(colonColon()); + const QString targetLangFlagName = QStringList(lst.mid(0, lst.size() - 1)).join(QLatin1Char('.')); const QString &targetLangQualifier = enumEntry->targetLangQualifier(); - if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) { + if (targetLangFlagName != targetLangQualifier) { qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum %1 and flags %2 differ in qualifiers") - .arg(targetLangQualifier, lst.constFirst()); + << QStringLiteral("enum %1 and flags %2 (%3) differ in qualifiers") + .arg(targetLangQualifier, lst.constFirst(), targetLangFlagName); } ftype->setFlagsName(lst.constLast()); @@ -1092,13 +1183,16 @@ FlagsTypeEntry * } SmartPointerTypeEntry * - TypeSystemParser::parseSmartPointerEntry(const QXmlStreamReader &, + TypeSystemParser::parseSmartPointerEntry(const QXmlStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; QString smartPointerType; QString getter; QString refCountMethodName; + QString instantiations; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); if (name == QLatin1String("type")) { @@ -1107,6 +1201,8 @@ SmartPointerTypeEntry * getter = attributes->takeAt(i).value().toString(); } else if (name == QLatin1String("ref-count-method")) { refCountMethodName = attributes->takeAt(i).value().toString(); + } else if (name == QLatin1String("instantiations")) { + instantiations = attributes->takeAt(i).value().toString(); } } @@ -1138,8 +1234,10 @@ SmartPointerTypeEntry * return nullptr; } - auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since); - applyCommonAttributes(type, attributes); + auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, + refCountMethodName, since, currentParentTypeEntry()); + applyCommonAttributes(reader, type, attributes); + m_smartPointerInstantiations.insert(type, instantiations); return type; } @@ -1148,12 +1246,14 @@ PrimitiveTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - auto *type = new PrimitiveTypeEntry(name, since); - applyCommonAttributes(type, attributes); + if (!checkRootElement()) + return nullptr; + auto *type = new PrimitiveTypeEntry(name, since, currentParentTypeEntry()); + applyCommonAttributes(reader, type, attributes); for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("target-lang-name")) { - type->setTargetLangName(attributes->takeAt(i).value().toString()); + if (name == targetLangNameAttribute()) { + type->setTargetLangName(attributes->takeAt(i).value().toString()); } else if (name == QLatin1String("target-lang-api-name")) { type->setTargetLangApiName(attributes->takeAt(i).value().toString()); } else if (name == preferredConversionAttribute()) { @@ -1168,8 +1268,6 @@ PrimitiveTypeEntry * } } - if (type->targetLangName().isEmpty()) - type->setTargetLangName(type->name()); if (type->targetLangApiName().isEmpty()) type->setTargetLangApiName(type->name()); type->setTargetLangPackage(m_defaultPackage); @@ -1177,40 +1275,37 @@ PrimitiveTypeEntry * } ContainerTypeEntry * - TypeSystemParser::parseContainerTypeEntry(const QXmlStreamReader &, + TypeSystemParser::parseContainerTypeEntry(const QXmlStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; const int typeIndex = indexOfAttribute(*attributes, u"type"); if (typeIndex == -1) { m_error = QLatin1String("no 'type' attribute specified"); return nullptr; } const QStringRef typeName = attributes->takeAt(typeIndex).value(); - ContainerTypeEntry::Type containerType = containerTypeFromAttribute(typeName); + ContainerTypeEntry::ContainerKind containerType = containerTypeFromAttribute(typeName); if (containerType == ContainerTypeEntry::NoContainer) { m_error = QLatin1String("there is no container of type ") + typeName.toString(); return nullptr; } - auto *type = new ContainerTypeEntry(name, containerType, since); - applyCommonAttributes(type, attributes); + auto *type = new ContainerTypeEntry(name, containerType, since, currentParentTypeEntry()); + applyCommonAttributes(reader, type, attributes); return type; } EnumTypeEntry * TypeSystemParser::parseEnumTypeEntry(const QXmlStreamReader &reader, - const QString &fullName, const QVersionNumber &since, + const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - QString scope; - QString name = fullName; - const int sep = fullName.lastIndexOf(colonColon()); - if (sep != -1) { - scope = fullName.left(sep); - name = fullName.right(fullName.size() - sep - 2); - } - auto *entry = new EnumTypeEntry(scope, name, since); - applyCommonAttributes(entry, attributes); + if (!checkRootElement()) + return nullptr; + auto *entry = new EnumTypeEntry(name, since, currentParentTypeEntry()); + applyCommonAttributes(reader, entry, attributes); entry->setTargetLangPackage(m_defaultPackage); QString flagNames; @@ -1237,51 +1332,22 @@ EnumTypeEntry * if (!flagNames.isEmpty()) { const QStringList &flagNameList = flagNames.split(QLatin1Char(',')); for (const QString &flagName : flagNameList) - parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes); + parseFlagsEntry(reader, entry, flagName.trimmed(), since, attributes); } return entry; } -ObjectTypeEntry * - TypeSystemParser::parseInterfaceTypeEntry(const QXmlStreamReader &, - const QString &name, const QVersionNumber &since, - QXmlStreamAttributes *attributes) -{ - auto *otype = new ObjectTypeEntry(name, since); - applyCommonAttributes(otype, attributes); - QString targetLangName = name; - bool generate = true; - for (int i = attributes->size() - 1; i >= 0; --i) { - const QStringRef name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("target-lang-name")) { - targetLangName = attributes->takeAt(i).value().toString(); - } else if (name == generateAttribute()) { - generate = convertBoolean(attributes->takeAt(i).value(), - generateAttribute(), true); - } - } - - InterfaceTypeEntry *itype = - new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since); - - if (generate) - itype->setCodeGeneration(m_generate); - else - itype->setCodeGeneration(TypeEntry::GenerateForSubclass); - - otype->setDesignatedInterface(itype); - itype->setOrigin(otype); - return otype; -} NamespaceTypeEntry * TypeSystemParser::parseNamespaceTypeEntry(const QXmlStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since)); - applyCommonAttributes(result.data(), attributes); - applyComplexTypeAttributes(reader, result.data(), attributes); + if (!checkRootElement()) + return nullptr; + QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since, currentParentTypeEntry())); + auto visibility = TypeSystem::Visibility::Unspecified; + applyCommonAttributes(reader, result.data(), attributes); for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef attributeName = attributes->at(i).qualifiedName(); if (attributeName == QLatin1String("files")) { @@ -1304,9 +1370,26 @@ NamespaceTypeEntry * return nullptr; } result->setExtends(*extendsIt); + } else if (attributeName == visibleAttribute()) { + const auto attribute = attributes->takeAt(i); + visibility = visibilityFromAttribute(attribute.value()); + if (visibility == TypeSystem::Visibility::Unspecified) { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } else if (attributeName == generateAttribute()) { + if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true)) + visibility = TypeSystem::Visibility::Invisible; + } else if (attributeName == generateUsingAttribute()) { + result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(), generateUsingAttribute(), true)); } } + if (visibility != TypeSystem::Visibility::Unspecified) + result->setVisibility(visibility); + // Handle legacy "generate" before the common handling + applyComplexTypeAttributes(reader, result.data(), attributes); + if (result->extends() && !result->hasPattern()) { m_error = msgExtendingNamespaceRequiresPattern(name); return nullptr; @@ -1316,12 +1399,14 @@ NamespaceTypeEntry * } ValueTypeEntry * - TypeSystemParser::parseValueTypeEntry(const QXmlStreamReader &, + TypeSystemParser::parseValueTypeEntry(const QXmlStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - auto *typeEntry = new ValueTypeEntry(name, since); - applyCommonAttributes(typeEntry, attributes); + if (!checkRootElement()) + return nullptr; + auto *typeEntry = new ValueTypeEntry(name, since, currentParentTypeEntry()); + applyCommonAttributes(reader, typeEntry, attributes); const int defaultCtIndex = indexOfAttribute(*attributes, u"default-constructor"); if (defaultCtIndex != -1) @@ -1330,10 +1415,12 @@ ValueTypeEntry * } FunctionTypeEntry * - TypeSystemParser::parseFunctionTypeEntry(const QXmlStreamReader &, + TypeSystemParser::parseFunctionTypeEntry(const QXmlStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute()); if (signatureIndex == -1) { m_error = msgMissingAttribute(signatureAttribute()); @@ -1345,8 +1432,8 @@ FunctionTypeEntry * TypeEntry *existingType = m_database->findType(name); if (!existingType) { - auto *result = new FunctionTypeEntry(name, signature, since); - applyCommonAttributes(result, attributes); + auto *result = new FunctionTypeEntry(name, signature, since, currentParentTypeEntry()); + applyCommonAttributes(reader, result, attributes); return result; } @@ -1362,10 +1449,13 @@ FunctionTypeEntry * } TypedefEntry * - TypeSystemParser::parseTypedefEntry(const QXmlStreamReader &, const QString &name, - const QVersionNumber &since, - QXmlStreamAttributes *attributes) + TypeSystemParser::parseTypedefEntry(const QXmlStreamReader &reader, + const QString &name, + const QVersionNumber &since, + QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; if (m_current && m_current->type != StackElement::Root && m_current->type != StackElement::NamespaceTypeEntry) { m_error = QLatin1String("typedef entries must be nested in namespaces or type system."); @@ -1377,8 +1467,8 @@ TypedefEntry * return nullptr; } const QString sourceType = attributes->takeAt(sourceIndex).value().toString(); - auto result = new TypedefEntry(name, sourceType, since); - applyCommonAttributes(result, attributes); + auto result = new TypedefEntry(name, sourceType, since, currentParentTypeEntry()); + applyCommonAttributes(reader, result, attributes); return result; } @@ -1407,7 +1497,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader qPrintable(msgUnimplementedAttributeWarning(reader, name))); const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false); ctype->setGenericClass(v); - } else if (name == QLatin1String("target-lang-name")) { + } else if (name == targetLangNameAttribute()) { ctype->setTargetLangName(attributes->takeAt(i).value().toString()); } else if (name == QLatin1String("polymorphic-base")) { ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); @@ -1462,13 +1552,10 @@ void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader if (ctype->type() != TypeEntry::ContainerType) ctype->setTargetLangPackage(package); - if (InterfaceTypeEntry *di = ctype->designatedInterface()) - di->setTargetLangPackage(package); - if (generate) ctype->setCodeGeneration(m_generate); else - ctype->setCodeGeneration(TypeEntry::GenerateForSubclass); + ctype->setCodeGeneration(TypeEntry::GenerationDisabled); } bool TypeSystemParser::parseRenameFunction(const QXmlStreamReader &, @@ -1618,8 +1705,10 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const QXmlStreamReader & auto *moduleEntry = const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage)); const bool add = moduleEntry == nullptr; - if (add) - moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since); + if (add) { + moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since, + currentParentTypeEntry()); + } moduleEntry->setCodeGeneration(m_generate); if ((m_generate == TypeEntry::GenerateForSubclass || @@ -1649,7 +1738,7 @@ bool TypeSystemParser::loadTypesystem(const QXmlStreamReader &, } const bool result = m_database->parseFile(typeSystemName, m_currentPath, generateChild - && m_generate == TypeEntry::GenerateAll); + && m_generate == TypeEntry::GenerateCode); if (!result) m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName); return result; @@ -2078,6 +2167,18 @@ bool TypeSystemParser::parseModifyField(const QXmlStreamReader &reader, return true; } +static bool parseOverloadNumber(const QXmlStreamAttribute &attribute, int *overloadNumber, + QString *errorMessage) +{ + bool ok; + *overloadNumber = attribute.value().toInt(&ok); + if (!ok || *overloadNumber < 0) { + *errorMessage = msgInvalidAttributeValue(attribute); + return false; + } + return true; +} + bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &, const StackElement &topElement, QXmlStreamAttributes *attributes) @@ -2091,6 +2192,7 @@ bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &, QString returnType = QLatin1String("void"); bool staticFunction = false; QString access; + int overloadNumber = TypeSystem::OverloadNumberUnset; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); if (name == QLatin1String("signature")) { @@ -2102,6 +2204,9 @@ bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &, staticAttribute(), false); } else if (name == accessAttribute()) { access = attributes->takeAt(i).value().toString(); + } else if (name == overloadNumberAttribute()) { + if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) + return false; } } @@ -2137,6 +2242,7 @@ bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &, m_contextStack.top()->functionMods.size(); FunctionModification mod; + mod.setOverloadNumber(overloadNumber); if (!mod.setSignature(m_currentSignature, &m_error)) return false; mod.setOriginalSignature(originalSignature); @@ -2144,6 +2250,40 @@ bool TypeSystemParser::parseAddFunction(const QXmlStreamReader &, return true; } +bool TypeSystemParser::parseProperty(const QXmlStreamReader &, const StackElement &topElement, + QXmlStreamAttributes *attributes) +{ + if ((topElement.type & StackElement::ComplexTypeEntryMask) == 0) { + m_error = QString::fromLatin1("Add property requires a complex type as parent" + ", was=%1").arg(topElement.type, 0, 16); + return false; + } + + TypeSystemProperty property; + for (int i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == nameAttribute()) { + property.name = attributes->takeAt(i).value().toString(); + } else if (name == QLatin1String("get")) { + property.read = attributes->takeAt(i).value().toString(); + } else if (name == QLatin1String("type")) { + property.type = attributes->takeAt(i).value().toString(); + } else if (name == QLatin1String("set")) { + property.write = attributes->takeAt(i).value().toString(); + } else if (name == generateGetSetDefAttribute()) { + property.generateGetSetDef = + convertBoolean(attributes->takeAt(i).value(), + generateGetSetDefAttribute(), false); + } + } + if (!property.isValid()) { + m_error = QLatin1String("<property> element is missing required attibutes (name/type/get)."); + return false; + } + static_cast<ComplexTypeEntry *>(topElement.entry)->addProperty(property); + return true; +} + bool TypeSystemParser::parseModifyFunction(const QXmlStreamReader &reader, const StackElement &topElement, QXmlStreamAttributes *attributes) @@ -2161,6 +2301,7 @@ bool TypeSystemParser::parseModifyFunction(const QXmlStreamReader &reader, QString association; bool deprecated = false; bool isThread = false; + int overloadNumber = TypeSystem::OverloadNumberUnset; TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified; for (int i = attributes->size() - 1; i >= 0; --i) { @@ -2197,6 +2338,9 @@ bool TypeSystemParser::parseModifyFunction(const QXmlStreamReader &reader, qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } + } else if (name == overloadNumberAttribute()) { + if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) + return false; } else if (name == virtualSlotAttribute()) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); @@ -2220,6 +2364,7 @@ bool TypeSystemParser::parseModifyFunction(const QXmlStreamReader &reader, return false; mod.setOriginalSignature(originalSignature); mod.setExceptionHandling(exceptionHandling); + mod.setOverloadNumber(overloadNumber); m_currentSignature = signature; if (!access.isEmpty()) { @@ -2398,7 +2543,7 @@ bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSni "// START of custom code block [file: " << source << "]\n" << extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel) - << "\n// END of custom code block [file: " << source + << "// END of custom code block [file: " << source << "]\n// ========================================================================\n"; snip->addCode(content); return true; @@ -2443,19 +2588,8 @@ bool TypeSystemParser::parseInjectCode(const QXmlStreamReader &, snip.position = position; snip.language = lang; - if (snip.language == TypeSystem::Interface - && topElement.type != StackElement::InterfaceTypeEntry) { - m_error = QLatin1String("Interface code injections must be direct child of an interface type entry"); - return false; - } - if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) { - if (snip.language == TypeSystem::ShellDeclaration) { - m_error = QLatin1String("no function implementation in shell declaration in which to inject code"); - return false; - } - FunctionModification &mod = m_contextStack.top()->functionMods.last(); mod.snips << snip; if (!snip.code().isEmpty()) @@ -2477,7 +2611,7 @@ bool TypeSystemParser::parseInclude(const QXmlStreamReader &, QString location; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("file-name")) + if (name == fileNameAttribute()) fileName = attributes->takeAt(i).value().toString(); else if (name == locationAttribute()) location = attributes->takeAt(i).value().toString(); @@ -2498,10 +2632,18 @@ bool TypeSystemParser::parseInclude(const QXmlStreamReader &, m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes"); return false; } - if (InterfaceTypeEntry *di = entry->designatedInterface()) { - di->setInclude(entry->include()); - di->setExtraIncludes(entry->extraIncludes()); + return true; +} + +bool TypeSystemParser::parseSystemInclude(const QXmlStreamReader &, + QXmlStreamAttributes *attributes) +{ + const int index = indexOfAttribute(*attributes, fileNameAttribute()); + if (index == -1) { + m_error = msgMissingAttribute(fileNameAttribute()); + return false; } + TypeDatabase::instance()->addSystemInclude(attributes->takeAt(index).value().toString()); return true; } @@ -2550,6 +2692,17 @@ bool TypeSystemParser::parseReplace(const QXmlStreamReader &, return true; } +static bool parseVersion(const QString &versionSpec, const QString &package, + QVersionNumber *result, QString *errorMessage) +{ + *result = QVersionNumber::fromString(versionSpec); + if (result->isNull()) { + *errorMessage = msgInvalidVersion(versionSpec, package); + return false; + } + return true; +} + bool TypeSystemParser::startElement(const QXmlStreamReader &reader) { if (m_ignoreDepth) { @@ -2560,20 +2713,25 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) const QStringRef tagName = reader.name(); QXmlStreamAttributes attributes = reader.attributes(); - QVersionNumber since(0, 0); - int index = indexOfAttribute(attributes, sinceAttribute()); - if (index != -1) { - const QStringRef sinceSpec = attributes.takeAt(index).value(); - since = QVersionNumber::fromString(sinceSpec.toString()); - if (since.isNull()) { - m_error = msgInvalidVersion(sinceSpec, m_defaultPackage); - return false; + VersionRange versionRange; + for (int i = attributes.size() - 1; i >= 0; --i) { + const QStringRef name = attributes.at(i).qualifiedName(); + if (name == sinceAttribute()) { + if (!parseVersion(attributes.takeAt(i).value().toString(), + m_defaultPackage, &versionRange.since, &m_error)) { + return false; + } + } else if (name == untilAttribute()) { + if (!parseVersion(attributes.takeAt(i).value().toString(), + m_defaultPackage, &versionRange.until, &m_error)) { + return false; + } } } - if (!m_defaultPackage.isEmpty() && since > QVersionNumber(0, 0)) { + if (!m_defaultPackage.isEmpty() && !versionRange.isNull()) { TypeDatabase* td = TypeDatabase::instance(); - if (!td->checkApiVersion(m_defaultPackage, since)) { + if (!td->checkApiVersion(m_defaultPackage, versionRange)) { ++m_ignoreDepth; return true; } @@ -2596,7 +2754,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) auto *element = new StackElement(m_current); element->type = elementType; - if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll) + if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateCode) customConversionsForReview.clear(); if (element->type == StackElement::CustomMetaConstructor @@ -2630,18 +2788,22 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) return false; } } + // Allow for primitive and/or std:: types only, else require proper nesting. + if (element->type != StackElement::PrimitiveTypeEntry && name.contains(QLatin1Char(':')) + && !name.contains(QLatin1String("std::"))) { + m_error = msgIncorrectlyNestedName(name); + return false; + } if (m_database->hasDroppedTypeEntries()) { - QString identifier = getNamePrefix(element) + QLatin1Char('.'); - identifier += element->type == StackElement::FunctionTypeEntry - ? attributes.value(signatureAttribute()).toString() - : name; - if (m_database->shouldDropTypeEntry(identifier)) { + const QString identifier = element->type == StackElement::FunctionTypeEntry + ? attributes.value(signatureAttribute()).toString() : name; + if (shouldDropTypeEntry(m_database, element, identifier)) { m_currentDroppedEntry = element; m_currentDroppedEntryDepth = 1; if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { - qCDebug(lcShiboken) - << QStringLiteral("Type system entry '%1' was intentionally dropped from generation.").arg(identifier); + qCInfo(lcShiboken, "Type system entry '%s' was intentionally dropped from generation.", + qPrintable(identifier)); } return true; } @@ -2677,13 +2839,6 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) } } - // Fix type entry name using nesting information. - if (element->type & StackElement::TypeEntryMask - && element->parent && element->parent->type != StackElement::Root) { - name = element->parent->entry->name() + colonColon() + name; - } - - if (name.isEmpty()) { m_error = QLatin1String("no 'name' attribute specified"); return false; @@ -2691,15 +2846,17 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) switch (element->type) { case StackElement::CustomTypeEntry: - element->entry = new TypeEntry(name, TypeEntry::CustomType, since); + if (!checkRootElement()) + return false; + element->entry = new TypeEntry(name, TypeEntry::CustomType, versionRange.since, m_current->entry); break; case StackElement::PrimitiveTypeEntry: - element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes); + element->entry = parsePrimitiveTypeEntry(reader, name, versionRange.since, &attributes); if (Q_UNLIKELY(!element->entry)) return false; break; case StackElement::ContainerTypeEntry: - if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, since, &attributes)) { + if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, versionRange.since, &attributes)) { applyComplexTypeAttributes(reader, ce, &attributes); element->entry = ce; } else { @@ -2708,7 +2865,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) break; case StackElement::SmartPointerTypeEntry: - if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, since, &attributes)) { + if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, versionRange.since, &attributes)) { applyComplexTypeAttributes(reader, se, &attributes); element->entry = se; } else { @@ -2716,22 +2873,14 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) } break; case StackElement::EnumTypeEntry: - m_currentEnum = parseEnumTypeEntry(reader, name, since, &attributes); + m_currentEnum = parseEnumTypeEntry(reader, name, versionRange.since, &attributes); if (Q_UNLIKELY(!m_currentEnum)) return false; element->entry = m_currentEnum; break; - case StackElement::InterfaceTypeEntry: - if (ObjectTypeEntry *oe = parseInterfaceTypeEntry(reader, name, since, &attributes)) { - applyComplexTypeAttributes(reader, oe, &attributes); - element->entry = oe; - } else { - return false; - } - break; case StackElement::ValueTypeEntry: - if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, since, &attributes)) { + if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, versionRange.since, &attributes)) { applyComplexTypeAttributes(reader, ve, &attributes); element->entry = ve; } else { @@ -2739,23 +2888,26 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) } break; case StackElement::NamespaceTypeEntry: - if (auto entry = parseNamespaceTypeEntry(reader, name, since, &attributes)) + if (auto entry = parseNamespaceTypeEntry(reader, name, versionRange.since, &attributes)) element->entry = entry; else return false; break; case StackElement::ObjectTypeEntry: - element->entry = new ObjectTypeEntry(name, since); - applyCommonAttributes(element->entry, &attributes); + case StackElement::InterfaceTypeEntry: + if (!checkRootElement()) + return false; + element->entry = new ObjectTypeEntry(name, versionRange.since, currentParentTypeEntry()); + applyCommonAttributes(reader, element->entry, &attributes); applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes); break; case StackElement::FunctionTypeEntry: - element->entry = parseFunctionTypeEntry(reader, name, since, &attributes); + element->entry = parseFunctionTypeEntry(reader, name, versionRange.since, &attributes); if (Q_UNLIKELY(!element->entry)) return false; break; case StackElement::TypedefTypeEntry: - if (TypedefEntry *te = parseTypedefEntry(reader, name, since, &attributes)) { + if (TypedefEntry *te = parseTypedefEntry(reader, name, versionRange.since, &attributes)) { applyComplexTypeAttributes(reader, te, &attributes); element->entry = te; } else { @@ -2764,7 +2916,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) break; default: Q_ASSERT(false); - }; + } if (element->entry) { if (!m_database->addType(element->entry, &m_error)) @@ -2787,6 +2939,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) || element->type == StackElement::LoadTypesystem || element->type == StackElement::InjectCode || element->type == StackElement::ExtraIncludes + || element->type == StackElement::SystemInclude || element->type == StackElement::ConversionRule || element->type == StackElement::AddFunction || element->type == StackElement::Template; @@ -2801,7 +2954,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) switch (element->type) { case StackElement::Root: - element->entry = parseRootElement(reader, since, &attributes); + element->entry = parseRootElement(reader, versionRange.since, &attributes); element->type = StackElement::Root; break; case StackElement::LoadTypesystem: @@ -2896,6 +3049,10 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) if (!parseAddFunction(reader, topElement, &attributes)) return false; break; + case StackElement::Property: + if (!parseProperty(reader, topElement, &attributes)) + return false; + break; case StackElement::ModifyFunction: if (!parseModifyFunction(reader, topElement, &attributes)) return false; @@ -2939,6 +3096,10 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) if (!addRejection(m_database, &attributes, &m_error)) return false; break; + case StackElement::SystemInclude: + if (!parseSystemInclude(reader, &attributes)) + return false; + break; case StackElement::Template: { const int nameIndex = indexOfAttribute(attributes, nameAttribute()); if (nameIndex == -1) { |