diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/typesystemparser.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/typesystemparser.cpp | 1316 |
1 files changed, 764 insertions, 552 deletions
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index d91fa9193..2b686e997 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -2,22 +2,19 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "typesystemparser_p.h" +#include "anystringview_helpers.h" +#include "addedfunction.h" #include "codesnip.h" #include "enumtypeentry.h" -#include "enumvaluetypeentry.h" -#include "arraytypeentry.h" -#include "constantvaluetypeentry.h" #include "containertypeentry.h" #include "customconversion.h" #include "customtypenentry.h" -#include "enumtypeentry.h" #include "flagstypeentry.h" #include "functiontypeentry.h" #include "namespacetypeentry.h" #include "objecttypeentry.h" #include "primitivetypeentry.h" #include "smartpointertypeentry.h" -#include "templateargumententry.h" #include "typedefentry.h" #include "typesystemtypeentry.h" #include "valuetypeentry.h" @@ -49,76 +46,84 @@ using namespace Qt::StringLiterals; -static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); } -static inline QString colonColon() { return QStringLiteral("::"); } -static inline QString checkFunctionAttribute() { return QStringLiteral("check-function"); } -static inline QString copyableAttribute() { return QStringLiteral("copyable"); } -static inline QString accessAttribute() { return QStringLiteral("access"); } -static inline QString actionAttribute() { return QStringLiteral("action"); } -static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); } -static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); } -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 disableWrapperAttribute() { return QStringLiteral("disable-wrapper"); } -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 generateFunctionsAttribute() { return QStringLiteral("generate-functions"); } -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 isNullAttribute() { return QStringLiteral("isNull"); } -static inline QString locationAttribute() { return QStringLiteral("location"); } -static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); } -static inline QString operatorBoolAttribute() { return QStringLiteral("operator-bool"); } -static inline QString parentManagementAttribute() { return QStringLiteral("parent-management"); } -static inline QString pyiTypeAttribute() { return QStringLiteral("pyi-type"); } -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"); } -static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); } -static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); } -static inline QString qtMetaTypeAttribute() { return QStringLiteral("qt-register-metatype"); } -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 opaqueContainerFieldAttribute() { return QStringLiteral("opaque-container"); } -static inline QString replaceAttribute() { return QStringLiteral("replace"); } -static inline QString toAttribute() { return QStringLiteral("to"); } -static inline QString signatureAttribute() { return QStringLiteral("signature"); } -static inline QString snippetAttribute() { return QStringLiteral("snippet"); } -static inline QString snakeCaseAttribute() { return QStringLiteral("snake-case"); } -static inline QString staticAttribute() { return QStringLiteral("static"); } -static inline QString classmethodAttribute() { return QStringLiteral("classmethod"); } -static inline QString threadAttribute() { return QStringLiteral("thread"); } -static inline QString sourceAttribute() { return QStringLiteral("source"); } -static inline QString streamAttribute() { return QStringLiteral("stream"); } -static inline QString privateAttribute() { return QStringLiteral("private"); } -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"); } -static inline QString yesAttributeValue() { return QStringLiteral("yes"); } -static inline QString trueAttributeValue() { return QStringLiteral("true"); } -static inline QString falseAttributeValue() { return QStringLiteral("false"); } +constexpr auto allowThreadAttribute = "allow-thread"_L1; +constexpr auto checkFunctionAttribute = "check-function"_L1; +constexpr auto copyableAttribute = "copyable"_L1; +constexpr auto accessAttribute = "access"_L1; +constexpr auto actionAttribute = "action"_L1; +constexpr auto quoteAfterLineAttribute = "quote-after-line"_L1; +constexpr auto quoteBeforeLineAttribute = "quote-before-line"_L1; +constexpr auto textAttribute = "text"_L1; +constexpr auto nameAttribute = "name"_L1; +constexpr auto sinceAttribute = "since"_L1; +constexpr auto untilAttribute = "until"_L1; +constexpr auto defaultSuperclassAttribute = "default-superclass"_L1; +constexpr auto deleteInMainThreadAttribute = "delete-in-main-thread"_L1; +constexpr auto deprecatedAttribute = "deprecated"_L1; +constexpr auto disableWrapperAttribute = "disable-wrapper"_L1; +constexpr auto docFileAttribute = "doc-file"_L1; +constexpr auto exceptionHandlingAttribute = "exception-handling"_L1; +constexpr auto extensibleAttribute = "extensible"_L1; +constexpr auto fileNameAttribute = "file-name"_L1; +constexpr auto fileAttribute = "file"_L1; +constexpr auto flagsAttribute = "flags"_L1; +constexpr auto forceAbstractAttribute = "force-abstract"_L1; +constexpr auto forceIntegerAttribute = "force-integer"_L1; +constexpr auto formatAttribute = "format"_L1; +constexpr auto generateUsingAttribute = "generate-using"_L1; +constexpr auto generateFunctionsAttribute = "generate-functions"_L1; +constexpr auto classAttribute = "class"_L1; +constexpr auto generateAttribute = "generate"_L1; +constexpr auto generateGetSetDefAttribute = "generate-getsetdef"_L1; +constexpr auto genericClassAttribute = "generic-class"_L1; +constexpr auto indexAttribute = "index"_L1; +constexpr auto invalidateAfterUseAttribute = "invalidate-after-use"_L1; +constexpr auto isNullAttribute = "isNull"_L1; +constexpr auto locationAttribute = "location"_L1; +constexpr auto modifiedTypeAttribute = "modified-type"_L1; +constexpr auto opaqueContainerAttribute = "opaque-containers"_L1; +constexpr auto operatorBoolAttribute = "operator-bool"_L1; +constexpr auto parentManagementAttribute = "parent-management"_L1; +constexpr auto pyiTypeAttribute = "pyi-type"_L1; +constexpr auto overloadNumberAttribute = "overload-number"_L1; +constexpr auto ownershipAttribute = "owner"_L1; +constexpr auto packageAttribute = "package"_L1; +constexpr auto polymorphicBaseAttribute = "polymorphic-base"_L1; +constexpr auto positionAttribute = "position"_L1; +constexpr auto preferredConversionAttribute = "preferred-conversion"_L1; +constexpr auto preferredTargetLangTypeAttribute = "preferred-target-lang-type"_L1; +constexpr auto pythonEnumTypeAttribute = "python-type"_L1; +constexpr auto pythonOverrideAttribute = "python-override"_L1; +constexpr auto cppEnumTypeAttribute = "cpp-type"_L1; +constexpr auto qtMetaObjectFunctionsAttribute = "qt-metaobject"_L1; +constexpr auto qtMetaTypeAttribute = "qt-register-metatype"_L1; +constexpr auto removeAttribute = "remove"_L1; +constexpr auto renameAttribute = "rename"_L1; +constexpr auto readAttribute = "read"_L1; +constexpr auto targetLangNameAttribute = "target-lang-name"_L1; +constexpr auto writeAttribute = "write"_L1; +constexpr auto opaqueContainerFieldAttribute = "opaque-container"_L1; +constexpr auto replaceAttribute = "replace"_L1; +constexpr auto toAttribute = "to"_L1; +constexpr auto signatureAttribute = "signature"_L1; +constexpr auto snippetAttribute = "snippet"_L1; +constexpr auto snakeCaseAttribute = "snake-case"_L1; +constexpr auto staticAttribute = "static"_L1; +constexpr auto classmethodAttribute = "classmethod"_L1; +constexpr auto threadAttribute = "thread"_L1; +constexpr auto sourceAttribute = "source"_L1; +constexpr auto streamAttribute = "stream"_L1; +constexpr auto privateAttribute = "private"_L1; +constexpr auto xPathAttribute = "xpath"_L1; +constexpr auto virtualSlotAttribute = "virtual-slot"_L1; +constexpr auto visibleAttribute = "visible"_L1; +constexpr auto enumIdentifiedByValueAttribute = "identified-by-value"_L1; +constexpr auto subModuleOfAttribute = "submodule-of"_L1; + +constexpr auto noAttributeValue = "no"_L1; +constexpr auto yesAttributeValue = "yes"_L1; +constexpr auto trueAttributeValue = "true"_L1; +constexpr auto falseAttributeValue = "false"_L1; static bool isTypeEntry(StackElement el) { @@ -135,7 +140,7 @@ static bool isDocumentation(StackElement el) return el >= StackElement::FirstDocumentation && el <= StackElement::LastDocumentation; } -static QList<CustomConversion *> customConversionsForReview; +static QList<CustomConversionPtr> customConversionsForReview; // Set a regular expression for rejection from text. By legacy, those are fixed // strings, except for '*' meaning 'match all'. Enclosing in "^..$" @@ -148,7 +153,7 @@ static bool setRejectionRegularExpression(const QString &patternIn, if (patternIn.startsWith(u'^') && patternIn.endsWith(u'$')) pattern = patternIn; else if (patternIn == u"*") - pattern = QStringLiteral("^.*$"); + pattern = "^.*$"_L1; else pattern = u'^' + QRegularExpression::escape(patternIn) + u'$'; re->setPattern(pattern); @@ -159,15 +164,20 @@ static bool setRejectionRegularExpression(const QString &patternIn, return true; } +static inline bool hasFileSnippetAttributes(const QXmlStreamAttributes *attributes) +{ + return attributes->hasAttribute(fileAttribute); +} + // Extract a snippet from a file within annotation "// @snippet label". std::optional<QString> extractSnippet(const QString &code, const QString &snippetLabel) { if (snippetLabel.isEmpty()) return code; - const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)") + const QString pattern = R"(^\s*//\s*@snippet\s+)"_L1 + QRegularExpression::escape(snippetLabel) - + QStringLiteral(R"(\s*$)"); + + R"(\s*$)"_L1; const QRegularExpression snippetRe(pattern); Q_ASSERT(snippetRe.isValid()); @@ -176,7 +186,7 @@ std::optional<QString> QString result; const auto lines = QStringView{code}.split(u'\n'); for (const auto &line : lines) { - if (snippetRe.match(line).hasMatch()) { + if (snippetRe.matchView(line).hasMatch()) { foundLabel = true; useLine = !useLine; if (!useLine) @@ -189,48 +199,31 @@ std::optional<QString> return CodeSnipAbstract::fixSpaces(result); } -template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive> +template <class EnumType> struct EnumLookup { QStringView name; EnumType value; }; -template <class EnumType, Qt::CaseSensitivity cs> -bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) -{ - return e1.name.compare(e2.name, cs) == 0; -} - -template <class EnumType, Qt::CaseSensitivity cs> -bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) -{ - return e1.name.compare(e2.name, cs) < 0; -} - // Helper macros to define lookup functions that take a QStringView needle // and an optional default return value. #define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName) \ static std::optional<EnumType> functionName(QStringView needle) \ { \ - using HaystackEntry = EnumLookup<EnumType, caseSensitivity>; \ - static const HaystackEntry haystack[] = - -#define ENUM_LOOKUP_LINEAR_SEARCH() \ - const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \ - const auto it = std::find(haystack, end, HaystackEntry{needle, {} }); \ + using HaystackEntry = EnumLookup<EnumType>; \ + constexpr auto cs = caseSensitivity; \ + static constexpr HaystackEntry haystack[] = + +#define ENUM_LOOKUP_LINEAR_SEARCH \ + auto pred = [cs, needle](const HaystackEntry &he) { \ + return he.name.compare(needle, cs) == 0; \ + }; \ + auto end = std::cend(haystack); \ + auto it = std::find_if(std::cbegin(haystack), end, pred); \ if (it != end) \ return it->value; \ - return {}; \ -} - -#define ENUM_LOOKUP_BINARY_SEARCH() \ - const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \ - const HaystackEntry needleEntry{needle, {} }; \ - const auto lb = std::lower_bound(haystack, end, needleEntry); \ - if (lb != end && *lb == needleEntry) \ - return lb->value; \ - return {}; \ + return std::nullopt; \ } ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive, @@ -242,7 +235,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive, {u"no", TypeSystem::AllowThread::Disallow}, {u"false", TypeSystem::AllowThread::Disallow}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive, @@ -253,7 +246,17 @@ ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive, {u"no", TypeSystem::BoolCast::Disabled}, {u"false", TypeSystem::BoolCast::Disabled}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH + +ENUM_LOOKUP_BEGIN(TypeSystem::PythonEnumType, Qt::CaseSensitive, + pythonEnumTypeFromAttribute) + { + {u"Enum", TypeSystem::PythonEnumType::Enum}, + {u"IntEnum", TypeSystem::PythonEnumType::IntEnum}, + {u"Flag", TypeSystem::PythonEnumType::Flag}, + {u"IntFlag", TypeSystem::PythonEnumType::IntFlag}, + }; +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive, qtMetaTypeFromAttribute) @@ -264,7 +267,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive, {u"no", TypeSystem::QtMetaTypeRegistration::Disabled}, {u"false", TypeSystem::QtMetaTypeRegistration::Disabled}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, languageFromAttribute) @@ -274,7 +277,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe {u"target", TypeSystem::TargetLangCode} // em algum lugar do cpp }; -ENUM_LOOKUP_BINARY_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive, ownershipFromFromAttribute) @@ -283,7 +286,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive, {u"c++", TypeSystem::CppOwnership}, {u"default", TypeSystem::DefaultOwnership} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive, addedFunctionAccessFromAttribute) @@ -291,7 +294,7 @@ ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive, {u"public", AddedFunction::Public}, {u"protected", AddedFunction::Protected}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive, modifierFromAttribute) @@ -299,12 +302,11 @@ ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive, {u"private", FunctionModification::Private}, {u"public", FunctionModification::Public}, {u"protected", FunctionModification::Protected}, - {u"friendly", FunctionModification::Friendly}, {u"rename", FunctionModification::Rename}, {u"final", FunctionModification::Final}, {u"non-final", FunctionModification::NonFinal} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive, referenceCountFromAttribute) @@ -315,7 +317,7 @@ ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive, {u"set", ReferenceCount::Set}, {u"ignore", ReferenceCount::Ignore} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive, argumentOwnerActionFromAttribute) @@ -323,16 +325,17 @@ ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive, {u"add", ArgumentOwner::Add}, {u"remove", ArgumentOwner::Remove} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive, codeSnipPositionFromAttribute) { {u"beginning", TypeSystem::CodeSnipPositionBeginning}, {u"end", TypeSystem::CodeSnipPositionEnd}, - {u"declaration", TypeSystem::CodeSnipPositionDeclaration} + {u"declaration", TypeSystem::CodeSnipPositionDeclaration}, + {u"override", TypeSystem::CodeSnipPositionPyOverride} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive, locationFromAttribute) @@ -341,7 +344,7 @@ ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive, {u"local", Include::LocalPath}, {u"target", Include::TargetLangImport} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, docModificationFromAttribute) @@ -350,7 +353,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, {u"prepend", TypeSystem::DocModificationPrepend}, {u"replace", TypeSystem::DocModificationReplace} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive, containerTypeFromAttribute) @@ -366,9 +369,10 @@ ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive, {u"multi-map", ContainerTypeEntry::MultiMapContainer}, {u"hash", ContainerTypeEntry::MapContainer}, {u"multi-hash", ContainerTypeEntry::MultiMapContainer}, - {u"pair", ContainerTypeEntry::PairContainer} + {u"pair", ContainerTypeEntry::PairContainer}, + {u"span", ContainerTypeEntry::SpanContainer} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, typeRejectionFromAttribute) @@ -380,7 +384,7 @@ ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, {u"argument-type", TypeRejection::ArgumentType}, {u"return-type", TypeRejection::ReturnType} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, exceptionHandlingFromAttribute) @@ -392,7 +396,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, {u"yes", TypeSystem::ExceptionHandling::On}, {u"true", TypeSystem::ExceptionHandling::On}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive, smartPointerTypeFromAttribute) @@ -402,7 +406,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive, {u"value-handle", TypeSystem::SmartPointerType::ValueHandle}, {u"shared", TypeSystem::SmartPointerType::Shared} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH template <class EnumType> static std::optional<EnumType> @@ -431,6 +435,7 @@ static const StackElementHash &stackElementHash() {u"add-function", StackElement::AddFunction}, {u"add-pymethoddef", StackElement::AddPyMethodDef}, {u"array", StackElement::Array}, + {u"configuration", StackElement::Configuration}, {u"container-type", StackElement::ContainerTypeEntry}, {u"conversion-rule", StackElement::ConversionRule}, {u"custom-constructor", StackElement::Unimplemented}, @@ -456,6 +461,7 @@ static const StackElementHash &stackElementHash() {u"native-to-target", StackElement::NativeToTarget}, {u"no-null-pointer", StackElement::NoNullPointers}, {u"object-type", StackElement::ObjectTypeEntry}, + {u"opaque-container", StackElement::OpaqueContainer}, {u"parent", StackElement::ParentOwner}, {u"primitive-type", StackElement::PrimitiveTypeEntry}, {u"property", StackElement::Property}, @@ -511,7 +517,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::SnakeCase, Qt::CaseSensitive, {u"true", TypeSystem::SnakeCase::Enabled}, {u"both", TypeSystem::SnakeCase::Both}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, visibilityFromAttribute) @@ -522,12 +528,12 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, {u"yes", TypeSystem::Visibility::Visible}, {u"true", TypeSystem::Visibility::Visible}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH static int indexOfAttribute(const QXmlStreamAttributes &atts, - QStringView name) + QAnyStringView name) { - for (int i = 0, size = atts.size(); i < size; ++i) { + for (qsizetype i = 0, size = atts.size(); i < size; ++i) { if (atts.at(i).qualifiedName() == name) return i; } @@ -558,7 +564,7 @@ static QString msgUnusedAttributes(QStringView tag, const QXmlStreamAttributes & QString result; QTextStream str(&result); str << attributes.size() << " attributes(s) unused on <" << tag << ">: "; - for (int i = 0, size = attributes.size(); i < size; ++i) { + for (qsizetype i = 0, size = attributes.size(); i < size; ++i) { if (i) str << ", "; str << attributes.at(i); @@ -593,17 +599,17 @@ QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *e path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); if (!QFileInfo::exists(path)) { *errorMessage = u"Unable to resolve: "_s + entityName; - return QString(); + return {}; } QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { *errorMessage = msgCannotOpenForReading(file); - return QString(); + return {}; } QString result = QString::fromUtf8(file.readAll()).trimmed(); // Remove license header comments on which QXmlStreamReader chokes if (result.startsWith(u"<!--")) { - const int commentEnd = result.indexOf(u"-->"); + const auto commentEnd = result.indexOf(u"-->"); if (commentEnd != -1) { result.remove(0, commentEnd + 3); result = result.trimmed(); @@ -638,7 +644,7 @@ enum class ParserState Template }; -TypeSystemParser::TypeSystemParser(const QSharedPointer<TypeDatabaseParserContext> &context, +TypeSystemParser::TypeSystemParser(const std::shared_ptr<TypeDatabaseParserContext> &context, bool generate) : m_context(context), m_generate(generate ? TypeEntry::GenerateCode : TypeEntry::GenerateForSubclass) @@ -681,7 +687,7 @@ static QString msgReaderError(const ConditionalStreamReader &reader, const QStri } static QString msgUnimplementedElementWarning(const ConditionalStreamReader &reader, - QStringView name) + QAnyStringView name) { QString message; QTextStream(&message) << "The element \"" << name @@ -706,7 +712,7 @@ static inline QString msgUnimplementedAttributeWarning(const ConditionalStreamRe static QString msgUnimplementedAttributeValueWarning(const ConditionalStreamReader &reader, - QStringView name, QStringView value) + QAnyStringView name, QAnyStringView value) { QString message; QTextStream(&message) << "The value \"" << value @@ -723,21 +729,22 @@ static inline attribute.value()); } -static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes, +static bool addRejection(TypeDatabase *database, bool generate, QXmlStreamAttributes *attributes, QString *errorMessage) { - const int classIndex = indexOfAttribute(*attributes, classAttribute()); + const auto classIndex = indexOfAttribute(*attributes, classAttribute); if (classIndex == -1) { - *errorMessage = msgMissingAttribute(classAttribute()); + *errorMessage = msgMissingAttribute(classAttribute); return false; } TypeRejection rejection; + rejection.generate = generate; const QString className = attributes->takeAt(classIndex).value().toString(); if (!setRejectionRegularExpression(className, &rejection.className, errorMessage)) return false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto &attribute = attributes->at(i); const auto name = attribute.qualifiedName(); const auto typeOpt = typeRejectionFromAttribute(name); @@ -864,13 +871,14 @@ bool TypeSystemParser::endElement(StackElement element) if (m_generate == TypeEntry::GenerateCode) { TypeDatabase::instance()->addGlobalUserFunctions(top->addedFunctions); TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods); - for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) { - const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions(); - for (CustomConversion::TargetToNativeConversion *toNative : toNatives) - toNative->setSourceType(m_context->db->findType(toNative->sourceTypeName())); + for (const auto &customConversion : std::as_const(customConversionsForReview)) { + TargetToNativeConversions &toNatives = + customConversion->targetToNativeConversions(); + for (auto &toNative : toNatives) + toNative.setSourceType(m_context->db->findType(toNative.sourceTypeName())); } } - purgeEmptyCodeSnips(&top->entry->codeSnips()); + purgeEmptyCodeSnips(&std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips()); break; case StackElement::FunctionTypeEntry: TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods); @@ -882,7 +890,7 @@ bool TypeSystemParser::endElement(StackElement element) case StackElement::NamespaceTypeEntry: { Q_ASSERT(top->entry); Q_ASSERT(top->entry->isComplex()); - auto *centry = static_cast<ComplexTypeEntry *>(top->entry); + auto centry = std::static_pointer_cast<ComplexTypeEntry>(top->entry); purgeEmptyCodeSnips(¢ry->codeSnips()); centry->setAddedFunctions(top->addedFunctions); centry->setFunctionModifications(top->functionMods); @@ -892,12 +900,15 @@ bool TypeSystemParser::endElement(StackElement element) break; case StackElement::TypedefTypeEntry: { - auto *centry = static_cast<TypedefEntry *>(top->entry)->target(); + auto centry = std::static_pointer_cast<TypedefEntry>(top->entry)->target(); centry->setAddedFunctions(centry->addedFunctions() + top->addedFunctions); centry->setFunctionModifications(centry->functionModifications() + top->functionMods); centry->setFieldModifications(centry->fieldModifications() + top->fieldMods); - centry->setCodeSnips(centry->codeSnips() + top->entry->codeSnips()); centry->setDocModification(centry->docModifications() + top->docModifications); + if (top->entry->isComplex()) { + auto cte = std::static_pointer_cast<const ComplexTypeEntry>(top->entry); + centry->setCodeSnips(centry->codeSnips() + cte->codeSnips()); + } } break; @@ -909,29 +920,30 @@ bool TypeSystemParser::endElement(StackElement element) Q_ASSERT(modIndex >= 0); Q_ASSERT(!top->addedFunctions.isEmpty()); while (modIndex < top->functionMods.size()) - top->addedFunctions.last()->modifications.append(top->functionMods.takeAt(modIndex)); + top->addedFunctions.last()->modifications().append(top->functionMods.takeAt(modIndex)); } break; case StackElement::NativeToTarget: case StackElement::AddConversion: switch (parserState()) { case ParserState::PrimitiveTypeNativeToTargetConversion: - case ParserState::PrimitiveTypeTargetToNativeConversion: - if (auto *customConversion = top->entry->customConversion()) { - QString code = top->conversionCodeSnips.constLast().code(); - if (element == StackElement::AddConversion) { - if (customConversion->targetToNativeConversions().isEmpty()) { - m_error = u"CustomConversion's target to native conversions missing."_s; - return false; - } - customConversion->targetToNativeConversions().last()->setConversion(code); - } else { - customConversion->setNativeToTargetConversion(code); + case ParserState::PrimitiveTypeTargetToNativeConversion: { + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + QString code = top->conversionCodeSnips.constLast().code(); + if (element == StackElement::AddConversion) { + if (customConversion->targetToNativeConversions().isEmpty()) { + m_error = u"CustomConversion's target to native conversions missing."_s; + return false; } + customConversion->targetToNativeConversions().last().setConversion(code); } else { - m_error = u"CustomConversion object is missing."_s; - return false; + customConversion->setNativeToTargetConversion(code); } + } break; case ParserState::ArgumentNativeToTargetConversion: { @@ -953,8 +965,6 @@ bool TypeSystemParser::endElement(StackElement element) break; case StackElement::EnumTypeEntry: - top->entry->setDocModification(top->docModifications); - top->docModifications = DocModificationList(); m_currentEnum = nullptr; break; case StackElement::Template: @@ -1055,10 +1065,13 @@ CodeSnipAbstract *TypeSystemParser::injectCodeTarget(qsizetype offset) const return &funcMod.snips().last(); } case ParserState::TypeEntryCodeInjection: + Q_ASSERT(top->entry->isComplex()); + return &std::static_pointer_cast<ComplexTypeEntry>(top->entry)->codeSnips().last(); case ParserState::TypeSystemCodeInjection: - return &top->entry->codeSnips().last(); + Q_ASSERT(top->entry->isTypeSystem()); + return &std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips().last(); case ParserState::Template: - return m_templateEntry; + return m_templateEntry.get(); default: break; } @@ -1092,15 +1105,22 @@ bool TypeSystemParser::characters(const String &ch) return true; } - if (isDocumentation(type)) - m_contextStack.top()->docModifications.last().setCode(ch); + if (isDocumentation(type)) { + const bool isAddedFunction = m_stack.value(m_stack.size() - 2, StackElement::None) + == StackElement::AddFunction; + const auto &top = m_contextStack.top(); + auto &docModifications = isAddedFunction + ? top->addedFunctions.last()->docModifications() + : top->docModifications; + docModifications.last().setCode(ch); + } return true; } bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) { - const QString fileName = atts.value(nameAttribute()).toString(); + const QString fileName = atts.value(nameAttribute).toString(); if (fileName.isEmpty()) { m_error = u"Required attribute 'name' missing for include-file tag."_s; return false; @@ -1115,11 +1135,11 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) } } - const auto quoteFrom = atts.value(quoteAfterLineAttribute()); + const auto quoteFrom = atts.value(quoteAfterLineAttribute); bool foundFromOk = quoteFrom.isEmpty(); bool from = quoteFrom.isEmpty(); - const auto quoteTo = atts.value(quoteBeforeLineAttribute()); + const auto quoteTo = atts.value(quoteBeforeLineAttribute); bool foundToOk = quoteTo.isEmpty(); bool to = true; @@ -1139,10 +1159,10 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) } } if (!foundFromOk || !foundToOk) { - QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.") - .arg(quoteFrom.toString(), fileName); - QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.") - .arg(quoteTo.toString(), fileName); + QString fromError = QString::fromLatin1("Could not find quote-after-line='%1' in file '%2'.") + .arg(quoteFrom.toString(), fileName); + QString toError = QString::fromLatin1("Could not find quote-before-line='%1' in file '%2'.") + .arg(quoteTo.toString(), fileName); if (!foundToOk) m_error = toError; @@ -1156,29 +1176,27 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) return true; } -static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue) +static bool convertBoolean(QStringView value, QAnyStringView attributeName, bool defaultValue) { - if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0 - || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) { + if (value.compare(trueAttributeValue, Qt::CaseInsensitive) == 0 + || value.compare(yesAttributeValue, Qt::CaseInsensitive) == 0) { return true; } - if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0 - || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) { + if (value.compare(falseAttributeValue, Qt::CaseInsensitive) == 0 + || value.compare(noAttributeValue, Qt::CaseInsensitive) == 0) { return false; } - const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") - .arg(value) - .arg(attributeName, - defaultValue ? yesAttributeValue() : noAttributeValue()); - - qCWarning(lcShiboken).noquote().nospace() << warn; + qCWarning(lcShiboken).noquote().nospace() << "Boolean value '" << value + << "' not supported in attribute '" << attributeName + << "'. Use 'yes' or 'no'. Defaulting to '" + << (defaultValue ? yesAttributeValue : noAttributeValue) << "'."; return defaultValue; } static bool convertRemovalAttribute(QStringView value) { return value == u"all" // Legacy - || convertBoolean(value, removeAttribute(), false); + || convertBoolean(value, removeAttribute, false); } // Check whether an entry should be dropped, allowing for dropping the module @@ -1188,7 +1206,7 @@ static bool shouldDropTypeEntry(const TypeDatabase *db, QString name) { for (auto i = stack.size() - 1; i >= 0; --i) { - if (auto *entry = stack.at(i)->entry) { + if (auto entry = stack.at(i)->entry) { if (entry->type() == TypeEntry::TypeSystemType) { if (db->shouldDropTypeEntry(name)) // Unqualified return true; @@ -1204,7 +1222,7 @@ static bool shouldDropTypeEntry(const TypeDatabase *db, static QString checkSignatureError(const QString& signature, const QString& tag) { QString funcName = signature.left(signature.indexOf(u'(')).trimmed(); - static const QRegularExpression whiteSpace(QStringLiteral("\\s")); + static const QRegularExpression whiteSpace("\\s"_L1); Q_ASSERT(whiteSpace.isValid()); if (!funcName.startsWith(u"operator ") && funcName.contains(whiteSpace)) { return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n" @@ -1215,7 +1233,7 @@ static QString checkSignatureError(const QString& signature, const QString& tag) return QString(); } -inline const TypeEntry *TypeSystemParser::currentParentTypeEntry() const +inline TypeEntryCPtr TypeSystemParser::currentParentTypeEntry() const { const auto size = m_contextStack.size(); return size > 1 ? m_contextStack.at(size - 2)->entry : nullptr; @@ -1224,7 +1242,7 @@ inline const TypeEntry *TypeSystemParser::currentParentTypeEntry() const bool TypeSystemParser::checkRootElement() { for (auto i = m_contextStack.size() - 1; i >= 0; --i) { - auto *e = m_contextStack.at(i)->entry; + auto e = m_contextStack.at(i)->entry; if (e && e->isTypeSystem()) return true; } @@ -1232,7 +1250,7 @@ bool TypeSystemParser::checkRootElement() return false; } -static TypeEntry *findViewedType(const QString &name) +static TypeEntryPtr findViewedType(const QString &name) { const auto range = TypeDatabase::instance()->entries().equal_range(name); for (auto i = range.first; i != range.second; ++i) { @@ -1249,20 +1267,21 @@ static TypeEntry *findViewedType(const QString &name) return nullptr; } -bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &reader, TypeEntry *type, +bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &reader, + const TypeEntryPtr &type, QXmlStreamAttributes *attributes) { type->setSourceLocation(SourceLocation(m_currentFile, reader.lineNumber())); type->setCodeGeneration(m_generate); - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"revision") { type->setRevision(attributes->takeAt(i).value().toInt()); } else if (name == u"view-on") { const QString name = attributes->takeAt(i).value().toString(); - TypeEntry *views = findViewedType(name); - if (views == nullptr) { + TypeEntryPtr views = findViewedType(name); + if (!views) { m_error = msgCannotFindView(name, type->name()); return false; } @@ -1272,55 +1291,55 @@ bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &read return true; } -CustomTypeEntry *TypeSystemParser::parseCustomTypeEntry(const ConditionalStreamReader &, +CustomTypeEntryPtr TypeSystemParser::parseCustomTypeEntry(const ConditionalStreamReader &, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *result = new CustomTypeEntry(name, since, m_contextStack.top()->entry); - for (int i = attributes->size() - 1; i >= 0; --i) { + auto result = std::make_shared<CustomTypeEntry>(name, since, m_contextStack.top()->entry); + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == checkFunctionAttribute()) + if (name == checkFunctionAttribute) result->setCheckFunction(attributes->takeAt(i).value().toString()); } return result; } -FlagsTypeEntry * +FlagsTypeEntryPtr TypeSystemParser::parseFlagsEntry(const ConditionalStreamReader &reader, - EnumTypeEntry *enumEntry, QString flagName, + const EnumTypeEntryPtr &enumEntry, QString flagName, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto ftype = new FlagsTypeEntry(u"QFlags<"_s + enumEntry->name() + u'>', - since, - currentParentTypeEntry()->typeSystemTypeEntry()); + auto ftype = std::make_shared<FlagsTypeEntry>(u"QFlags<"_s + enumEntry->name() + u'>', + since, + typeSystemTypeEntry(currentParentTypeEntry())); ftype->setOriginator(enumEntry); ftype->setTargetLangPackage(enumEntry->targetLangPackage()); // Try toenumEntry get the guess the qualified flag name - if (!flagName.contains(colonColon())) { + if (!flagName.contains(u"::"_s)) { auto eq = enumEntry->qualifier(); if (!eq.isEmpty()) - flagName.prepend(eq + colonColon()); + flagName.prepend(eq + u"::"_s); } ftype->setOriginalName(flagName); if (!applyCommonAttributes(reader, ftype, attributes)) return nullptr; - QStringList lst = flagName.split(colonColon()); + QStringList lst = flagName.split(u"::"_s); const QString name = lst.takeLast(); const QString targetLangFlagName = lst.join(u'.'); const QString &targetLangQualifier = enumEntry->targetLangQualifier(); if (targetLangFlagName != targetLangQualifier) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum %1 and flags %2 (%3) differ in qualifiers") - .arg(targetLangQualifier, lst.value(0), targetLangFlagName); + qCWarning(lcShiboken, "enum %s and flags %s (%s) differ in qualifiers", + qPrintable(targetLangQualifier), qPrintable(lst.value(0)), + qPrintable(targetLangFlagName)); } ftype->setFlagsName(name); @@ -1337,7 +1356,7 @@ FlagsTypeEntry * return ftype; } -SmartPointerTypeEntry * +SmartPointerTypeEntryPtr TypeSystemParser::parseSmartPointerEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) @@ -1351,7 +1370,7 @@ SmartPointerTypeEntry * QString nullCheckMethod; QString resetMethod; QString instantiations; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"type") { const auto attribute = attributes->takeAt(i); @@ -1400,8 +1419,9 @@ SmartPointerTypeEntry * return nullptr; } - auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, - refCountMethodName, since, currentParentTypeEntry()); + auto type = std::make_shared<SmartPointerTypeEntry>(name, getter, smartPointerType, + refCountMethodName, since, + currentParentTypeEntry()); if (!applyCommonAttributes(reader, type, attributes)) return nullptr; applyComplexTypeAttributes(reader, type, attributes); @@ -1412,29 +1432,29 @@ SmartPointerTypeEntry * return type; } -PrimitiveTypeEntry * +PrimitiveTypeEntryPtr TypeSystemParser::parsePrimitiveTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *type = new PrimitiveTypeEntry(name, since, currentParentTypeEntry()); + auto type = std::make_shared<PrimitiveTypeEntry>(name, since, currentParentTypeEntry()); QString targetLangApiName; if (!applyCommonAttributes(reader, type, attributes)) return nullptr; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == targetLangNameAttribute()) { + if (name == targetLangNameAttribute) { type->setTargetLangName(attributes->takeAt(i).value().toString()); } else if (name == u"target-lang-api-name") { targetLangApiName = attributes->takeAt(i).value().toString(); - } else if (name == preferredConversionAttribute()) { + } else if (name == preferredConversionAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == preferredTargetLangTypeAttribute()) { + } else if (name == preferredTargetLangTypeAttribute) { const bool v = convertBoolean(attributes->takeAt(i).value(), - preferredTargetLangTypeAttribute(), true); + preferredTargetLangTypeAttribute, true); type->setPreferredTargetLangType(v); } else if (name == u"default-constructor") { type->setDefaultConstructor(attributes->takeAt(i).value().toString()); @@ -1442,40 +1462,53 @@ PrimitiveTypeEntry * } if (!targetLangApiName.isEmpty()) { - auto *e = m_context->db->findType(targetLangApiName); - if (e == nullptr || !e->isCustom()) { + auto e = m_context->db->findType(targetLangApiName); + if (!e || !e->isCustom()) { m_error = msgInvalidTargetLanguageApiName(targetLangApiName); return nullptr; } - type->setTargetLangApiType(static_cast<CustomTypeEntry *>(e)); + type->setTargetLangApiType(std::static_pointer_cast<CustomTypeEntry>(e)); } type->setTargetLangPackage(m_defaultPackage); return type; } // "int:QList_int;QString:QList_QString" -static bool parseOpaqueContainers(QStringView s, ContainerTypeEntry *cte) +bool TypeSystemParser::parseOpaqueContainers(QStringView s, OpaqueContainers *result) { const auto entries = s.split(u';'); for (const auto &entry : entries) { const auto values = entry.split(u':'); - if (values.size() != 2) - return false; - QString instantiation = values.at(0).trimmed().toString(); - QString name = values.at(1).trimmed().toString(); - cte->addOpaqueContainer({instantiation, name}); + if (values.size() != 2) { + m_error = u"Error parsing the opaque container attribute: \""_s + + s.toString() + u"\"."_s; + return false; + } + OpaqueContainer oc; + oc.name = values.at(1).trimmed().toString(); + const auto instantiations = values.at(0).split(u',', Qt::SkipEmptyParts); + for (const auto &instantiationV : instantiations) { + QString instantiation = instantiationV.trimmed().toString(); + // Fix to match AbstractMetaType::signature() which is used for matching + // "Foo*" -> "Foo *" + const auto asteriskPos = instantiation.indexOf(u'*'); + if (asteriskPos > 0 && !instantiation.at(asteriskPos - 1).isSpace()) + instantiation.insert(asteriskPos, u' '); + oc.instantiations.append(instantiation); + } + result->append(oc); } return true; } -ContainerTypeEntry * +ContainerTypeEntryPtr TypeSystemParser::parseContainerTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - const int typeIndex = indexOfAttribute(*attributes, u"type"); + const auto typeIndex = indexOfAttribute(*attributes, u"type"); if (typeIndex == -1) { m_error = u"no 'type' attribute specified"_s; return nullptr; @@ -1487,40 +1520,61 @@ ContainerTypeEntry * return nullptr; } attributes->removeAt(typeIndex); - auto *type = new ContainerTypeEntry(name, containerTypeOpt.value(), - since, currentParentTypeEntry()); + auto type = std::make_shared<ContainerTypeEntry>(name, containerTypeOpt.value(), + since, currentParentTypeEntry()); if (!applyCommonAttributes(reader, type, attributes)) return nullptr; applyComplexTypeAttributes(reader, type, attributes); - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == u"opaque-containers") { + if (name == opaqueContainerAttribute) { const auto attribute = attributes->takeAt(i); - if (!parseOpaqueContainers(attribute.value(), type)) { - m_error = u"Error parsing the opaque container attribute: \""_s - + attribute.value().toString() + u"\"."_s; + OpaqueContainers oc; + if (!parseOpaqueContainers(attribute.value(), &oc)) return nullptr; - } + type->appendOpaqueContainers(oc); } } return type; } -EnumTypeEntry * +bool TypeSystemParser::parseOpaqueContainerElement(QXmlStreamAttributes *attributes) +{ + QString containerName; + OpaqueContainers oc; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == nameAttribute) { + containerName = attributes->takeAt(i).value().toString(); + } else if (name == opaqueContainerAttribute) { + const auto attribute = attributes->takeAt(i); + if (!parseOpaqueContainers(attribute.value(), &oc)) + return false; + } + } + if (containerName.isEmpty()) { + m_error = msgMissingAttribute(nameAttribute); + return false; + } + m_context->opaqueContainerHash[containerName].append(oc); + return true; +} + +EnumTypeEntryPtr TypeSystemParser::parseEnumTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *entry = new EnumTypeEntry(name, since, currentParentTypeEntry()); + auto entry = std::make_shared<EnumTypeEntry>(name, since, currentParentTypeEntry()); applyCommonAttributes(reader, entry, attributes); entry->setTargetLangPackage(m_defaultPackage); QString flagNames; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"upper-bound") { qCWarning(lcShiboken, "%s", @@ -1528,13 +1582,26 @@ EnumTypeEntry * } else if (name == u"lower-bound") { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == forceIntegerAttribute()) { + } else if (name == docFileAttribute) { + entry->setDocFile(attributes->takeAt(i).value().toString()); + } else if (name == forceIntegerAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == extensibleAttribute()) { + } else if (name == pythonEnumTypeAttribute) { + const auto attribute = attributes->takeAt(i); + const auto typeOpt = pythonEnumTypeFromAttribute(attribute.value()); + if (typeOpt.has_value()) { + entry->setPythonEnumType(typeOpt.value()); + } else { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } else if (name == cppEnumTypeAttribute) { + entry->setCppType(attributes->takeAt(i).value().toString()); + } else if (name == extensibleAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == flagsAttribute()) { + } else if (name == flagsAttribute) { flagNames = attributes->takeAt(i).value().toString(); } } @@ -1549,17 +1616,17 @@ EnumTypeEntry * } -NamespaceTypeEntry * +NamespaceTypeEntryPtr TypeSystemParser::parseNamespaceTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - std::unique_ptr<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since, currentParentTypeEntry())); + auto result = std::make_shared<NamespaceTypeEntry>(name, since, currentParentTypeEntry()); auto visibility = TypeSystem::Visibility::Unspecified; - applyCommonAttributes(reader, result.get(), attributes); - for (int i = attributes->size() - 1; i >= 0; --i) { + applyCommonAttributes(reader, result, attributes); + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto attributeName = attributes->at(i).qualifiedName(); if (attributeName == u"files") { const QString pattern = attributes->takeAt(i).value().toString(); @@ -1573,7 +1640,7 @@ NamespaceTypeEntry * const auto extendsPackageName = attributes->at(i).value(); auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name); auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(), - [extendsPackageName] (const NamespaceTypeEntry *e) { + [extendsPackageName] (const NamespaceTypeEntryCPtr &e) { return e->targetLangPackage() == extendsPackageName; }); if (extendsIt == allEntries.cend()) { @@ -1582,7 +1649,7 @@ NamespaceTypeEntry * } result->setExtends(*extendsIt); attributes->removeAt(i); - } else if (attributeName == visibleAttribute()) { + } else if (attributeName == visibleAttribute) { const auto attribute = attributes->takeAt(i); const auto visibilityOpt = visibilityFromAttribute(attribute.value()); if (!visibilityOpt.has_value()) { @@ -1590,35 +1657,36 @@ NamespaceTypeEntry * return nullptr; } visibility = visibilityOpt.value(); - } else if (attributeName == generateAttribute()) { - if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true)) + } 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)); + } 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.get(), attributes); + applyComplexTypeAttributes(reader, result, attributes); if (result->extends() && !result->hasPattern()) { m_error = msgExtendingNamespaceRequiresPattern(name); - return nullptr; + return {}; } - return result.release(); + return result; } -ValueTypeEntry * +ValueTypeEntryPtr TypeSystemParser::parseValueTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *typeEntry = new ValueTypeEntry(name, since, currentParentTypeEntry()); + auto typeEntry = std::make_shared<ValueTypeEntry>(name, since, currentParentTypeEntry()); if (!applyCommonAttributes(reader, typeEntry, attributes)) return nullptr; applyComplexTypeAttributes(reader, typeEntry, attributes); @@ -1629,7 +1697,7 @@ ValueTypeEntry * return typeEntry; } -FunctionTypeEntry * +FunctionTypeEntryPtr TypeSystemParser::parseFunctionTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) @@ -1637,50 +1705,56 @@ FunctionTypeEntry * if (!checkRootElement()) return nullptr; - QString signature; - TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Disabled; + FunctionModification mod; + const auto oldAttributesSize = attributes->size(); + if (!parseModifyFunctionAttributes(attributes, &mod)) + return nullptr; + const bool hasModification = attributes->size() < oldAttributesSize; - for (int i = attributes->size() - 1; i >= 0; --i) { + QString originalSignature; + QString docFile; + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == signatureAttribute()) { - signature = TypeDatabase::normalizedSignature(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { - const auto attribute = attributes->takeAt(i); - const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); - if (!snakeCaseOpt.has_value()) { - m_error = msgInvalidAttributeValue(attribute); - return nullptr; - } - snakeCase = snakeCaseOpt.value(); - } + if (name == signatureAttribute) + originalSignature = attributes->takeAt(i).value().toString().simplified(); + else if (name == docFileAttribute) + docFile = attributes->takeAt(i).value().toString(); } + const QString signature = TypeDatabase::normalizedSignature(originalSignature); if (signature.isEmpty()) { - m_error = msgMissingAttribute(signatureAttribute()); + m_error = msgMissingAttribute(signatureAttribute); return nullptr; } - TypeEntry *existingType = m_context->db->findType(name); + if (hasModification) { + mod.setOriginalSignature(originalSignature); + mod.setSignature(signature); + m_contextStack.top()->functionMods << mod; + } + + TypeEntryPtr existingType = m_context->db->findType(name); if (!existingType) { - auto *result = new FunctionTypeEntry(name, signature, since, currentParentTypeEntry()); - result->setSnakeCase(snakeCase); + auto result = std::make_shared<FunctionTypeEntry>(name, signature, since, + currentParentTypeEntry()); + result->setTargetLangPackage(m_defaultPackage); + result->setDocFile(docFile); applyCommonAttributes(reader, result, attributes); return result; } if (existingType->type() != TypeEntry::FunctionType) { - m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.") - .arg(name); + m_error = name + " expected to be a function, but isn't! Maybe it was already declared as a class or something else."_L1; return nullptr; } - auto *result = reinterpret_cast<FunctionTypeEntry *>(existingType); + auto result = std::static_pointer_cast<FunctionTypeEntry>(existingType); result->addSignature(signature); return result; } -TypedefEntry * +TypedefEntryPtr TypeSystemParser::parseTypedefEntry(const ConditionalStreamReader &reader, const QString &name, StackElement topElement, const QVersionNumber &since, @@ -1693,13 +1767,14 @@ TypedefEntry * m_error = u"typedef entries must be nested in namespaces or type system."_s; return nullptr; } - const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute()); + const auto sourceIndex = indexOfAttribute(*attributes, sourceAttribute); if (sourceIndex == -1) { - m_error = msgMissingAttribute(sourceAttribute()); + m_error = msgMissingAttribute(sourceAttribute); return nullptr; } const QString sourceType = attributes->takeAt(sourceIndex).value().toString(); - auto result = new TypedefEntry(name, sourceType, since, currentParentTypeEntry()); + auto result = std::make_shared<TypedefEntry>(name, sourceType, since, + currentParentTypeEntry()); if (!applyCommonAttributes(reader, result, attributes)) return nullptr; applyComplexTypeAttributes(reader, result, attributes); @@ -1707,7 +1782,7 @@ TypedefEntry * } void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader &reader, - ComplexTypeEntry *ctype, + const ComplexTypeEntryPtr &ctype, QXmlStreamAttributes *attributes) const { bool generate = true; @@ -1716,36 +1791,40 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader auto allowThread = m_allowThread; QString package = m_defaultPackage; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == streamAttribute()) { - ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false)); - } else if (name == privateAttribute()) { + if (name == streamAttribute) { + ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute, false)); + } else if (name == privateAttribute) { ctype->setPrivate(convertBoolean(attributes->takeAt(i).value(), - privateAttribute(), false)); - } else if (name == generateAttribute()) { - generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true); - } else if (name ==packageAttribute()) { + privateAttribute, false)); + } else if (name == generateAttribute) { + generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true); + } else if (name ==packageAttribute) { package = attributes->takeAt(i).value().toString(); - } else if (name == defaultSuperclassAttribute()) { + } else if (name == defaultSuperclassAttribute) { ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString()); - } else if (name == genericClassAttribute()) { + } else if (name == genericClassAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false); + const bool v = convertBoolean(attributes->takeAt(i).value(), + genericClassAttribute, false); ctype->setGenericClass(v); - } else if (name == targetLangNameAttribute()) { + } else if (name == targetLangNameAttribute) { ctype->setTargetLangName(attributes->takeAt(i).value().toString()); - } else if (name == u"polymorphic-base") { - ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); + } else if (name == polymorphicBaseAttribute) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + polymorphicBaseAttribute, false); + ctype->setIsPolymorphicBase(v); } else if (name == u"polymorphic-name-function") { ctype->setPolymorphicNameFunction(attributes->takeAt(i).value().toString()); } else if (name == u"polymorphic-id-expression") { ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); - } else if (name == copyableAttribute()) { - const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false); + } else if (name == copyableAttribute) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + copyableAttribute, false); ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet); - } else if (name == exceptionHandlingAttribute()) { + } else if (name == exceptionHandlingAttribute) { const auto attribute = attributes->takeAt(i); const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); if (exceptionOpt.has_value()) { @@ -1754,7 +1833,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == allowThreadAttribute()) { + } else if (name == allowThreadAttribute) { const auto attribute = attributes->takeAt(i); const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); if (allowThreadOpt.has_value()) { @@ -1768,19 +1847,25 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qPrintable(msgUnimplementedAttributeWarning(reader, name))); } else if (name == u"hash-function") { ctype->setHashFunction(attributes->takeAt(i).value().toString()); - } else if (name == forceAbstractAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute(), false)) + } else if (name == forceAbstractAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract); - } else if (name == deprecatedAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false)) + } else if (name == deprecatedAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated); - } else if (name == disableWrapperAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute(), false)) + } else if (name == disableWrapperAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DisableWrapper); - } else if (name == deleteInMainThreadAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false)) + } else if (name == deleteInMainThreadAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute, false)) ctype->setDeleteInMainThread(true); - } else if (name == generateFunctionsAttribute()) { + } else if (name == qtMetaObjectFunctionsAttribute) { + if (!convertBoolean(attributes->takeAt(i).value(), + qtMetaObjectFunctionsAttribute, true)) { + ctype->setTypeFlags(ctype->typeFlags() + | ComplexTypeEntry::DisableQtMetaObjectFunctions); + } + } else if (name == generateFunctionsAttribute) { const auto names = attributes->takeAt(i).value(); const auto nameList = names.split(u';', Qt::SkipEmptyParts); QSet<QString> nameSet; @@ -1789,7 +1874,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader ctype->setGenerateFunctions(nameSet); } else if (name == u"target-type") { ctype->setTargetType(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -1798,7 +1883,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == isNullAttribute()) { + } else if (name == isNullAttribute) { const auto attribute = attributes->takeAt(i); const auto boolCastOpt = boolCastFromAttribute(attribute.value()); if (boolCastOpt.has_value()) { @@ -1807,7 +1892,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == operatorBoolAttribute()) { + } else if (name == operatorBoolAttribute) { const auto attribute = attributes->takeAt(i); const auto boolCastOpt = boolCastFromAttribute(attribute.value()); if (boolCastOpt.has_value()) { @@ -1816,7 +1901,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == qtMetaTypeAttribute()) { + } else if (name == qtMetaTypeAttribute) { const auto attribute = attributes->takeAt(i); const auto qtMetaTypeOpt = qtMetaTypeFromAttribute(attribute.value()); if (qtMetaTypeOpt.has_value()) { @@ -1825,9 +1910,9 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == parentManagementAttribute()) { + } else if (name == parentManagementAttribute) { const auto attribute = attributes->takeAt(i); - if (convertBoolean(attribute.value(), parentManagementAttribute(), false)) + if (convertBoolean(attribute.value(), parentManagementAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ParentManagement); ComplexTypeEntry::setParentManagementEnabled(true); } @@ -1848,23 +1933,49 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader ctype->setCodeGeneration(TypeEntry::GenerationDisabled); } +bool TypeSystemParser::parseConfiguration(StackElement topElement, + QXmlStreamAttributes *attributes) +{ + if (!isComplexTypeEntry(topElement) + && topElement != StackElement::EnumTypeEntry) { + m_error = u"<configuration> must be nested into a complex or enum type entry."_s; + return false; + } + QString condition; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == u"condition") { + condition = attributes->takeAt(i).value().toString(); + } + } + if (condition.isEmpty()) { + m_error = u"<configuration> requires a \"condition\" attribute."_s; + return false; + } + const auto topEntry = m_contextStack.top()->entry; + const auto configurableEntry = std::dynamic_pointer_cast<ConfigurableTypeEntry>(topEntry); + Q_ASSERT(configurableEntry); + configurableEntry->setConfigCondition(condition); + return true; +} + bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &, QString *name, QXmlStreamAttributes *attributes) { QString signature; QString rename; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == signatureAttribute()) { + if (name == signatureAttribute) { // Do not remove as it is needed for the type entry later on - signature = attributes->at(i).value().toString(); - } else if (name == renameAttribute()) { + signature = attributes->at(i).value().toString().simplified(); + } else if (name == renameAttribute) { rename = attributes->takeAt(i).value().toString(); } } if (signature.isEmpty()) { - m_error = msgMissingAttribute(signatureAttribute()); + m_error = msgMissingAttribute(signatureAttribute); return false; } @@ -1897,10 +2008,11 @@ bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &, bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *attributes) { + const bool isAddFunction = topElement == StackElement::AddFunction; const bool validParent = isTypeEntry(topElement) || topElement == StackElement::ModifyFunction || topElement == StackElement::ModifyField - || topElement == StackElement::AddFunction; + || isAddFunction; if (!validParent) { m_error = u"inject-documentation must be inside modify-function, add-function" "modify-field or other tags that creates a type"_s; @@ -1909,7 +2021,7 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace; TypeSystem::Language lang = TypeSystem::NativeCode; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"mode") { const auto attribute = attributes->takeAt(i); @@ -1919,7 +2031,7 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, return false; } mode = modeOpt.value(); - } else if (name == formatAttribute()) { + } else if (name == formatAttribute) { const auto attribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(attribute.value()); if (!langOpt.has_value()) { @@ -1933,7 +2045,17 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature; DocModification mod(mode, signature); mod.setFormat(lang); - m_contextStack.top()->docModifications << mod; + if (hasFileSnippetAttributes(attributes)) { + const auto snippetOptional = readFileSnippet(attributes); + if (!snippetOptional.has_value()) + return false; + mod.setCode(snippetOptional.value().content); + } + auto &top = m_contextStack.top(); + if (isAddFunction) + top->addedFunctions.last()->addDocModification(mod); + else + top->docModifications << mod; return true; } @@ -1946,13 +2068,13 @@ bool TypeSystemParser::parseModifyDocumentation(const ConditionalStreamReader &, || topElement == StackElement::ModifyField; if (!validParent) { m_error = u"modify-documentation must be inside modify-function, " - "modify-field or other tags that creates a type"_qs; + "modify-field or other tags that creates a type"_s; return false; } - const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute()); + const auto xpathIndex = indexOfAttribute(*attributes, xPathAttribute); if (xpathIndex == -1) { - m_error = msgMissingAttribute(xPathAttribute()); + m_error = msgMissingAttribute(xPathAttribute); return false; } @@ -1964,19 +2086,22 @@ bool TypeSystemParser::parseModifyDocumentation(const ConditionalStreamReader &, } // m_exceptionHandling -TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamReader &, +TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStreamReader &, const QVersionNumber &since, QXmlStreamAttributes *attributes) { TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; + QString subModuleOf; + QString namespaceBegin; + QString namespaceEnd; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == packageAttribute()) { + if (name == packageAttribute) { m_defaultPackage = attributes->takeAt(i).value().toString(); - } else if (name == defaultSuperclassAttribute()) { + } else if (name == defaultSuperclassAttribute) { m_defaultSuperclass = attributes->takeAt(i).value().toString(); - } else if (name == exceptionHandlingAttribute()) { + } else if (name == exceptionHandlingAttribute) { const auto attribute = attributes->takeAt(i); const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); if (exceptionOpt.has_value()) { @@ -1985,7 +2110,7 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == allowThreadAttribute()) { + } else if (name == allowThreadAttribute) { const auto attribute = attributes->takeAt(i); const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); if (allowThreadOpt.has_value()) { @@ -1994,7 +2119,7 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -2003,25 +2128,36 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } + } else if (name == subModuleOfAttribute) { + subModuleOf = attributes->takeAt(i).value().toString(); + } else if (name == "namespace-begin"_L1) { + namespaceBegin = attributes->takeAt(i).value().toString(); + } else if (name == "namespace-end"_L1) { + namespaceEnd = attributes->takeAt(i).value().toString(); } } if (m_defaultPackage.isEmpty()) { // Extending default, see addBuiltInContainerTypes() - auto *moduleEntry = const_cast<TypeSystemTypeEntry *>(m_context->db->defaultTypeSystemType()); + auto moduleEntry = std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->defaultTypeSystemType()); Q_ASSERT(moduleEntry); m_defaultPackage = moduleEntry->name(); return moduleEntry; } - auto *moduleEntry = - const_cast<TypeSystemTypeEntry *>(m_context->db->findTypeSystemType(m_defaultPackage)); - const bool add = moduleEntry == nullptr; + auto moduleEntry = + std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->findTypeSystemType(m_defaultPackage)); + const bool add = !moduleEntry; if (add) { - moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since, - currentParentTypeEntry()); + moduleEntry.reset(new TypeSystemTypeEntry(m_defaultPackage, since, + currentParentTypeEntry())); + moduleEntry->setSubModule(subModuleOf); } moduleEntry->setCodeGeneration(m_generate); moduleEntry->setSnakeCase(snakeCase); + if (!namespaceBegin.isEmpty()) + moduleEntry->setNamespaceBegin(namespaceBegin); + if (!namespaceEnd.isEmpty()) + moduleEntry->setNamespaceEnd(namespaceEnd); if ((m_generate == TypeEntry::GenerateForSubclass || m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty()) @@ -2037,12 +2173,12 @@ bool TypeSystemParser::loadTypesystem(const ConditionalStreamReader &, { QString typeSystemName; bool generateChild = true; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) + if (name == nameAttribute) typeSystemName = attributes->takeAt(i).value().toString(); - else if (name == generateAttribute()) - generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true); + else if (name == generateAttribute) + generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true); } if (typeSystemName.isEmpty()) { m_error = u"No typesystem name specified"_s; @@ -2063,9 +2199,9 @@ bool TypeSystemParser::parseRejectEnumValue(const ConditionalStreamReader &, m_error = u"<reject-enum-value> node must be used inside a <enum-type> node"_s; return false; } - const int nameIndex = indexOfAttribute(*attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(*attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString()); @@ -2080,7 +2216,7 @@ bool TypeSystemParser::parseReplaceArgumentType(const ConditionalStreamReader &, m_error = u"Type replacement can only be specified for argument modifications"_s; return false; } - const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute()); + const auto modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute); if (modifiedTypeIndex == -1) { m_error = u"Type replacement requires 'modified-type' attribute"_s; return false; @@ -2106,9 +2242,9 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, QString sourceFile; QString snippetLabel; TypeSystem::Language lang = TypeSystem::NativeCode; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto languageAttribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(languageAttribute.value()); if (!langOpt.has_value()) { @@ -2118,7 +2254,7 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, lang = langOpt.value(); } else if (name == u"file") { sourceFile = attributes->takeAt(i).value().toString(); - } else if (name == snippetAttribute()) { + } else if (name == snippetAttribute) { snippetLabel = attributes->takeAt(i).value().toString(); } } @@ -2131,14 +2267,18 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, return true; } - if (top->entry->hasTargetConversionRule() || top->entry->hasCustomConversion()) { - m_error = u"Types can have only one conversion rule"_s; - return false; + ValueTypeEntryPtr valueTypeEntry; + if (top->entry->isValue()) { + valueTypeEntry = std::static_pointer_cast<ValueTypeEntry>(top->entry); + if (valueTypeEntry->hasTargetConversionRule() || valueTypeEntry->hasCustomConversion()) { + m_error = u"Types can have only one conversion rule"_s; + return false; + } } // The old conversion rule tag that uses a file containing the conversion // will be kept temporarily for compatibility reasons. FIXME PYSIDE7: Remove - if (!sourceFile.isEmpty()) { + if (valueTypeEntry != nullptr && !sourceFile.isEmpty()) { if (m_generate != TypeEntry::GenerateForSubclass && m_generate != TypeEntry::GenerateNothing) { qWarning(lcShiboken, "Specifying conversion rules by \"file\" is deprecated."); @@ -2156,12 +2296,18 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, m_error = msgCannotFindSnippet(sourceFile, snippetLabel); return false; } - top->entry->setTargetConversionRule(conversionRuleOptional.value()); + valueTypeEntry->setTargetConversionRule(conversionRuleOptional.value()); } return true; } - auto *customConversion = new CustomConversion(top->entry); + auto customConversion = std::make_shared<CustomConversion>(top->entry); + if (top->entry->isPrimitive()) + std::static_pointer_cast<PrimitiveTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isContainer()) + std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isValue()) + std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion); customConversionsForReview.append(customConversion); return true; } @@ -2175,7 +2321,7 @@ bool TypeSystemParser::parseNativeToTarget(const ConditionalStreamReader &, return false; } CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; m_contextStack.top()->conversionCodeSnips.append(snip); return true; @@ -2192,7 +2338,7 @@ bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &, QString sourceTypeName; QString typeCheck; CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; const auto &top = m_contextStack.top(); @@ -2201,7 +2347,7 @@ bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &, if (parserState() == ParserState::ArgumentTargetToNativeConversion) return true; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"type") sourceTypeName = attributes->takeAt(i).value().toString(); @@ -2213,7 +2359,12 @@ bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &, m_error = u"Target to Native conversions must specify the input type with the 'type' attribute."_s; return false; } - top->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck); + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + customConversion->addTargetToNativeConversion(sourceTypeName, typeCheck); return true; } @@ -2222,7 +2373,7 @@ static bool parseIndex(const QString &index, int *result, QString *errorMessage) bool ok = false; *result = index.toInt(&ok); if (!ok) - *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index); + *errorMessage = QString::fromLatin1("Cannot convert '%1' to integer").arg(index); return ok; } @@ -2255,22 +2406,22 @@ bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &, QString renameTo; QString pyiType; bool resetAfterUse = false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == indexAttribute()) { + if (name == indexAttribute) { index = attributes->takeAt(i).value().toString(); - } else if (name == invalidateAfterUseAttribute()) { + } else if (name == invalidateAfterUseAttribute) { resetAfterUse = convertBoolean(attributes->takeAt(i).value(), - invalidateAfterUseAttribute(), false); - } else if (name == renameAttribute()) { + invalidateAfterUseAttribute, false); + } else if (name == renameAttribute) { renameTo = attributes->takeAt(i).value().toString(); - } else if (name == pyiTypeAttribute()) { + } else if (name == pyiTypeAttribute) { pyiType = attributes->takeAt(i).value().toString(); } } if (index.isEmpty()) { - m_error = msgMissingAttribute(indexAttribute()); + m_error = msgMissingAttribute(indexAttribute); return false; } @@ -2318,9 +2469,9 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, TypeSystem::Language lang = TypeSystem::TargetLangCode; std::optional<TypeSystem::Ownership> ownershipOpt; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto classAttribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(classAttribute.value()); if (!langOpt.has_value() || langOpt.value() == TypeSystem::ShellCode) { @@ -2328,7 +2479,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, return false; } lang = langOpt.value(); - } else if (name == ownershipAttribute()) { + } else if (name == ownershipAttribute) { const auto attribute = attributes->takeAt(i); ownershipOpt = ownershipFromFromAttribute(attribute.value()); if (!ownershipOpt.has_value()) { @@ -2339,7 +2490,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, } if (!ownershipOpt.has_value()) { - m_error = QStringLiteral("unspecified ownership"); + m_error = "unspecified ownership"_L1; return false; } auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last(); @@ -2366,9 +2517,9 @@ bool TypeSystemParser::parseRename(const ConditionalStreamReader &, return false; } - const int toIndex = indexOfAttribute(*attributes, toAttribute()); + const auto toIndex = indexOfAttribute(*attributes, toAttribute); if (toIndex == -1) { - m_error = msgMissingAttribute(toAttribute()); + m_error = msgMissingAttribute(toAttribute); return false; } const QString renamed_to = attributes->takeAt(toIndex).value().toString(); @@ -2380,22 +2531,22 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &, QXmlStreamAttributes *attributes) { FieldModification fm; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) { + if (name == nameAttribute) { fm.setName(attributes->takeAt(i).value().toString()); - } else if (name == removeAttribute()) { + } else if (name == removeAttribute) { fm.setRemoved(convertRemovalAttribute(attributes->takeAt(i).value())); - } else if (name == opaqueContainerFieldAttribute()) { + } else if (name == opaqueContainerFieldAttribute) { fm.setOpaqueContainer(convertBoolean(attributes->takeAt(i).value(), - opaqueContainerFieldAttribute(), false)); - } else if (name == readAttribute()) { - fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute(), true)); - } else if (name == writeAttribute()) { - fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true)); - } else if (name == renameAttribute()) { + opaqueContainerFieldAttribute, false)); + } else if (name == readAttribute) { + fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute, true)); + } else if (name == writeAttribute) { + fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute, true)); + } else if (name == renameAttribute) { fm.setRenamedToName(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -2407,7 +2558,7 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &, } } if (fm.name().isEmpty()) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } m_contextStack.top()->fieldMods << fm; @@ -2439,29 +2590,37 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, ", was=%1").arg(tagFromElement(topElement)); return false; } + + FunctionModification mod; + if (!(t == StackElement::AddFunction + ? parseBasicModifyFunctionAttributes(attributes, &mod) + : parseModifyFunctionAttributes(attributes, &mod))) { + return false; + } + QString originalSignature; QString returnType; bool staticFunction = false; bool classMethod = false; + bool pythonOverride = false; QString access; - int overloadNumber = TypeSystem::OverloadNumberUnset; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == u"signature") { - originalSignature = attributes->takeAt(i).value().toString(); + if (name == signatureAttribute) { + originalSignature = attributes->takeAt(i).value().toString().simplified(); } else if (name == u"return-type") { returnType = attributes->takeAt(i).value().toString(); - } else if (name == staticAttribute()) { + } else if (name == staticAttribute) { staticFunction = convertBoolean(attributes->takeAt(i).value(), - staticAttribute(), false); - } else if (name == classmethodAttribute()) { + staticAttribute, false); + } else if (name == classmethodAttribute) { classMethod = convertBoolean(attributes->takeAt(i).value(), - classmethodAttribute(), false); - } else if (name == accessAttribute()) { + classmethodAttribute, 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; + } else if (name == pythonOverrideAttribute) { + pythonOverride = convertBoolean(attributes->takeAt(i).value(), + pythonOverrideAttribute, false); } } @@ -2478,13 +2637,15 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, } AddedFunctionPtr func = AddedFunction::createAddedFunction(signature, returnType, &errorString); - if (func.isNull()) { + if (!func) { m_error = errorString; return false; } func->setStatic(staticFunction); func->setClassMethod(classMethod); + func->setPythonOverride(pythonOverride); + func->setTargetLangPackage(m_defaultPackage); // Create signature for matching modifications signature = TypeDatabase::normalizedSignature(originalSignature); @@ -2506,8 +2667,6 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, m_contextStack.top()->addedFunctionModificationIndex = m_contextStack.top()->functionMods.size(); - FunctionModification mod; - mod.setOverloadNumber(overloadNumber); if (!mod.setSignature(m_currentSignature, &m_error)) return false; mod.setOriginalSignature(originalSignature); @@ -2526,9 +2685,9 @@ bool TypeSystemParser::parseAddPyMethodDef(const ConditionalStreamReader &, } TypeSystemPyMethodDefEntry def; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) { + if (name == nameAttribute) { def.name = attributes->takeAt(i).value().toString(); } else if (name == u"doc") { def.doc = attributes->takeAt(i).value().toString(); @@ -2551,7 +2710,7 @@ bool TypeSystemParser::parseAddPyMethodDef(const ConditionalStreamReader &, m_error = u"add-pymethoddef requires at least a name and a function attribute"_s; return false; } - static_cast<ComplexTypeEntry *>(m_contextStack.top()->entry)->addPyMethodDef(def); + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addPyMethodDef(def); return true; } @@ -2565,9 +2724,9 @@ bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackEleme } TypeSystemProperty property; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) { + if (name == nameAttribute) { property.name = attributes->takeAt(i).value().toString(); } else if (name == u"get") { property.read = attributes->takeAt(i).value().toString(); @@ -2575,17 +2734,78 @@ bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackEleme property.type = attributes->takeAt(i).value().toString(); } else if (name == u"set") { property.write = attributes->takeAt(i).value().toString(); - } else if (name == generateGetSetDefAttribute()) { + } else if (name == generateGetSetDefAttribute) { property.generateGetSetDef = convertBoolean(attributes->takeAt(i).value(), - generateGetSetDefAttribute(), false); + generateGetSetDefAttribute, false); } } if (!property.isValid()) { m_error = u"<property> element is missing required attibutes (name/type/get)."_s; return false; } - static_cast<ComplexTypeEntry *>(m_contextStack.top()->entry)->addProperty(property); + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addProperty(property); + return true; +} + +// Parse basic attributes applicable to <add-function>/<declare-function>/<function> +// and <modify-function> (all that is not done by injected code). +bool TypeSystemParser::parseBasicModifyFunctionAttributes(QXmlStreamAttributes *attributes, + FunctionModification *mod) +{ + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == overloadNumberAttribute) { + int overloadNumber = TypeSystem::OverloadNumberUnset; + if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) + return false; + mod->setOverloadNumber(overloadNumber); + } + } + return true; +} + +// Parse attributes applicable to <declare-function>/<function> +// and <modify-function>. +bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attributes, + FunctionModification *mod) +{ + if (!parseBasicModifyFunctionAttributes(attributes, mod)) + return false; + + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == allowThreadAttribute) { + const QXmlStreamAttribute attribute = attributes->takeAt(i); + const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); + if (!allowThreadOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); + return false; + } + mod->setAllowThread(allowThreadOpt.value()); + } else if (name == exceptionHandlingAttribute) { + const auto attribute = attributes->takeAt(i); + const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); + if (!exceptionOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); + return false; + } + mod->setExceptionHandling(exceptionOpt.value()); + } else if (name == snakeCaseAttribute) { + const auto attribute = attributes->takeAt(i); + const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); + if (!snakeCaseOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); + return false; + } + mod->setSnakeCase(snakeCaseOpt.value()); + } else if (name == deprecatedAttribute) { + const bool deprecated = convertBoolean(attributes->takeAt(i).value(), + deprecatedAttribute, false); + mod->setModifierFlag(deprecated ? FunctionModification::Deprecated + : FunctionModification::Undeprecated); + } + } return true; } @@ -2603,61 +2823,24 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader } QString originalSignature; + FunctionModification mod; + if (!parseModifyFunctionAttributes(attributes, &mod)) + return false; + QString access; bool removed = false; QString rename; - bool deprecated = false; - bool isThread = false; - int overloadNumber = TypeSystem::OverloadNumberUnset; - TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; - TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified; - TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == u"signature") { - originalSignature = attributes->takeAt(i).value().toString(); - } else if (name == accessAttribute()) { + if (name == signatureAttribute) { + originalSignature = attributes->takeAt(i).value().toString().simplified(); + } else if (name == accessAttribute) { access = attributes->takeAt(i).value().toString(); - } else if (name == renameAttribute()) { + } else if (name == renameAttribute) { rename = attributes->takeAt(i).value().toString(); - } else if (name == removeAttribute()) { + } else if (name == removeAttribute) { removed = convertRemovalAttribute(attributes->takeAt(i).value()); - } else if (name == deprecatedAttribute()) { - deprecated = convertBoolean(attributes->takeAt(i).value(), - deprecatedAttribute(), false); - } else if (name == threadAttribute()) { - isThread = convertBoolean(attributes->takeAt(i).value(), - threadAttribute(), false); - } else if (name == allowThreadAttribute()) { - const QXmlStreamAttribute attribute = attributes->takeAt(i); - const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); - if (!allowThreadOpt.has_value()) { - m_error = msgInvalidAttributeValue(attribute); - return false; - } - allowThread = allowThreadOpt.value(); - } else if (name == exceptionHandlingAttribute()) { - const auto attribute = attributes->takeAt(i); - const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); - if (exceptionOpt.has_value()) { - exceptionHandling = exceptionOpt.value(); - } else { - qCWarning(lcShiboken, "%s", - qPrintable(msgInvalidAttributeValue(attribute))); - } - } else if (name == overloadNumberAttribute()) { - if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) - return false; - } else if (name == snakeCaseAttribute()) { - const auto attribute = attributes->takeAt(i); - const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); - if (snakeCaseOpt.has_value()) { - snakeCase = snakeCaseOpt.value(); - } else { - qCWarning(lcShiboken, "%s", - qPrintable(msgInvalidAttributeValue(attribute))); - } - } else if (name == virtualSlotAttribute()) { + } else if (name == virtualSlotAttribute || name == threadAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); } @@ -2666,7 +2849,7 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader // Child of global <function> const auto &top = m_contextStack.top(); if (originalSignature.isEmpty() && top->entry->isFunction()) { - auto f = static_cast<const FunctionTypeEntry *>(top->entry); + auto f = std::static_pointer_cast<const FunctionTypeEntry>(top->entry); originalSignature = f->signatures().value(0); } @@ -2682,13 +2865,9 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader return false; } - FunctionModification mod; if (!mod.setSignature(signature, &m_error)) return false; mod.setOriginalSignature(originalSignature); - mod.setExceptionHandling(exceptionHandling); - mod.setOverloadNumber(overloadNumber); - mod.setSnakeCase(snakeCase); m_currentSignature = signature; if (!access.isEmpty()) { @@ -2698,17 +2877,14 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader return false; } const FunctionModification::ModifierFlag m = modifierFlagOpt.value(); - if (m == FunctionModification::Final || m == FunctionModification::NonFinal) { + if (m == FunctionModification::NonFinal) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeValueWarning(reader, - accessAttribute(), access))); + accessAttribute, access))); } mod.setModifierFlag(m); } - if (deprecated) - mod.setModifierFlag(FunctionModification::Deprecated); - mod.setRemoved(removed); if (!rename.isEmpty()) { @@ -2716,10 +2892,6 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader mod.setModifierFlag(FunctionModification::Rename); } - mod.setIsThread(isThread); - if (allowThread != TypeSystem::AllowThread::Unspecified) - mod.setAllowThread(allowThread); - top->functionMods << mod; return true; } @@ -2732,7 +2904,7 @@ bool TypeSystemParser::parseReplaceDefaultExpression(const ConditionalStreamRead m_error = u"Replace default expression only allowed as child of argument modification"_s; return false; } - const int withIndex = indexOfAttribute(*attributes, u"with"); + const auto withIndex = indexOfAttribute(*attributes, u"with"); if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) { m_error = u"Default expression replaced with empty string. Use remove-default-expression instead."_s; return false; @@ -2753,9 +2925,9 @@ bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader } ReferenceCount rc; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == actionAttribute()) { + if (name == actionAttribute) { const QXmlStreamAttribute attribute = attributes->takeAt(i); const auto actionOpt = referenceCountFromAttribute(attribute.value()); if (!actionOpt.has_value()) { @@ -2790,13 +2962,13 @@ bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &, return false; } ArgumentOwner ao; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == indexAttribute()) { + if (name == indexAttribute) { const QString index = attributes->takeAt(i).value().toString(); if (!parseArgumentIndex(index, &ao.index, &m_error)) return false; - } else if (name == actionAttribute()) { + } else if (name == actionAttribute) { const auto action = attributes->takeAt(i); const auto actionOpt = argumentOwnerActionFromAttribute(action.value()); if (!actionOpt.has_value()) { @@ -2810,46 +2982,62 @@ bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &, return true; } -bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip) +std::optional<TypeSystemParser::Snippet> + TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes) { - QString fileName; - QString snippetLabel; - for (int i = attributes->size() - 1; i >= 0; --i) { + Snippet result; + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == u"file") { - fileName = attributes->takeAt(i).value().toString(); - } else if (name == snippetAttribute()) { - snippetLabel = attributes->takeAt(i).value().toString(); + if (name == fileAttribute) { + result.fileName = attributes->takeAt(i).value().toString(); + } else if (name == snippetAttribute) { + result.snippetLabel = attributes->takeAt(i).value().toString(); } } - if (fileName.isEmpty()) - return true; - const QString resolved = m_context->db->modifiedTypesystemFilepath(fileName, m_currentPath); + if (result.fileName.isEmpty()) { + m_error = "Snippet missing file name"_L1; + return std::nullopt; + } + const QString resolved = m_context->db->modifiedTypesystemFilepath(result.fileName, + m_currentPath); if (!QFile::exists(resolved)) { m_error = u"File for inject code not exist: "_s - + QDir::toNativeSeparators(fileName); - return false; + + QDir::toNativeSeparators(result.fileName); + return std::nullopt; } QFile codeFile(resolved); if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) { m_error = msgCannotOpenForReading(codeFile); - return false; + return std::nullopt; } - const auto codeOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel); + const auto contentOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()), + result.snippetLabel); codeFile.close(); - if (!codeOptional.has_value()) { - m_error = msgCannotFindSnippet(resolved, snippetLabel); - return false; + if (!contentOptional.has_value()) { + m_error = msgCannotFindSnippet(resolved, result.snippetLabel); + return std::nullopt; } + result.content = contentOptional.value(); + return result; +} + +bool TypeSystemParser::readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip) +{ + if (!hasFileSnippetAttributes(attributes)) + return true; // Expecting inline content. + const auto snippetOptional = readFileSnippet(attributes); + if (!snippetOptional.has_value()) + return false; + const auto snippet = snippetOptional.value(); - QString source = fileName; - if (!snippetLabel.isEmpty()) - source += u" ("_s + snippetLabel + u')'; + QString source = snippet.fileName; + if (!snippet.snippetLabel.isEmpty()) + source += " ("_L1 + snippet.snippetLabel + u')'; QString content; QTextStream str(&content); str << "// ========================================================================\n" "// START of custom code block [file: " - << source << "]\n" << codeOptional.value() + << source << "]\n" << snippet.content << "// END of custom code block [file: " << source << "]\n// ========================================================================\n"; snip->addCode(content); @@ -2871,11 +3059,11 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning; TypeSystem::Language lang = TypeSystem::TargetLangCode; CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto attribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(attribute.value()); if (!langOpt.has_value()) { @@ -2883,7 +3071,7 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, return false; } lang = langOpt.value(); - } else if (name == positionAttribute()) { + } else if (name == positionAttribute) { const auto attribute = attributes->takeAt(i); const auto positionOpt = codeSnipPositionFromAttribute(attribute.value()); if (!positionOpt.has_value()) { @@ -2897,29 +3085,36 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, snip.position = position; snip.language = lang; - if (topElement == StackElement::ModifyFunction - || topElement == StackElement::AddFunction) { + switch (topElement) { + case StackElement::ModifyFunction: + case StackElement::AddFunction: { FunctionModification &mod = m_contextStack.top()->functionMods.last(); mod.appendSnip(snip); if (!snip.code().isEmpty()) mod.setModifierFlag(FunctionModification::CodeInjection); - } else { - m_contextStack.top()->entry->addCodeSnip(snip); + } + break; + case StackElement::Root: + std::static_pointer_cast<TypeSystemTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip); + break; + default: + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip); + break; } return true; } bool TypeSystemParser::parseInclude(const ConditionalStreamReader &, StackElement topElement, - TypeEntry *entry, QXmlStreamAttributes *attributes) + const TypeEntryPtr &entry, QXmlStreamAttributes *attributes) { QString fileName; Include::IncludeType location = Include::IncludePath; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == fileNameAttribute()) { + if (name == fileNameAttribute) { fileName = attributes->takeAt(i).value().toString(); - } else if (name == locationAttribute()) { + } else if (name == locationAttribute) { const auto attribute = attributes->takeAt(i); const auto locationOpt = locationFromAttribute(attribute.value()); if (!locationOpt.has_value()) { @@ -2949,12 +3144,12 @@ bool TypeSystemParser::parseInclude(const ConditionalStreamReader &, bool TypeSystemParser::parseSystemInclude(const ConditionalStreamReader &, QXmlStreamAttributes *attributes) { - const int index = indexOfAttribute(*attributes, fileNameAttribute()); + const auto index = indexOfAttribute(*attributes, fileNameAttribute); if (index == -1) { - m_error = msgMissingAttribute(fileNameAttribute()); + m_error = msgMissingAttribute(fileNameAttribute); return false; } - TypeDatabase::instance()->addSystemInclude(attributes->takeAt(index).value().toString()); + TypeDatabase::instance()->addForceProcessSystemInclude(attributes->takeAt(index).value().toString()); return true; } @@ -2972,9 +3167,9 @@ TemplateInstance * "conversion-rule, native-to-target or add-conversion tags."_s; return nullptr; } - const int nameIndex = indexOfAttribute(*attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(*attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return nullptr; } return new TemplateInstance(attributes->takeAt(nameIndex).value().toString()); @@ -2989,11 +3184,11 @@ bool TypeSystemParser::parseReplace(const ConditionalStreamReader &, } QString from; QString to; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"from") from = attributes->takeAt(i).value().toString(); - else if (name == toAttribute()) + else if (name == toAttribute) to = attributes->takeAt(i).value().toString(); } m_templateInstance->addReplaceRule(from, to); @@ -3010,7 +3205,7 @@ bool TypeSystemParser::checkDuplicatedTypeEntry(const ConditionalStreamReader &r { if (t == StackElement::PrimitiveTypeEntry || t == StackElement::FunctionTypeEntry) return true; - const auto *duplicated = m_context->db->findType(name); + const auto duplicated = m_context->db->findType(name); if (!duplicated || duplicated->isNamespace()) return true; if (duplicated->isBuiltIn()) { @@ -3047,14 +3242,14 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack QXmlStreamAttributes attributes = reader.attributes(); VersionRange versionRange; - for (int i = attributes.size() - 1; i >= 0; --i) { + for (auto i = attributes.size() - 1; i >= 0; --i) { const auto name = attributes.at(i).qualifiedName(); - if (name == sinceAttribute()) { + if (name == sinceAttribute) { if (!parseVersion(attributes.takeAt(i).value().toString(), m_defaultPackage, &versionRange.since, &m_error)) { return false; } - } else if (name == untilAttribute()) { + } else if (name == untilAttribute) { if (!parseVersion(attributes.takeAt(i).value().toString(), m_defaultPackage, &versionRange.until, &m_error)) { return false; @@ -3063,7 +3258,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack } if (!m_defaultPackage.isEmpty() && !versionRange.isNull()) { - TypeDatabase* td = TypeDatabase::instance(); + auto *td = TypeDatabase::instance(); if (!td->checkApiVersion(m_defaultPackage, versionRange)) { ++m_ignoreDepth; return true; @@ -3088,7 +3283,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack } if (isTypeEntry(element) || element == StackElement::Root) - m_contextStack.push(StackElementContextPtr(new StackElementContext())); + m_contextStack.push(std::make_shared<StackElementContext>()); if (m_contextStack.isEmpty()) { m_error = msgNoRootTypeSystemEntry(); @@ -3101,11 +3296,11 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack if (isTypeEntry(element)) { QString name; if (element != StackElement::FunctionTypeEntry) { - const int nameIndex = indexOfAttribute(attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(attributes, nameAttribute); if (nameIndex != -1) { name = attributes.takeAt(nameIndex).value().toString(); } else if (element != StackElement::EnumTypeEntry) { // anonymous enum? - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } } @@ -3118,7 +3313,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack if (m_context->db->hasDroppedTypeEntries()) { const QString identifier = element == StackElement::FunctionTypeEntry - ? attributes.value(signatureAttribute()).toString() : name; + ? attributes.value(signatureAttribute).toString().simplified() : name; if (shouldDropTypeEntry(m_context->db, m_contextStack, identifier)) { m_currentDroppedEntryDepth = 1; if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { @@ -3142,14 +3337,15 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack // types (which we need to do in order to support fake meta objects) if (element != StackElement::PrimitiveTypeEntry && element != StackElement::FunctionTypeEntry) { - TypeEntry *tmp = m_context->db->findType(name); + TypeEntryPtr tmp = m_context->db->findType(name); if (tmp && !tmp->isNamespace()) qCWarning(lcShiboken).noquote().nospace() << "Duplicate type entry: '" << name << '\''; } if (element == StackElement::EnumTypeEntry) { - const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute()); + const auto enumIdentifiedByIndex = + indexOfAttribute(attributes, enumIdentifiedByValueAttribute); const QString identifiedByValue = enumIdentifiedByIndex != -1 ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString(); if (name.isEmpty()) { @@ -3208,7 +3404,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack case StackElement::InterfaceTypeEntry: { if (!checkRootElement()) return false; - auto *ce = new ObjectTypeEntry(name, versionRange.since, currentParentTypeEntry()); + auto ce = std::make_shared<ObjectTypeEntry>(name, versionRange.since, currentParentTypeEntry()); top->entry = ce; applyCommonAttributes(reader, top->entry, &attributes); applyComplexTypeAttributes(reader, ce, &attributes); @@ -3256,7 +3452,8 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack || element == StackElement::ConversionRule || element == StackElement::AddFunction || element == StackElement::DeclareFunction - || element == StackElement::Template; + || element == StackElement::Template + || element == StackElement::OpaqueContainer; if (!topLevel && m_stack.at(m_stack.size() - 2) == StackElement::Root) { m_error = u"Tag requires parent: '"_s + tagName.toString() + u'\''; @@ -3295,11 +3492,16 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack const auto topParent = m_stack.value(m_stack.size() - 3, StackElement::None); if (isTypeEntry(topParent)) { - const int replaceIndex = indexOfAttribute(attributes, replaceAttribute()); + const auto replaceIndex = indexOfAttribute(attributes, replaceAttribute); const bool replace = replaceIndex == -1 || convertBoolean(attributes.takeAt(replaceIndex).value(), - replaceAttribute(), true); - top->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace); + replaceAttribute, true); + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + customConversion->setReplaceOriginalTargetToNativeConversions(replace); } } break; @@ -3320,14 +3522,17 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack return false; break; case StackElement::SuppressedWarning: { - const int textIndex = indexOfAttribute(attributes, textAttribute()); + const auto textIndex = indexOfAttribute(attributes, textAttribute); if (textIndex == -1) { qCWarning(lcShiboken) << "Suppressed warning with no text specified"; } else { const QString suppressedWarning = attributes.takeAt(textIndex).value().toString(); - if (!m_context->db->addSuppressedWarning(suppressedWarning, &m_error)) + if (!m_context->db->addSuppressedWarning(suppressedWarning, + m_generate == TypeEntry::GenerateCode, + &m_error)) { return false; + } } } break; @@ -3396,32 +3601,39 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack return false; break; case StackElement::Rejection: - if (!addRejection(m_context->db, &attributes, &m_error)) + if (!addRejection(m_context->db, m_generate == TypeEntry::GenerateCode, + &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()); + const auto nameIndex = indexOfAttribute(attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } - m_templateEntry = - new TemplateEntry(attributes.takeAt(nameIndex).value().toString()); + m_templateEntry.reset(new TemplateEntry(attributes.takeAt(nameIndex).value().toString())); } break; case StackElement::InsertTemplate: m_templateInstance.reset(parseInsertTemplate(reader, topElement, &attributes)); - if (m_templateInstance.isNull()) + if (!m_templateInstance) return false; break; case StackElement::Replace: if (!parseReplace(reader, topElement, &attributes)) return false; break; + case StackElement::OpaqueContainer: + if (!parseOpaqueContainerElement(&attributes)) + case StackElement::Configuration: + if (!parseConfiguration(topElement, &attributes)) + return false; + break; default: break; // nada } |