aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/shiboken6/ApiExtractor/classdocumentation.cpp42
-rw-r--r--sources/shiboken6/ApiExtractor/classdocumentation.h2
-rw-r--r--sources/shiboken6/ApiExtractor/complextypeentry.h3
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp19
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h3
-rw-r--r--sources/shiboken6/ApiExtractor/qtdocparser.cpp44
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem.cpp13
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser.cpp2
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst16
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
^^^^^^^^^^^^^^