diff options
| -rw-r--r-- | sources/shiboken6/ApiExtractor/classdocumentation.cpp | 42 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/classdocumentation.h | 2 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/complextypeentry.h | 3 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/messages.cpp | 19 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/messages.h | 3 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/qtdocparser.cpp | 44 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typesystem.cpp | 13 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typesystemparser.cpp | 2 | ||||
| -rw-r--r-- | sources/shiboken6/doc/typesystem_specifying_types.rst | 16 |
9 files changed, 106 insertions, 38 deletions
diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.cpp b/sources/shiboken6/ApiExtractor/classdocumentation.cpp index 2f92b2e3c..199d6992a 100644 --- a/sources/shiboken6/ApiExtractor/classdocumentation.cpp +++ b/sources/shiboken6/ApiExtractor/classdocumentation.cpp @@ -195,23 +195,15 @@ static QString msgXmlError(const QString &fileName, const QXmlStreamReader &read return result; } -std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage) +static bool parseWebXmlHelper(QFile *file, ClassDocumentation *result, QString *errorMessage) { - ClassDocumentation result; - - QFile file(fileName); - if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) { - *errorMessage = msgCannotOpenForReading(file); - return std::nullopt; - } - WebXmlCodeTag lastTag = WebXmlCodeTag::Other; - QXmlStreamReader reader(&file); + QXmlStreamReader reader(file); while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: { const auto currentTag = tag(reader.name()); - parseWebXmlElement(currentTag, reader.attributes(), &result); + parseWebXmlElement(currentTag, reader.attributes(), result); switch (currentTag) { // Store relevant tags in lastTag case WebXmlCodeTag::Class: case WebXmlCodeTag::Function: @@ -225,16 +217,16 @@ std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString * QString *target = nullptr; switch (lastTag) { case WebXmlCodeTag::Class: - target = &result.description; + target = &result->description; break; case WebXmlCodeTag::Function: - target = &result.functions.last().description; + target = &result->functions.last().description; break; case WebXmlCodeTag::Enum: - target = &result.enums.last().description; + target = &result->enums.last().description; break; case WebXmlCodeTag::Property: - target = &result.properties.last().description; + target = &result->properties.last().description; default: break; } @@ -252,8 +244,24 @@ std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString * } if (reader.error() != QXmlStreamReader::NoError) { - *errorMessage= msgXmlError(fileName, reader); - return std::nullopt; + *errorMessage= msgXmlError(file->fileName(), reader); + return false; + } + + return result; +} + +std::optional<ClassDocumentation> parseWebXml(const QStringList &fileNames, QString *errorMessage) +{ + ClassDocumentation result; + for (const auto &fileName : fileNames) { + QFile file(fileName); + if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) { + *errorMessage = msgCannotOpenForReading(file); + return std::nullopt; + } + if (!parseWebXmlHelper(&file, &result, errorMessage)) + return std::nullopt; } sortDocumentation(&result); diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.h b/sources/shiboken6/ApiExtractor/classdocumentation.h index 108a1ff78..df834ff35 100644 --- a/sources/shiboken6/ApiExtractor/classdocumentation.h +++ b/sources/shiboken6/ApiExtractor/classdocumentation.h @@ -69,7 +69,7 @@ struct ClassDocumentation }; /// Parse a WebXML class/namespace document -std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage); +std::optional<ClassDocumentation> parseWebXml(const QStringList &fileNames, QString *errorMessage); /// Extract the module description from a WebXML module document QString webXmlModuleDescription(const QString &fileName, QString *errorMessage); diff --git a/sources/shiboken6/ApiExtractor/complextypeentry.h b/sources/shiboken6/ApiExtractor/complextypeentry.h index 5b884f2cc..f1d711313 100644 --- a/sources/shiboken6/ApiExtractor/complextypeentry.h +++ b/sources/shiboken6/ApiExtractor/complextypeentry.h @@ -163,6 +163,9 @@ public: bool isValueTypeWithCopyConstructorOnly() const; void setValueTypeWithCopyConstructorOnly(bool v); + QString docFile() const; + void setDocFile(const QString &docFile); + // FIXME PYSIDE 7: Remove this static bool isParentManagementEnabled(); static void setParentManagementEnabled(bool e); diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index 6ed0cceae..57b4e7575 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -6,6 +6,7 @@ #include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetalang.h" +#include "include.h" #include "modifications.h" #include "sourcelocation.h" #include "typedatabase.h" @@ -22,6 +23,9 @@ #include <QtCore/QStringList> #include <QtCore/QXmlStreamReader> +#include <algorithm> +#include <iterator> + using namespace Qt::StringLiterals; // abstractmetabuilder.cpp @@ -1034,3 +1038,18 @@ QString msgCannotCopy(const QFile &source, const QString &target) + " to "_L1 + QDir::toNativeSeparators(target) + ": "_L1 + source.errorString(); } + +QString msgCannotFindQDocFile(const AbstractMetaClassCPtr &metaClass, + const QStringList &candidates) +{ + QStringList nativeCandidates; + std::transform(candidates.cbegin(), candidates.cend(), std::back_inserter(nativeCandidates), + QDir::toNativeSeparators); + QString result; + QTextStream(&result) << "Cannot find qdoc file for " + << (metaClass->isNamespace() ? "namespace" : "class") << " \"" + << metaClass->typeEntry()->qualifiedCppName() << "\" (" + << QDir::toNativeSeparators(metaClass->typeEntry()->include().name()) + << "), tried: " << nativeCandidates.join(", "_L1); + return result; +} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index 5412a8b6c..a7d491db1 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -273,4 +273,7 @@ QString msgCannotCreateDir(const QString &dir); QString msgCannotCopy(const QFile &source, const QString &target); +QString msgCannotFindQDocFile(const AbstractMetaClassCPtr &metaClass, + const QStringList &candidates); + #endif // MESSAGES_H diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp index 96d14ea93..216eccb05 100644 --- a/sources/shiboken6/ApiExtractor/qtdocparser.cpp +++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp @@ -28,6 +28,9 @@ #include <QtCore/QHash> #include <QtCore/QUrl> +#include <algorithm> +#include <iterator> + using namespace Qt::StringLiterals; enum { debugFunctionSearch = 0 }; @@ -86,13 +89,11 @@ QString QtDocParser::qdocModuleDir(const QString &pythonType) return it.value(); } -static QString xmlFileNameRoot(const AbstractMetaClassPtr &metaClass) +static QString xmlFileBaseName(const AbstractMetaClassPtr &metaClass) { QString className = metaClass->qualifiedCppName().toLower(); className.replace("::"_L1, "-"_L1); - - return QtDocParser::qdocModuleDir(metaClass->typeEntry()->targetLangPackage()) - + u'/' + className; + return className; } static void formatPreQualifications(QTextStream &str, const AbstractMetaType &type) @@ -324,7 +325,7 @@ void QtDocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr return; QString errorMessage; - auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + auto classDocumentationO = parseWebXml({sourceFileName}, &errorMessage); if (!classDocumentationO.has_value()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return; @@ -347,7 +348,7 @@ void QtDocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &e) return; QString errorMessage; - auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + auto classDocumentationO = parseWebXml({sourceFileName}, &errorMessage); if (!classDocumentationO.has_value()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return; @@ -370,28 +371,35 @@ QString QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass) context = context->enclosingClass(); } - QString sourceFileRoot = documentationDataDirectory() + u'/' + xmlFileNameRoot(metaClass); - - QFileInfo sourceFile(sourceFileRoot + webxmlSuffix); - if (!sourceFile.exists()) - sourceFile.setFile(sourceFileRoot + ".xml"_L1); - if (!sourceFile.exists()) { - qCWarning(lcShibokenDoc).noquote().nospace() - << "Can't find qdoc file for class " << metaClass->name() << ", tried: " - << QDir::toNativeSeparators(sourceFile.absoluteFilePath()); + // Find qdoc files of a class. + QStringList allCandidates; + const auto typeEntry = metaClass->typeEntry(); + const QString docDir = documentationDataDirectory() + u'/' + + QtDocParser::qdocModuleDir(typeEntry->targetLangPackage()) + u'/'; + const QString baseName = xmlFileBaseName(metaClass); + allCandidates.append(docDir + baseName + webxmlSuffix); + const QString &docFile = typeEntry->docFile(); + if (!docFile.isEmpty()) + allCandidates.append(docDir + docFile + webxmlSuffix); + allCandidates.append(docDir + baseName + ".xml"_L1); + QStringList candidates; + std::copy_if(allCandidates.cbegin(), allCandidates.cend(), std::back_inserter(candidates), + qOverload<const QString &>(QFileInfo::exists)); + + if (candidates.isEmpty()) { + qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindQDocFile(metaClass, allCandidates))); return {}; } - const QString sourceFileName = sourceFile.absoluteFilePath(); QString errorMessage; - - const auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + const auto classDocumentationO = parseWebXml(candidates, &errorMessage); if (!classDocumentationO.has_value()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return {}; } const auto &classDocumentation = classDocumentationO.value(); + const QString &sourceFileName = candidates.constFirst(); for (const auto &p : classDocumentation.properties) { Documentation doc(p.description, p.brief, sourceFileName); metaClass->setPropertyDocumentation(p.name, doc); diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index d1274fd99..98b82cb46 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -1367,6 +1367,7 @@ public: QString m_defaultConstructor; QString m_defaultSuperclass; QString m_qualifiedCppName; + QString m_docFile; uint m_polymorphicBase : 1; uint m_genericClass : 1; @@ -1799,6 +1800,18 @@ void ComplexTypeEntry::setValueTypeWithCopyConstructorOnly(bool v) d->m_isValueTypeWithCopyConstructorOnly = v; } +QString ComplexTypeEntry::docFile() const +{ + S_D(const ComplexTypeEntry); + return d->m_docFile; +} + +void ComplexTypeEntry::setDocFile(const QString &docFile) +{ + S_D(ComplexTypeEntry); + d->m_docFile = docFile; +} + // FIXME PYSIDE 7: Remove this and make "true" the default static bool parentManagementEnabled = false; diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index f2189ec6e..bf632a026 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -1925,6 +1925,8 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader if (convertBoolean(attribute.value(), parentManagementAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ParentManagement); ComplexTypeEntry::setParentManagementEnabled(true); + } else if (name == docFileAttribute) { + ctype->setDocFile(attributes->takeAt(i).value().toString()); } } diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index e2bdd9566..ab085df8d 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -235,6 +235,7 @@ child nodes. since="..." extends = "..." files = "..." + doc-file = "..." revision="..." /> </typesystem> @@ -275,6 +276,9 @@ The *optional* **file** attribute specifies a regular expression matching the include files whose contents are to be associated with the current module in case of a namespace spanning several modules. +The *optional* **doc-file** attribute specifies the base name of a ``.qdoc`` +file where documentation of the class is to be found (``qdoc`` only). + .. _enum-type: enum-type @@ -388,7 +392,8 @@ node or other type nodes and may contain :ref:`add-function`, :ref:`add-pymethod stream="yes | no" default-constructor="..." revision="..." - snake-case="yes | no | both" /> + snake-case="yes | no | both" + doc-file = "..." /> </typesystem> The **name** attribute is the fully qualified C++ class name, such as @@ -436,6 +441,9 @@ The *optional* **isNull** and **operator-bool** attributes can be used to override the command line setting for generating bool casts (see :ref:`bool-cast`). +The *optional* **doc-file** attribute specifies the base name of a ``.qdoc`` +file where documentation of the class is to be found (``qdoc`` only). + .. _object-type: object-type @@ -473,7 +481,8 @@ or other type nodes and may contain :ref:`add-function`, :ref:`add-pymethoddef`, qt-register-metatype = "yes | no | base" stream="yes | no" revision="..." - snake-case="yes | no | both" /> + snake-case="yes | no | both" + doc-file = "..." /> </typesystem> The **name** attribute is the fully qualified C++ class name. If there is no @@ -553,6 +562,9 @@ attribute. For the *optional* **polymorphic-id-expression**, **polymorphic-name-function** and **polymorphic-base** attributes, see :ref:`typediscovery-attributes`. +The *optional* **doc-file** attribute specifies the base name of a ``.qdoc`` +file where documentation of the class is to be found (``qdoc`` only). + interface-type ^^^^^^^^^^^^^^ |
