diff options
-rw-r--r-- | sources/shiboken2/ApiExtractor/messages.cpp | 6 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/messages.h | 2 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.cpp | 66 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem_p.h | 6 | ||||
-rw-r--r-- | sources/shiboken2/doc/typesystem_specifying_types.rst | 24 |
5 files changed, 104 insertions, 0 deletions
diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp index fa4c75743..fdae2359b 100644 --- a/sources/shiboken2/ApiExtractor/messages.cpp +++ b/sources/shiboken2/ApiExtractor/messages.cpp @@ -167,6 +167,12 @@ QString msgSkippingFunction(const FunctionModelItem &functionItem, return result; } +QString msgCannotResolveEntity(const QString &name, const QString &reason) +{ + return QLatin1String("Cannot resolve entity \"") + name + + QLatin1String("\": ") + reason; +} + QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason) { return function + QLatin1String(": Cannot use parameter ") diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h index 539332aef..30b13fbf8 100644 --- a/sources/shiboken2/ApiExtractor/messages.h +++ b/sources/shiboken2/ApiExtractor/messages.h @@ -68,6 +68,8 @@ QString msgUnmatchedReturnType(const FunctionModelItem &functionItem, QString msgSkippingFunction(const FunctionModelItem &functionItem, const QString &signature, const QString &why); +QString msgCannotResolveEntity(const QString &name, const QString &reason); + QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason); QString msgUnableToTranslateType(const QString &t, const QString &why); diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index 52dc2a82f..318a52e2e 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -40,6 +40,7 @@ #include <QtCore/QStringAlgorithms> #include <QtCore/QXmlStreamAttributes> #include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamEntityResolver> #include <algorithm> @@ -439,12 +440,75 @@ static QString msgUnusedAttributes(const QStringRef &tag, const QXmlStreamAttrib return result; } +// QXmlStreamEntityResolver::resolveEntity(publicId, systemId) is not +// implemented; resolve via undeclared entities instead. +class TypeSystemEntityResolver : public QXmlStreamEntityResolver +{ +public: + explicit TypeSystemEntityResolver(const QString ¤tPath) : + m_currentPath(currentPath) {} + + QString resolveUndeclaredEntity(const QString &name) override; + +private: + QString readFile(const QString &entityName, QString *errorMessage) const; + + const QString m_currentPath; + QHash<QString, QString> m_cache; +}; + +QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const +{ + QString fileName = entityName; + if (!fileName.contains(QLatin1Char('.'))) + fileName += QLatin1String(".xml"); + QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); + if (!QFileInfo::exists(path)) // PySide2-specific hack + fileName.prepend(QLatin1String("typesystem_")); + path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); + if (!QFileInfo::exists(path)) { + *errorMessage = QLatin1String("Unable to resolve: ") + entityName; + return QString(); + } + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + *errorMessage = msgCannotOpenForReading(file); + return QString(); + } + QString result = QString::fromUtf8(file.readAll()).trimmed(); + // Remove license header comments on which QXmlStreamReader chokes + if (result.startsWith(QLatin1String("<!--"))) { + const int commentEnd = result.indexOf(QLatin1String("-->")); + if (commentEnd != -1) { + result.remove(0, commentEnd + 3); + result = result.trimmed(); + } + } + return result; +} + +QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name) +{ + auto it = m_cache.find(name); + if (it == m_cache.end()) { + QString errorMessage; + it = m_cache.insert(name, readFile(name, &errorMessage)); + if (it.value().isEmpty()) { // The parser will fail and display the line number. + qCWarning(lcShiboken, "%s", + qPrintable(msgCannotResolveEntity(name, errorMessage))); + } + } + return it.value(); +} + Handler::Handler(TypeDatabase *database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) { } +Handler::~Handler() = default; + static QString readerFileName(const QXmlStreamReader &reader) { const QFile *file = qobject_cast<const QFile *>(reader.device()); @@ -584,6 +648,8 @@ bool Handler::parse(QXmlStreamReader &reader) const QString fileName = readerFileName(reader); if (!fileName.isEmpty()) m_currentPath = QFileInfo(fileName).absolutePath(); + m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath)); + reader.setEntityResolver(m_entityResolver.data()); while (!reader.atEnd()) { switch (reader.readNext()) { diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h index df1390cc3..f6b0717f4 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_p.h +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -29,11 +29,13 @@ #define TYPESYSTEM_P_H #include <QStack> +#include <QtCore/QScopedPointer> #include "typesystem.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) +class TypeSystemEntityResolver; class TypeDatabase; class StackElement { @@ -138,7 +140,10 @@ struct StackElementContext class Handler { public: + Q_DISABLE_COPY(Handler) + Handler(TypeDatabase* database, bool generate); + ~Handler(); bool parse(QXmlStreamReader &reader); @@ -256,6 +261,7 @@ private: QString m_currentSignature; QString m_currentPath; + QScopedPointer<TypeSystemEntityResolver> m_entityResolver; }; #endif diff --git a/sources/shiboken2/doc/typesystem_specifying_types.rst b/sources/shiboken2/doc/typesystem_specifying_types.rst index f4016bc2c..ac1121461 100644 --- a/sources/shiboken2/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/doc/typesystem_specifying_types.rst @@ -3,6 +3,30 @@ Specifying Types .. _typesystem: +Including Snippets +^^^^^^^^^^^^^^^^^^ + +There might be repetitive XML code, for example function modifications that +need to be done on classes that are not related by type inheritance. +It is possible to split out such snippets and include them via an entity reference. + +.. code-block:: xml + + <typesystem> + <object-type name="A"> + &common_function_modifications; + </object-type> + <object-type name="B"> + &common_function_modifications; + </object-type> + </typesystem> + +The entity name is interpreted as file name (with suffix **xml**) appended and resolved +in the type system paths passed as command line argument. + +Note that this is not a standard externally parsed entity due to the limitations +of the underlying parser. + typesystem ^^^^^^^^^^ |