diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-05 14:49:25 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-06 13:09:37 +0200 |
commit | 21e1bfafa1ed86adfa2e9ec4e990a582e4a20266 (patch) | |
tree | bf4e020ba25c6752c4e8674657898502cbf06e0c /sources/shiboken6 | |
parent | 429961686dfce2b2a3a5fba868a2664f281fc824 (diff) |
shiboken6: Refactor Handling of CustomConversion
CustomConversion can appear in PrimitiveTypeEntry, ContainerTypeEntry
and ValueTypeEntry. Move the field from the base class TypeEntry
there.
The deprecated QString targetConversionRule() was only implemented for
ValueTypeEntry; move it from the base class TypeEntry
there.
In the original code, CustomConversion was stored as a raw pointer in
TypeEntry. This is bad since TypeEntry are cloneable. Use a
QSharedPointer to prevent crashes.
Change-Id: Ia74219671bbd5792398f9711b4a020f5c9825b1b
Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/shiboken6')
17 files changed, 257 insertions, 133 deletions
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp index 6958c8c8f..d55a68fad 100644 --- a/sources/shiboken6/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp @@ -22,6 +22,7 @@ #include "smartpointertypeentry.h" #include "typedefentry.h" #include "typesystemtypeentry.h" +#include "valuetypeentry.h" #include "qtcompat.h" @@ -612,8 +613,8 @@ static void getCode(QStringList &code, const TypeEntry *type) else if (type->isTypeSystem()) getCode(code, static_cast<const TypeSystemTypeEntry *>(type)->codeSnips()); - CustomConversion *customConversion = type->customConversion(); - if (!customConversion) + auto customConversion = CustomConversion::getCustomConversion(type); + if (customConversion.isNull()) return; if (!customConversion->nativeToTargetConversion().isEmpty()) diff --git a/sources/shiboken6/ApiExtractor/containertypeentry.h b/sources/shiboken6/ApiExtractor/containertypeentry.h index 34ee08808..50c3c91c9 100644 --- a/sources/shiboken6/ApiExtractor/containertypeentry.h +++ b/sources/shiboken6/ApiExtractor/containertypeentry.h @@ -36,6 +36,10 @@ public: bool generateOpaqueContainer(const QString &instantiation) const; QString opaqueContainerName(const QString &instantiation) const; + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + TypeEntry *clone() const override; #ifndef QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/customconversion.h b/sources/shiboken6/ApiExtractor/customconversion.h index 172600d48..3a4766fea 100644 --- a/sources/shiboken6/ApiExtractor/customconversion.h +++ b/sources/shiboken6/ApiExtractor/customconversion.h @@ -5,6 +5,7 @@ #define CUSTOMCONVERSION_H #include "typesystem_enums.h" +#include "typesystem_typedefs.h" #include <QtCore/QList> #include <QtCore/QString> @@ -14,7 +15,7 @@ class TypeEntry; class CustomConversion { public: - CustomConversion(TypeEntry* ownerType); + explicit CustomConversion(const TypeEntry* ownerType); ~CustomConversion(); const TypeEntry* ownerType() const; @@ -56,6 +57,10 @@ public: void addTargetToNativeConversion(const QString& sourceTypeName, const QString& sourceTypeCheck, const QString& conversion = QString()); + + /// Return the custom conversion of a type; helper for type system parser + static CustomConversionPtr getCustomConversion(const TypeEntry *type); + private: struct CustomConversionPrivate; CustomConversionPrivate* m_d; diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index e91aef5cc..29fb23edb 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -931,3 +931,11 @@ QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func, << "\" for \"" << func->classQualifiedSignature() << "\" not found!"; return result; } + +QString msgMissingCustomConversion(const TypeEntry *t) +{ + QString result; + QTextStream(&result) << "Entry \"" << t->qualifiedCppName() + << "\" is missing a custom conversion."; + return result; +} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index 4a23c6487..4edab4b44 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -247,4 +247,6 @@ QString msgUnknownCheckFunction(const TypeEntry *t); QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func, const TypeEntry *t); +QString msgMissingCustomConversion(const TypeEntry *t); + #endif // MESSAGES_H diff --git a/sources/shiboken6/ApiExtractor/primitivetypeentry.h b/sources/shiboken6/ApiExtractor/primitivetypeentry.h index d0b50aa9c..e3e530f38 100644 --- a/sources/shiboken6/ApiExtractor/primitivetypeentry.h +++ b/sources/shiboken6/ApiExtractor/primitivetypeentry.h @@ -53,6 +53,10 @@ public: bool preferredTargetLangType() const; void setPreferredTargetLangType(bool b); + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + TypeEntry *clone() const override; #ifndef QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp index d1172ecc0..261ff4a6c 100644 --- a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp @@ -8,6 +8,7 @@ #include <modifications.h> #include <textstream.h> #include <complextypeentry.h> +#include <valuetypeentry.h> #include <qtcompat.h> @@ -64,7 +65,9 @@ void TestCodeInjections::testReadFile() QCOMPARE(classA->typeEntry()->codeSnips().size(), 1); QString code = classA->typeEntry()->codeSnips().constFirst().code(); QVERIFY(code.indexOf(expected) != -1); - code = classA->typeEntry()->targetConversionRule(); + QVERIFY(classA->typeEntry()->isValue()); + auto *vte = static_cast<const ValueTypeEntry *>(classA->typeEntry()); + code = vte->targetConversionRule(); QVERIFY(code.indexOf(expected) != -1); } diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp index 5f126c5f5..301dbdb95 100644 --- a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp @@ -7,6 +7,7 @@ #include <complextypeentry.h> #include <customconversion.h> #include <primitivetypeentry.h> +#include <valuetypeentry.h> #include <qtcompat.h> @@ -39,8 +40,10 @@ void TestConversionRuleTag::testConversionRuleTagWithFile() const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, u"A"); QVERIFY(classA); const ComplexTypeEntry* typeEntry = classA->typeEntry(); - QVERIFY(typeEntry->hasTargetConversionRule()); - QCOMPARE(typeEntry->targetConversionRule(), QLatin1String(conversionData)); + QVERIFY(typeEntry->isValue()); + auto *vte = static_cast<const ValueTypeEntry *>(typeEntry); + QVERIFY(vte->hasTargetConversionRule()); + QCOMPARE(vte->targetConversionRule(), QLatin1String(conversionData)); } void TestConversionRuleTag::testConversionRuleTagReplace() @@ -87,8 +90,8 @@ void TestConversionRuleTag::testConversionRuleTagReplace() PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(u"A"_s); QVERIFY(typeA); - CustomConversion* conversion = typeA->customConversion(); - QVERIFY(conversion); + QVERIFY(typeA->hasCustomConversion()); + auto conversion = typeA->customConversion(); QCOMPARE(typeA, conversion->ownerType()); QCOMPARE(conversion->nativeToTargetConversion().simplified(), @@ -153,8 +156,10 @@ if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\ auto *classA = AbstractMetaClass::findClass(builder->classes(), u"Date"); QVERIFY(classA); - CustomConversion* conversion = classA->typeEntry()->customConversion(); - QVERIFY(conversion); + QVERIFY(classA->typeEntry()->isValue()); + auto *vte = static_cast<const ValueTypeEntry *>(classA->typeEntry()); + QVERIFY(vte->hasCustomConversion()); + auto conversion = vte->customConversion(); QCOMPARE(conversion->nativeToTargetConversion(), QString()); @@ -216,8 +221,8 @@ void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate() PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(u"A"_s); QVERIFY(typeA); - CustomConversion* conversion = typeA->customConversion(); - QVERIFY(conversion); + QVERIFY(typeA->hasCustomConversion()); + auto conversion = typeA->customConversion(); QCOMPARE(typeA, conversion->ownerType()); QCOMPARE(conversion->nativeToTargetConversion().trimmed(), diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 9db414563..50cd01695 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -53,7 +53,7 @@ class TypeEntryPrivate public: explicit TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, const TypeEntry *parent); - virtual ~TypeEntryPrivate(); + virtual ~TypeEntryPrivate() = default; QString shortName() const; @@ -66,9 +66,7 @@ public: mutable QString m_cachedTargetLangEntryName; // "Bar" IncludeList m_extraIncludes; Include m_include; - QString m_targetConversionRule; QVersionNumber m_version; - CustomConversion *m_customConversion = nullptr; SourceLocation m_sourceLocation; // XML file TypeEntry::CodeGeneration m_codeGeneration = TypeEntry::GenerateCode; TypeEntry *m_viewOn = nullptr; @@ -91,11 +89,6 @@ TypeEntryPrivate::TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, { } -TypeEntryPrivate::~TypeEntryPrivate() -{ - delete m_customConversion; -} - TypeEntry::TypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, const TypeEntry *parent) : TypeEntry(new TypeEntryPrivate(entryName, t, vr, parent)) @@ -143,26 +136,11 @@ void TypeEntry::setInclude(const Include &inc) } } -void TypeEntry::setTargetConversionRule(const QString &conversionRule) -{ - m_d->m_targetConversionRule = conversionRule; -} - -QString TypeEntry::targetConversionRule() const -{ - return m_d->m_targetConversionRule; -} - QVersionNumber TypeEntry::version() const { return m_d->m_version; } -bool TypeEntry::hasTargetConversionRule() const -{ - return !m_d->m_targetConversionRule.isEmpty(); -} - bool TypeEntry::isCppPrimitive() const { if (!isPrimitive()) @@ -567,21 +545,6 @@ bool TypeEntry::isComplex() const return false; } -bool TypeEntry::hasCustomConversion() const -{ - return m_d->m_customConversion != nullptr; -} - -void TypeEntry::setCustomConversion(CustomConversion* customConversion) -{ - m_d->m_customConversion = customConversion; -} - -CustomConversion* TypeEntry::customConversion() const -{ - return m_d->m_customConversion; -} - TypeEntry *TypeEntry::viewOn() const { return m_d->m_viewOn; @@ -885,8 +848,9 @@ public: } QString m_defaultConstructor; - uint m_preferredTargetLangType : 1; + CustomConversionPtr m_customConversion; PrimitiveTypeEntry* m_referencedTypeEntry = nullptr; + uint m_preferredTargetLangType : 1; }; PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, @@ -961,6 +925,24 @@ void PrimitiveTypeEntry::setPreferredTargetLangType(bool b) d->m_preferredTargetLangType = b; } +bool PrimitiveTypeEntry::hasCustomConversion() const +{ + S_D(const PrimitiveTypeEntry); + return !d->m_customConversion.isNull(); +} + +void PrimitiveTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(PrimitiveTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr PrimitiveTypeEntry::customConversion() const +{ + S_D(const PrimitiveTypeEntry); + return d->m_customConversion; +} + TypeEntry *PrimitiveTypeEntry::clone() const { S_D(const PrimitiveTypeEntry); @@ -1805,6 +1787,7 @@ public: } OpaqueContainers m_opaqueContainers; + CustomConversionPtr m_customConversion; ContainerTypeEntry::ContainerKind m_containerKind; }; @@ -1852,6 +1835,24 @@ QString ContainerTypeEntry::opaqueContainerName(const QString &instantiation) co return it != d->m_opaqueContainers.cend() ? it->name : QString{}; } +bool ContainerTypeEntry::hasCustomConversion() const +{ + S_D(const ContainerTypeEntry); + return !d->m_customConversion.isNull(); +} + +void ContainerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(ContainerTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr ContainerTypeEntry::customConversion() const +{ + S_D(const ContainerTypeEntry); + return d->m_customConversion; +} + TypeEntry *ContainerTypeEntry::clone() const { S_D(const ContainerTypeEntry); @@ -2126,12 +2127,58 @@ void NamespaceTypeEntry::setGenerateUsing(bool generateUsing) } // ----------------- ValueTypeEntry + +class ValueTypeEntryPrivate : public ComplexTypeEntryPrivate +{ +public: + using ComplexTypeEntryPrivate::ComplexTypeEntryPrivate; + + QString m_targetConversionRule; + CustomConversionPtr m_customConversion; +}; + ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, const TypeEntry *parent) : - ComplexTypeEntry(entryName, BasicValueType, vr, parent) + ComplexTypeEntry(new ValueTypeEntryPrivate(entryName, BasicValueType, vr, parent)) { } +bool ValueTypeEntry::hasCustomConversion() const +{ + S_D(const ValueTypeEntry); + return !d->m_customConversion.isNull(); +} + +void ValueTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(ValueTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr ValueTypeEntry::customConversion() const +{ + S_D(const ValueTypeEntry); + return d->m_customConversion; +} + +void ValueTypeEntry::setTargetConversionRule(const QString &conversionRule) +{ + S_D(ValueTypeEntry); + d->m_targetConversionRule = conversionRule; +} + +QString ValueTypeEntry::targetConversionRule() const +{ + S_D(const ValueTypeEntry); + return d->m_targetConversionRule; +} + +bool ValueTypeEntry::hasTargetConversionRule() const +{ + S_D(const ValueTypeEntry); + return !d->m_targetConversionRule.isEmpty(); +} + bool ValueTypeEntry::isValue() const { return true; @@ -2139,8 +2186,8 @@ bool ValueTypeEntry::isValue() const TypeEntry *ValueTypeEntry::clone() const { - S_D(const ComplexTypeEntry); - return new ValueTypeEntry(new ComplexTypeEntryPrivate(*d)); + S_D(const ValueTypeEntry); + return new ValueTypeEntry(new ValueTypeEntryPrivate(*d)); } ValueTypeEntry::ValueTypeEntry(ComplexTypeEntryPrivate *d) : @@ -2179,11 +2226,9 @@ struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPriva QString conversion; }; -CustomConversion::CustomConversion(TypeEntry* ownerType) +CustomConversion::CustomConversion(const TypeEntry *ownerType) + : m_d(new CustomConversionPrivate(ownerType)) { - m_d = new CustomConversionPrivate(ownerType); - if (ownerType) - ownerType->setCustomConversion(this); } CustomConversion::~CustomConversion() @@ -2302,6 +2347,17 @@ void CustomConversion::TargetToNativeConversion::setConversion(const QString& co m_d->conversion = conversion; } +CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntry *type) +{ + if (type->isPrimitive()) + return static_cast<const PrimitiveTypeEntry *>(type)->customConversion(); + if (type->isContainer()) + return static_cast<const ContainerTypeEntry *>(type)->customConversion(); + if (type->isValue()) + return static_cast<const ValueTypeEntry *>(type)->customConversion(); + return {}; +} + // ----------------- FunctionTypeEntry class FunctionTypeEntryPrivate : public TypeEntryPrivate { @@ -2426,7 +2482,6 @@ void TypeEntry::formatDebug(QDebug &debug) const FORMAT_NONEMPTY_STRING("package", m_d->m_targetLangPackage) FORMAT_BOOL("stream", m_d->m_stream) FORMAT_BOOL("built-in", m_d->m_builtin) - FORMAT_NONEMPTY_STRING("targetConversionRule", m_d->m_targetConversionRule) if (m_d->m_viewOn) debug << ", views=" << m_d->m_viewOn->name(); if (!m_d->m_version.isNull() && m_d->m_version > QVersionNumber(0, 0)) diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h index 5e22af5f8..e83f03b67 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.h +++ b/sources/shiboken6/ApiExtractor/typesystem.h @@ -12,7 +12,6 @@ #include <QtCore/QScopedPointer> class AbstractMetaType; -class CustomConversion; class CustomTypeEntry; class PrimitiveTypeEntry; class SourceLocation; @@ -160,24 +159,10 @@ public: Include include() const; void setInclude(const Include &inc); - // FIXME PYSIDE7: Remove - /// Set the target type conversion rule - void setTargetConversionRule(const QString& conversionRule); - - /// Returns the target type conversion rule - QString targetConversionRule() const; - QVersionNumber version() const; - /// TODO-CONVERTER: mark as deprecated - bool hasTargetConversionRule() const; - bool isCppPrimitive() const; - bool hasCustomConversion() const; - void setCustomConversion(CustomConversion* customConversion); - CustomConversion* customConversion() const; - // View on: Type to use for function argument conversion, fex // std::string_view -> std::string for foo(std::string_view). // cf AbstractMetaType::viewOn() diff --git a/sources/shiboken6/ApiExtractor/typesystem_typedefs.h b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h index 3c1ad53f8..89081b9ea 100644 --- a/sources/shiboken6/ApiExtractor/typesystem_typedefs.h +++ b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h @@ -13,6 +13,7 @@ class CodeSnip; class DocModification; struct AddedFunction; +class CustomConversion; class FieldModification; class FunctionModification; class TypeEntry; @@ -20,6 +21,7 @@ class TypeEntry; using AddedFunctionPtr = QSharedPointer<AddedFunction>; using AddedFunctionList = QList<AddedFunctionPtr>; using CodeSnipList = QList<CodeSnip>; +using CustomConversionPtr = QSharedPointer<CustomConversion>; using DocModificationList = QList<DocModification>; using FieldModificationList = QList<FieldModification>; using FunctionModificationList = QList<FunctionModification>; diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index 3979d462a..310976550 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -137,7 +137,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 "^..$" @@ -876,7 +876,7 @@ 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)) { + for (const auto &customConversion : qAsConst(customConversionsForReview)) { const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions(); for (CustomConversion::TargetToNativeConversion *toNative : toNatives) toNative->setSourceType(m_context->db->findType(toNative->sourceTypeName())); @@ -931,22 +931,23 @@ bool TypeSystemParser::endElement(StackElement element) 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.isNull()) { + 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: { @@ -2156,14 +2157,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; + ValueTypeEntry *valueTypeEntry = nullptr; + if (top->entry->isValue()) { + valueTypeEntry = static_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."); @@ -2181,12 +2186,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); + CustomConversionPtr customConversion(new CustomConversion(top->entry)); + if (top->entry->isPrimitive()) + static_cast<PrimitiveTypeEntry *>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isContainer()) + static_cast<ContainerTypeEntry *>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isValue()) + static_cast<ValueTypeEntry *>(top->entry)->setCustomConversion(customConversion); customConversionsForReview.append(customConversion); return true; } @@ -2238,7 +2249,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.isNull()) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + customConversion->addTargetToNativeConversion(sourceTypeName, typeCheck); return true; } @@ -3331,7 +3347,12 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack const bool replace = replaceIndex == -1 || convertBoolean(attributes.takeAt(replaceIndex).value(), replaceAttribute(), true); - top->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace); + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (customConversion.isNull()) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + customConversion->setReplaceOriginalTargetToNativeConversions(replace); } } break; diff --git a/sources/shiboken6/ApiExtractor/valuetypeentry.h b/sources/shiboken6/ApiExtractor/valuetypeentry.h index 15cac1a79..af181a24f 100644 --- a/sources/shiboken6/ApiExtractor/valuetypeentry.h +++ b/sources/shiboken6/ApiExtractor/valuetypeentry.h @@ -12,6 +12,20 @@ public: explicit ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, const TypeEntry *parent); + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + + // FIXME PYSIDE7: Remove + /// Set the target type conversion rule + void setTargetConversionRule(const QString &conversionRule); + + /// Returns the target type conversion rule + QString targetConversionRule() const; + + /// TODO-CONVERTER: mark as deprecated + bool hasTargetConversionRule() const; + bool isValue() const override; TypeEntry *clone() const override; diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 7921f6865..6724a4ab5 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -32,6 +32,7 @@ #include <primitivetypeentry.h> #include <smartpointertypeentry.h> #include <typesystemtypeentry.h> +#include <valuetypeentry.h> #include <parser/enumvalue.h> #include "qtcompat.h" @@ -679,9 +680,12 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon } // python conversion rules - if (typeEntry->hasTargetConversionRule()) { - s << "// Python Conversion\n"; - s << typeEntry->targetConversionRule() << '\n'; + if (typeEntry->isValue()) { + auto *vte = static_cast<const ValueTypeEntry *>(typeEntry); + if (vte->hasTargetConversionRule()) { + s << "// Python Conversion\n"; + s << vte->targetConversionRule() << '\n'; + } } if (classContext.useWrapper()) { @@ -1942,13 +1946,16 @@ return result;)"; writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv); } - writeCustomConverterFunctions(s, typeEntry->customConversion()); + if (typeEntry->isValue()) { + auto *vte = static_cast<const ValueTypeEntry *>(typeEntry); + writeCustomConverterFunctions(s, vte->customConversion()); + } } void CppGenerator::writeCustomConverterFunctions(TextStream &s, - const CustomConversion *customConversion) const + const CustomConversionPtr &customConversion) const { - if (!customConversion) + if (customConversion.isNull()) return; const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions(); if (toCppConversions.isEmpty()) @@ -2071,13 +2078,17 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv); } - writeCustomConverterRegister(s, typeEntry->customConversion(), u"converter"_s); + if (typeEntry->isValue()) { + auto *vte = static_cast<const ValueTypeEntry *>(typeEntry); + writeCustomConverterRegister(s, vte->customConversion(), u"converter"_s); + } } -void CppGenerator::writeCustomConverterRegister(TextStream &s, const CustomConversion *customConversion, +void CppGenerator::writeCustomConverterRegister(TextStream &s, + const CustomConversionPtr &customConversion, const QString &converterVar) { - if (!customConversion) + if (customConversion.isNull()) return; const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions(); if (toCppConversions.isEmpty()) @@ -3417,7 +3428,8 @@ static void replaceCppToPythonVariables(QString &code, const QString &typeName, code.replace(u"%out"_s, u"pyOut"_s); } -void CppGenerator::writeCppToPythonFunction(TextStream &s, const CustomConversion *customConversion) const +void CppGenerator::writeCppToPythonFunction(TextStream &s, + const CustomConversionPtr &customConversion) const { QString code = customConversion->nativeToTargetConversion(); auto *ownerType = customConversion->ownerType(); @@ -3427,18 +3439,16 @@ void CppGenerator::writeCppToPythonFunction(TextStream &s, const CustomConversio } void CppGenerator::writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const { - const CustomConversion *customConversion = containerType.typeEntry()->customConversion(); - if (!customConversion) { + Q_ASSERT(containerType.typeEntry()->isContainer()); + auto *cte = static_cast<const ContainerTypeEntry *>(containerType.typeEntry()); + if (!cte->hasCustomConversion()) { QString m; QTextStream(&m) << "Can't write the C++ to Python conversion function for container type '" << containerType.typeEntry()->qualifiedCppName() << "' - no conversion rule was defined for it in the type system."; throw Exception(m); } - if (!containerType.typeEntry()->isContainer()) { - writeCppToPythonFunction(s, customConversion); - return; - } + const auto customConversion = cte->customConversion(); QString code = customConversion->nativeToTargetConversion(); for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) { const AbstractMetaType &type = containerType.instantiations().at(i); @@ -3565,11 +3575,14 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const { - const CustomConversion *customConversion = containerType.typeEntry()->customConversion(); - if (!customConversion) { + Q_ASSERT(containerType.typeEntry()->isContainer()); + auto *cte = static_cast<const ContainerTypeEntry *>(containerType.typeEntry()); + if (!cte->hasCustomConversion()) { //qFatal return; } + + const auto customConversion = cte->customConversion(); const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions(); if (toCppConversions.isEmpty()) { //qFatal @@ -4293,7 +4306,7 @@ void CppGenerator::writeSpecialCastFunction(TextStream &s, const AbstractMetaCla } void CppGenerator::writePrimitiveConverterInitialization(TextStream &s, - const CustomConversion *customConversion) + const CustomConversionPtr &customConversion) { const TypeEntry *type = customConversion->ownerType(); QString converter = converterObject(type); @@ -6651,10 +6664,10 @@ bool CppGenerator::finishGeneration() } } - const QList<const CustomConversion *> &typeConversions = getPrimitiveCustomConversions(); + const QList<CustomConversionPtr> &typeConversions = getPrimitiveCustomConversions(); if (!typeConversions.isEmpty()) { s << "\n// Primitive Type converters.\n\n"; - for (const CustomConversion *conversion : typeConversions) { + for (const auto &conversion : typeConversions) { s << "// C++ to Python conversion for primitive type '" << conversion->ownerType()->qualifiedCppName() << "'.\n"; writeCppToPythonFunction(s, conversion); writeCustomConverterFunctions(s, conversion); @@ -6747,7 +6760,7 @@ bool CppGenerator::finishGeneration() if (!typeConversions.isEmpty()) { s << '\n'; - for (const CustomConversion *conversion : typeConversions) { + for (const auto &conversion : typeConversions) { writePrimitiveConverterInitialization(s, conversion); s << '\n'; } diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 615a0f775..4556849fc 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -96,10 +96,11 @@ private: void writeConverterFunctions(TextStream &s, const AbstractMetaClass *metaClass, const GeneratorContext &classContext) const; void writeCustomConverterFunctions(TextStream &s, - const CustomConversion *customConversion) const; + const CustomConversionPtr &customConversion) const; void writeConverterRegister(TextStream &s, const AbstractMetaClass *metaClass, const GeneratorContext &classContext) const; - static void writeCustomConverterRegister(TextStream &s, const CustomConversion *customConversion, + static void writeCustomConverterRegister(TextStream &s, + const CustomConversionPtr &customConversion, const QString &converterVar); void writeContainerConverterFunctions(TextStream &s, @@ -295,7 +296,7 @@ private: /// Writes a C++ to Python conversion function. void writeCppToPythonFunction(TextStream &s, const QString &code, const QString &sourceTypeName, QString targetTypeName = QString()) const; - void writeCppToPythonFunction(TextStream &s, const CustomConversion *customConversion) const; + void writeCppToPythonFunction(TextStream &s, const CustomConversionPtr &customConversion) const; void writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const; /// Writes a Python to C++ conversion function. @@ -451,7 +452,7 @@ private: static void writeSpecialCastFunction(TextStream &s, const AbstractMetaClass *metaClass); static void writePrimitiveConverterInitialization(TextStream &s, - const CustomConversion *customConversion); + const CustomConversionPtr &customConversion); static void writeFlagsConverterInitialization(TextStream &s, const FlagsTypeEntry *enumType); static void writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum); QString writeContainerConverterInitialization(TextStream &s, const AbstractMetaType &type) const; diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 264c8cfea..93c35d2fa 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -29,6 +29,7 @@ #include <namespacetypeentry.h> #include <primitivetypeentry.h> #include <pythontypeentry.h> +#include <valuetypeentry.h> #include <iostream> @@ -250,10 +251,11 @@ ShibokenGenerator::FunctionGeneration AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntry *t) const { - if (!generateImplicitConversions()) + if (!generateImplicitConversions() || !t->isValue()) return {}; - auto *customConversion = t->customConversion(); - if (customConversion && customConversion->replaceOriginalTargetToNativeConversions()) + auto *vte = static_cast<const ValueTypeEntry *>(t); + auto customConversion = vte->customConversion(); + if (!customConversion.isNull() && customConversion->replaceOriginalTargetToNativeConversions()) return {}; auto result = api().implicitConversions(t); @@ -1174,15 +1176,13 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter return extConvs; } -QList<const CustomConversion *> ShibokenGenerator::getPrimitiveCustomConversions() +QList<CustomConversionPtr> ShibokenGenerator::getPrimitiveCustomConversions() { - QList<const CustomConversion *> conversions; + QList<CustomConversionPtr> conversions; const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); for (const PrimitiveTypeEntry *type : primitiveTypeList) { - if (!type->shouldGenerate() || !type->isUserPrimitive() || !type->customConversion()) - continue; - - conversions << type->customConversion(); + if (type->shouldGenerate() && type->isUserPrimitive() && type->hasCustomConversion()) + conversions << type->customConversion(); } return conversions; } diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h index 767af579d..24c866f33 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.h +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h @@ -6,6 +6,7 @@ #include <generator.h> +#include "typesystem_typedefs.h" #include "customconversion.h" #include <QtCore/QRegularExpression> @@ -298,7 +299,7 @@ protected: ExtendedConverterData getExtendedConverters() const; /// Returns a list of converters for the non wrapper types of the current module. - static QList<const CustomConversion *> getPrimitiveCustomConversions() ; + static QList<CustomConversionPtr> getPrimitiveCustomConversions(); /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments. bool pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const; |