diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-09-30 12:27:12 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-02-05 11:48:54 +0100 |
commit | 919ee9a8677a1f0838af3f7d3d59e18179c42242 (patch) | |
tree | af0b74dcf67511477199d5dedb267cd51c3e88eb | |
parent | 242f0fa7269e9baf331679dc413c28471b1f7d05 (diff) |
shiboken: Make it possible to specify smartpointer instantiations
Add an attribute "instantiations" to the smart-pointer-type element,
which allows to specify a comma-separated list of instantiation types
for which wrappers should be generated in the module.
This avoids clashes of indexes.
Task-number: PYSIDE-1024
Change-Id: Iac4b93b91ca4982064beef4c5abafc547052e7f1
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r-- | sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp | 68 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/messages.cpp | 17 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/messages.h | 4 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.cpp | 5 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.h | 1 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystemparser.cpp | 68 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystemparser.h | 4 | ||||
-rw-r--r-- | sources/shiboken2/doc/typesystem_specifying_types.rst | 11 | ||||
-rw-r--r-- | sources/shiboken2/tests/smartbinding/typesystem_smart.xml | 3 |
9 files changed, 159 insertions, 22 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 59ea3b079..514027242 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -2286,6 +2286,26 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo return nullptr; } + QScopedPointer<AbstractMetaType> metaType(new AbstractMetaType); + metaType->setIndirectionsV(typeInfo.indirectionsV()); + metaType->setReferenceType(typeInfo.referenceType()); + metaType->setConstant(typeInfo.isConstant()); + metaType->setVolatile(typeInfo.isVolatile()); + metaType->setOriginalTypeDescription(_typei.toString()); + + const auto &templateArguments = typeInfo.instantiations(); + for (int t = 0, size = templateArguments.size(); t < size; ++t) { + const TypeInfo &ti = templateArguments.at(t); + AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + if (!targType) { + if (errorMessageIn) + *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); + return nullptr; + } + + metaType->addInstantiation(targType, true); + } + if (types.size() > 1) { const bool sameType = std::all_of(types.cbegin() + 1, types.cend(), [typeEntryType](const TypeEntry *e) { @@ -2295,43 +2315,51 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo *errorMessageIn = msgAmbiguousVaryingTypesFound(qualifiedName, types); return nullptr; } - // Ambiguous primitive types are possible (when including type systems). - if (typeEntryType != TypeEntry::PrimitiveType) { + // Ambiguous primitive/smart pointer types are possible (when + // including type systems). + if (typeEntryType != TypeEntry::PrimitiveType + && typeEntryType != TypeEntry::SmartPointerType) { if (errorMessageIn) *errorMessageIn = msgAmbiguousTypesFound(qualifiedName, types); return nullptr; } } - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(type); - metaType->setIndirectionsV(typeInfo.indirectionsV()); - metaType->setReferenceType(typeInfo.referenceType()); - metaType->setConstant(typeInfo.isConstant()); - metaType->setVolatile(typeInfo.isVolatile()); - metaType->setOriginalTypeDescription(_typei.toString()); - - const auto &templateArguments = typeInfo.instantiations(); - for (int t = 0, size = templateArguments.size(); t < size; ++t) { - const TypeInfo &ti = templateArguments.at(t); - AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); - if (!targType) { + if (typeEntryType == TypeEntry::SmartPointerType) { + // Find a matching instantiation + if (metaType->instantiations().size() != 1) { if (errorMessageIn) - *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); - delete metaType; + *errorMessageIn = msgInvalidSmartPointerType(_typei); return nullptr; } - - metaType->addInstantiation(targType, true); + auto instantiationType = metaType->instantiations().constFirst()->typeEntry(); + if (instantiationType->type() == TypeEntry::TemplateArgumentType) { + // Member functions of the template itself, SharedPtr(const SharedPtr &) + type = instantiationType; + } else { + auto it = std::find_if(types.cbegin(), types.cend(), + [instantiationType](const TypeEntry *e) { + auto smartPtr = static_cast<const SmartPointerTypeEntry *>(e); + return smartPtr->matchesInstantiation(instantiationType); + }); + if (it == types.cend()) { + if (errorMessageIn) + *errorMessageIn = msgCannotFindSmartPointerInstantion(_typei); + return nullptr; + } + type =*it; + } } + metaType->setTypeEntry(type); + // The usage pattern *must* be decided *after* the possible template // instantiations have been determined, or else the absence of // such instantiations will break the caching scheme of // AbstractMetaType::cppSignature(). metaType->decideUsagePattern(); - return metaType; + return metaType.take(); } AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp index fb9dd573a..fa83b77db 100644 --- a/sources/shiboken2/ApiExtractor/messages.cpp +++ b/sources/shiboken2/ApiExtractor/messages.cpp @@ -219,6 +219,23 @@ QString msgCannotFindTypeEntry(const QString &t) return QLatin1String("Cannot find type entry for \"") + t + QLatin1String("\"."); } +QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType) +{ + return QLatin1String("Cannot find type entry \"") + t + + QLatin1String("\" for instantiation of \"") + smartPointerType + QLatin1String("\"."); +} + +QString msgInvalidSmartPointerType(const TypeInfo &i) +{ + return QLatin1String("Invalid smart pointer type \"") + i.toString() + QLatin1String("\"."); +} + +QString msgCannotFindSmartPointerInstantion(const TypeInfo &i) +{ + return QLatin1String("Cannot find instantiation of smart pointer type for \"") + + i.toString() + QLatin1String("\"."); +} + QString msgCannotTranslateTemplateArgument(int i, const TypeInfo &typeInfo, const QString &why) diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h index 944cb231e..563d412ee 100644 --- a/sources/shiboken2/ApiExtractor/messages.h +++ b/sources/shiboken2/ApiExtractor/messages.h @@ -83,6 +83,10 @@ QString msgUnableToTranslateType(const TypeInfo &typeInfo, QString msgCannotFindTypeEntry(const QString &t); +QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType); +QString msgInvalidSmartPointerType(const TypeInfo &i); +QString msgCannotFindSmartPointerInstantion(const TypeInfo &i); + QString msgCannotTranslateTemplateArgument(int i, const TypeInfo &typeInfo, const QString &why); diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index f8199622a..a29fa6dcf 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -956,6 +956,11 @@ TypeEntry *SmartPointerTypeEntry::clone() const SmartPointerTypeEntry::SmartPointerTypeEntry(const SmartPointerTypeEntry &) = default; +bool SmartPointerTypeEntry::matchesInstantiation(const TypeEntry *e) const +{ + return m_instantiations.isEmpty() || m_instantiations.contains(e); +} + NamespaceTypeEntry::NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, const TypeEntry *parent) : ComplexTypeEntry(entryName, NamespaceType, vr, parent) diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 8d162a732..544673e4d 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -1488,6 +1488,7 @@ public: Instantiations instantiations() const { return m_instantiations; } void setInstantiations(const Instantiations &i) { m_instantiations = i; } + bool matchesInstantiation(const TypeEntry *e) const; #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index e2450e6b4..0e28e8602 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -650,6 +650,14 @@ bool TypeSystemParser::parse(QXmlStreamReader &reader) { m_error.clear(); m_currentPath.clear(); + m_smartPointerInstantiations.clear(); + const bool result = parseXml(reader) && setupSmartPointerInstantiations(); + m_smartPointerInstantiations.clear(); + return result; +} + +bool TypeSystemParser::parseXml(QXmlStreamReader &reader) +{ const QString fileName = readerFileName(reader); if (!fileName.isEmpty()) m_currentPath = QFileInfo(fileName).absolutePath(); @@ -693,6 +701,62 @@ bool TypeSystemParser::parse(QXmlStreamReader &reader) return true; } +// Split a type list potentially with template types +// "A<B,C>,D" -> ("A<B,C>", "D") +static QStringList splitTypeList(const QString &s) +{ + QStringList result; + int templateDepth = 0; + int lastPos = 0; + const int size = s.size(); + for (int i = 0; i < size; ++i) { + switch (s.at(i).toLatin1()) { + case '<': + ++templateDepth; + break; + case '>': + --templateDepth; + break; + case ',': + if (templateDepth == 0) { + result.append(s.mid(lastPos, i - lastPos).trimmed()); + lastPos = i + 1; + } + break; + } + } + if (lastPos < size) + result.append(s.mid(lastPos, size - lastPos).trimmed()); + return result; +} + +bool TypeSystemParser::setupSmartPointerInstantiations() +{ + for (auto it = m_smartPointerInstantiations.cbegin(), + end = m_smartPointerInstantiations.cend(); it != end; ++it) { + auto smartPointerEntry = it.key(); + const auto instantiationNames = splitTypeList(it.value()); + SmartPointerTypeEntry::Instantiations instantiations; + instantiations.reserve(instantiationNames.size()); + for (const auto &instantiationName : instantiationNames) { + const auto types = m_database->findCppTypes(instantiationName); + if (types.isEmpty()) { + m_error = + msgCannotFindTypeEntryForSmartPointer(instantiationName, + smartPointerEntry->name()); + return false; + } + if (types.size() > 1) { + m_error = msgAmbiguousTypesFound(instantiationName, types); + return false; + } + instantiations.append(types.constFirst()); + } + smartPointerEntry->setInstantiations(instantiations); + } + return true; +} + bool TypeSystemParser::endElement(const QStringRef &localName) { if (m_ignoreDepth) { @@ -1135,6 +1199,7 @@ SmartPointerTypeEntry * QString smartPointerType; QString getter; QString refCountMethodName; + QString instantiations; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); if (name == QLatin1String("type")) { @@ -1143,6 +1208,8 @@ SmartPointerTypeEntry * getter = attributes->takeAt(i).value().toString(); } else if (name == QLatin1String("ref-count-method")) { refCountMethodName = attributes->takeAt(i).value().toString(); + } else if (name == QLatin1String("instantiations")) { + instantiations = attributes->takeAt(i).value().toString(); } } @@ -1177,6 +1244,7 @@ SmartPointerTypeEntry * auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since, currentParentTypeEntry()); applyCommonAttributes(type, attributes); + m_smartPointerInstantiations.insert(type, instantiations); return type; } diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.h b/sources/shiboken2/ApiExtractor/typesystemparser.h index f56e8e0fc..2e9eb3c9b 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.h +++ b/sources/shiboken2/ApiExtractor/typesystemparser.h @@ -31,6 +31,7 @@ #include "typesystem.h" #include <QtCore/QStack> +#include <QtCore/QHash> #include <QtCore/QScopedPointer> QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) @@ -152,6 +153,8 @@ public: QString errorString() const { return m_error; } private: + bool parseXml(QXmlStreamReader &reader); + bool setupSmartPointerInstantiations(); bool startElement(const QXmlStreamReader &reader); SmartPointerTypeEntry *parseSmartPointerEntry(const QXmlStreamReader &, const QString &name, @@ -273,6 +276,7 @@ private: QString m_currentSignature; QString m_currentPath; QScopedPointer<TypeSystemEntityResolver> m_entityResolver; + QHash<SmartPointerTypeEntry *, QString> m_smartPointerInstantiations; }; #endif // TYPESYSTEMPARSER_H diff --git a/sources/shiboken2/doc/typesystem_specifying_types.rst b/sources/shiboken2/doc/typesystem_specifying_types.rst index dd443f8f8..f842adb76 100644 --- a/sources/shiboken2/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/doc/typesystem_specifying_types.rst @@ -445,6 +445,14 @@ smart-pointer-type to function return values. **ref-count-method** specifies the name of the method used to do reference counting. + The *optional* attribute **instantiations** specifies for which instantiations + of the smart pointer wrappers will be generated (comma-separated list). + By default, this will happen for all instantiations found by code parsing. + This might be a problem when linking different modules, since wrappers for the + same instantiation might be generated into different modules, which then clash. + Providing an instantiations list makes it possible to specify which wrappers + will be generated into specific modules. + .. code-block:: xml <typesystem> @@ -452,7 +460,8 @@ smart-pointer-type since="..." type="..." getter="..." - ref-count-method="..."/> + ref-count-method="..." + instantiations="..."/> </typesystem> .. _function: diff --git a/sources/shiboken2/tests/smartbinding/typesystem_smart.xml b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml index 0bb485957..8fb3082a0 100644 --- a/sources/shiboken2/tests/smartbinding/typesystem_smart.xml +++ b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml @@ -43,7 +43,8 @@ possible to explicitly instantiate a new shared pointer in python e.g. o = SharedPtr_Foo() won't work. --> - <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount" /> + <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount" + instantiations="Integer,Smart::Integer2,Obj"/> <object-type name="Obj" /> <value-type name="Integer" /> |