aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-09-30 12:27:12 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-02-05 11:48:54 +0100
commit919ee9a8677a1f0838af3f7d3d59e18179c42242 (patch)
treeaf0b74dcf67511477199d5dedb267cd51c3e88eb
parent242f0fa7269e9baf331679dc413c28471b1f7d05 (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.cpp68
-rw-r--r--sources/shiboken2/ApiExtractor/messages.cpp17
-rw-r--r--sources/shiboken2/ApiExtractor/messages.h4
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp5
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h1
-rw-r--r--sources/shiboken2/ApiExtractor/typesystemparser.cpp68
-rw-r--r--sources/shiboken2/ApiExtractor/typesystemparser.h4
-rw-r--r--sources/shiboken2/doc/typesystem_specifying_types.rst11
-rw-r--r--sources/shiboken2/tests/smartbinding/typesystem_smart.xml3
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" />