From 29287d7db849688231a0fc9cc49afce4088cf3e2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 11 Dec 2020 16:16:02 +0100 Subject: Shiboken6: Decouple QtXmlToSphinx from the doc generator To enable testing, decouple QtXmlToSphinx from the doc generator by introducing a parameter struct QtXmlToSphinxParameters and an interface QtXmlToSphinxDocGeneratorInterface. Move the messages back into qtxmltosphinx.cpp and move the helper function convertToRst to the doc generator since it uses FileOut. Change-Id: I176888dcbd65003856ea8797a5629949598801d5 Reviewed-by: Christian Tismer (cherry picked from commit cddc4e975398c7c285b0dfada8a57fe997f05833) Reviewed-by: Qt Cherry-pick Bot --- sources/shiboken6/ApiExtractor/messages.cpp | 30 --- sources/shiboken6/ApiExtractor/messages.h | 7 - .../shiboken6/generator/qtdoc/qtdocgenerator.cpp | 132 +++++++++++-- sources/shiboken6/generator/qtdoc/qtdocgenerator.h | 30 +-- .../shiboken6/generator/qtdoc/qtxmltosphinx.cpp | 218 ++++++++------------- sources/shiboken6/generator/qtdoc/qtxmltosphinx.h | 22 +-- .../generator/qtdoc/qtxmltosphinxinterface.h | 60 ++++++ 7 files changed, 289 insertions(+), 210 deletions(-) create mode 100644 sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h (limited to 'sources') diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index 5bdd58ae2..664db57eb 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -792,33 +792,3 @@ QString msgRegisterMetaTypeUnqualifiedName(const AbstractMetaClass *c, << "). This is currently fixed by a hack(ct) and needs improvement!"; return result; } - -// qtdocgenerator.cpp - -QString msgTagWarning(const QXmlStreamReader &reader, const QString &context, - const QString &tag, const QString &message) -{ - QString result; - QTextStream str(&result); - str << "While handling <"; - const auto currentTag = reader.name(); - if (currentTag.isEmpty()) - str << tag; - else - str << currentTag; - str << "> in " << context << ", line "<< reader.lineNumber() - << ": " << message; - return result; -} - -QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context, - const QString &tag, const QString &location, - const QString &identifier, const QString &fallback) -{ - QString message = QLatin1String("Falling back to \"") - + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"") - + location + QLatin1Char('"'); - if (!identifier.isEmpty()) - message += QLatin1String(" [") + identifier + QLatin1Char(']'); - return msgTagWarning(reader, context, tag, message); -} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index 21b16a264..e3a89319f 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -231,11 +231,4 @@ QString msgUnknownTypeInArgumentTypeReplacement(const QString &typeReplaced, QString msgRegisterMetaTypeUnqualifiedName(const AbstractMetaClass *c, const char *file, int line); -QString msgTagWarning(const QXmlStreamReader &reader, const QString &context, - const QString &tag, const QString &message); - -QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context, - const QString &tag, const QString &location, - const QString &identifier, const QString &fallback); - #endif // MESSAGES_H diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp index 06fc7aa42..07ec29f03 100644 --- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -150,6 +151,8 @@ static QString getFuncName(const AbstractMetaFunctionCPtr& cppFunc) QtDocGenerator::QtDocGenerator() { + m_parameters.snippetComparison = + ReportHandler::debugLevel() >= ReportHandler::FullDebug; } QtDocGenerator::~QtDocGenerator() = default; @@ -186,7 +189,7 @@ void QtDocGenerator::writeFormattedText(TextStream &s, const Documentation &doc, metaClassName = metaClass->fullName(); if (doc.format() == Documentation::Native) { - QtXmlToSphinx x(this, doc.value(docType), metaClassName); + QtXmlToSphinx x(this, m_parameters, doc.value(docType), metaClassName); s << x; } else { const QString &value = doc.value(docType); @@ -905,7 +908,7 @@ void QtDocGenerator::writeModuleDocumentation() if (moduleDoc.format() == Documentation::Native) { QString context = it.key(); QtXmlToSphinx::stripPythonQualifiers(&context); - QtXmlToSphinx x(this, moduleDoc.value(), context); + QtXmlToSphinx x(this, m_parameters, moduleDoc.value(), context); s << x; } else { s << moduleDoc.value(); @@ -962,13 +965,13 @@ void QtDocGenerator::writeAdditionalDocumentation() const } } else { // Normal file entry - QFileInfo fi(m_docDataDir + QLatin1Char('/') + line); + QFileInfo fi(m_parameters.docDataDir + QLatin1Char('/') + line); if (fi.isFile()) { const QString rstFileName = fi.baseName() + rstSuffix; const QString rstFile = targetDir + QLatin1Char('/') + rstFileName; const QString context = targetDir.mid(targetDir.lastIndexOf(QLatin1Char('/')) + 1); - if (QtXmlToSphinx::convertToRst(this, fi.absoluteFilePath(), - rstFile, context, &errorMessage)) { + if (convertToRst(fi.absoluteFilePath(), + rstFile, context, &errorMessage)) { ++successCount; qCDebug(lcShibokenDoc).nospace().noquote() << __FUNCTION__ << " converted " << fi.fileName() @@ -978,7 +981,7 @@ void QtDocGenerator::writeAdditionalDocumentation() const } } else { qCWarning(lcShibokenDoc, "%s", - qPrintable(msgNonExistentAdditionalDocFile(m_docDataDir, line))); + qPrintable(msgNonExistentAdditionalDocFile(m_parameters.docDataDir, line))); } ++count; } @@ -997,20 +1000,23 @@ void QtDocGenerator::writeAdditionalDocumentation() const bool QtDocGenerator::doSetup() { - if (m_codeSnippetDirs.isEmpty()) - m_codeSnippetDirs = m_libSourceDir.split(QLatin1Char(PATH_SEP)); + if (m_parameters.codeSnippetDirs.isEmpty()) { + m_parameters.codeSnippetDirs = + m_parameters.libSourceDir.split(QLatin1Char(PATH_SEP)); + } if (m_docParser.isNull()) m_docParser.reset(new QtDocParser); - if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) { + if (m_parameters.libSourceDir.isEmpty() + || m_parameters.docDataDir.isEmpty()) { qCWarning(lcShibokenDoc) << "Documentation data dir and/or Qt source dir not informed, " "documentation will not be extracted from Qt sources."; return false; } - m_docParser->setDocumentationDataDirectory(m_docDataDir); - m_docParser->setLibrarySourceDirectory(m_libSourceDir); + m_docParser->setDocumentationDataDirectory(m_parameters.docDataDir); + m_docParser->setLibrarySourceDirectory(m_parameters.libSourceDir); return true; } @@ -1037,15 +1043,15 @@ Generator::OptionDescriptions QtDocGenerator::options() const bool QtDocGenerator::handleOption(const QString &key, const QString &value) { if (key == QLatin1String("library-source-dir")) { - m_libSourceDir = value; + m_parameters.libSourceDir = value; return true; } if (key == QLatin1String("documentation-data-dir")) { - m_docDataDir = value; + m_parameters.docDataDir = value; return true; } if (key == QLatin1String("documentation-code-snippets-dir")) { - m_codeSnippetDirs = value.split(QLatin1Char(PATH_SEP)); + m_parameters.codeSnippetDirs = value.split(QLatin1Char(PATH_SEP)); return true; } if (key == QLatin1String("documentation-extra-sections-dir")) { @@ -1064,3 +1070,101 @@ bool QtDocGenerator::handleOption(const QString &key, const QString &value) } return false; } + +bool QtDocGenerator::convertToRst(const QString &sourceFileName, + const QString &targetFileName, + const QString &context, + QString *errorMessage) const +{ + QFile sourceFile(sourceFileName); + if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + if (errorMessage) + *errorMessage = msgCannotOpenForReading(sourceFile); + return false; + } + const QString doc = QString::fromUtf8(sourceFile.readAll()); + sourceFile.close(); + + FileOut targetFile(targetFileName); + QtXmlToSphinx x(this, m_parameters, doc, context); + targetFile.stream << x; + return targetFile.done(errorMessage) != FileOut::Failure; +} + +// QtXmlToSphinxDocGeneratorInterface +QString QtDocGenerator::expandFunction(const QString &function) const +{ + const int firstDot = function.indexOf(QLatin1Char('.')); + const AbstractMetaClass *metaClass = nullptr; + if (firstDot != -1) { + const auto className = QStringView{function}.left(firstDot); + for (const AbstractMetaClass *cls : classes()) { + if (cls->name() == className) { + metaClass = cls; + break; + } + } + } + + return metaClass + ? metaClass->typeEntry()->qualifiedTargetLangName() + + function.right(function.size() - firstDot) + : function; +} + +QString QtDocGenerator::expandClass(const QString &context, + const QString &name) const +{ + if (auto typeEntry = TypeDatabase::instance()->findType(name)) + return typeEntry->qualifiedTargetLangName(); + // fall back to the old heuristic if the type wasn't found. + QString result = name; + const auto rawlinklist = QStringView{name}.split(QLatin1Char('.')); + QStringList splittedContext = context.split(QLatin1Char('.')); + if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) { + splittedContext.removeLast(); + result.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.')) + + QLatin1Char('.')); + } + return result; +} + +QString QtDocGenerator::resolveContextForMethod(const QString &context, + const QString &methodName) const +{ + const auto currentClass = QStringView{context}.split(QLatin1Char('.')).constLast(); + + const AbstractMetaClass *metaClass = nullptr; + for (const AbstractMetaClass *cls : classes()) { + if (cls->name() == currentClass) { + metaClass = cls; + break; + } + } + + if (metaClass) { + AbstractMetaFunctionCList funcList; + const auto &methods = metaClass->queryFunctionsByName(methodName); + for (const auto &func : methods) { + if (methodName == func->name()) + funcList.append(func); + } + + const AbstractMetaClass *implementingClass = nullptr; + for (const auto &func : qAsConst(funcList)) { + implementingClass = func->implementingClass(); + if (implementingClass->name() == currentClass) + break; + } + + if (implementingClass) + return implementingClass->typeEntry()->qualifiedTargetLangName(); + } + + return QLatin1Char('~') + context; +} + +const QLoggingCategory &QtDocGenerator::loggingCategory() const +{ + return lcShibokenDoc(); +} diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h index 673dc9104..218625cef 100644 --- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h @@ -36,25 +36,19 @@ #include "documentation.h" #include "typesystem_enums.h" #include "typesystem_typedefs.h" +#include "qtxmltosphinxinterface.h" class DocParser; /** * The DocGenerator generates documentation from library being binded. */ -class QtDocGenerator : public Generator +class QtDocGenerator : public Generator, public QtXmlToSphinxDocGeneratorInterface { public: QtDocGenerator(); ~QtDocGenerator(); - QString libSourceDir() const - { - return m_libSourceDir; - } - - QString docDataDir() const { return m_docDataDir; } - bool doSetup() override; const char* name() const override @@ -65,10 +59,13 @@ public: OptionDescriptions options() const override; bool handleOption(const QString &key, const QString &value) override; - QStringList codeSnippetDirs() const - { - return m_codeSnippetDirs; - } + // QtXmlToSphinxDocGeneratorInterface + QString expandFunction(const QString &function) const override; + QString expandClass(const QString &context, + const QString &name) const override; + QString resolveContextForMethod(const QString &context, + const QString &methodName) const override; + const QLoggingCategory &loggingCategory() const override; protected: bool shouldGenerate(const AbstractMetaClass *) const override; @@ -108,13 +105,16 @@ private: const AbstractMetaFunctionCPtr &func); QString translateToPythonType(const AbstractMetaType &type, const AbstractMetaClass *cppClass) const; - QString m_docDataDir; - QString m_libSourceDir; - QStringList m_codeSnippetDirs; + bool convertToRst(const QString &sourceFileName, + const QString &targetFileName, + const QString &context = QString(), + QString *errorMessage = nullptr) const; + QString m_extraSectionDir; QStringList m_functionList; QMap m_packages; QScopedPointer m_docParser; + QtXmlToSphinxParameters m_parameters; QString m_additionalDocumentationList; }; diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp index 12d13f6b7..66c267852 100644 --- a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp +++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp @@ -27,19 +27,13 @@ ****************************************************************************/ #include "qtxmltosphinx.h" -#include "fileout.h" -#include "messages.h" +#include "qtxmltosphinxinterface.h" #include "rstformat.h" -#include "qtdocgenerator.h" -#include -#include -#include -#include -#include #include #include #include +#include #include #include @@ -47,6 +41,34 @@ static inline QString nameAttribute() { return QStringLiteral("name"); } static inline QString titleAttribute() { return QStringLiteral("title"); } static inline QString fullTitleAttribute() { return QStringLiteral("fulltitle"); } +QString msgTagWarning(const QXmlStreamReader &reader, const QString &context, + const QString &tag, const QString &message) +{ + QString result; + QTextStream str(&result); + str << "While handling <"; + const auto currentTag = reader.name(); + if (currentTag.isEmpty()) + str << tag; + else + str << currentTag; + str << "> in " << context << ", line "<< reader.lineNumber() + << ": " << message; + return result; +} + +QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context, + const QString &tag, const QString &location, + const QString &identifier, const QString &fallback) +{ + QString message = QLatin1String("Falling back to \"") + + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"") + + location + QLatin1Char('"'); + if (!identifier.isEmpty()) + message += QLatin1String(" [") + identifier + QLatin1Char(']'); + return msgTagWarning(reader, context, tag, message); +} + struct QtXmlToSphinx::LinkContext { enum Type @@ -211,10 +233,12 @@ static const WebXmlTagHash &webXmlTagHash() return result; } -QtXmlToSphinx::QtXmlToSphinx(const QtDocGenerator *generator, +QtXmlToSphinx::QtXmlToSphinx(const QtXmlToSphinxDocGeneratorInterface *docGenerator, + const QtXmlToSphinxParameters ¶meters, const QString& doc, const QString& context) : m_output(static_cast(nullptr)), - m_tableHasHeader(false), m_context(context), m_generator(generator), + m_tableHasHeader(false), m_context(context), + m_generator(docGenerator), m_parameters(parameters), m_insideBold(false), m_insideItalic(false) { m_result = transform(doc); @@ -362,6 +386,16 @@ void QtXmlToSphinx::callHandler(WebXmlTag t, QXmlStreamReader &r) } } +void QtXmlToSphinx::formatCurrentTable() +{ + if (m_currentTable.isEmpty()) + return; + m_currentTable.setHeaderEnabled(m_tableHasHeader); + m_currentTable.normalize(); + m_output << ensureEndl; + m_currentTable.format(m_output); +} + void QtXmlToSphinx::pushOutputBuffer() { auto *buffer = new QString(); @@ -379,60 +413,6 @@ QString QtXmlToSphinx::popOutputBuffer() return strcpy; } -QString QtXmlToSphinx::expandFunction(const QString& function) const -{ - const int firstDot = function.indexOf(QLatin1Char('.')); - const AbstractMetaClass *metaClass = nullptr; - if (firstDot != -1) { - const auto className = QStringView{function}.left(firstDot); - for (const AbstractMetaClass *cls : m_generator->classes()) { - if (cls->name() == className) { - metaClass = cls; - break; - } - } - } - - return metaClass - ? metaClass->typeEntry()->qualifiedTargetLangName() - + function.right(function.size() - firstDot) - : function; -} - -QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) const -{ - const auto currentClass = QStringView{m_context}.split(QLatin1Char('.')).constLast(); - - const AbstractMetaClass *metaClass = nullptr; - for (const AbstractMetaClass *cls : m_generator->classes()) { - if (cls->name() == currentClass) { - metaClass = cls; - break; - } - } - - if (metaClass) { - AbstractMetaFunctionCList funcList; - const auto &methods = metaClass->queryFunctionsByName(methodName); - for (const auto &func : methods) { - if (methodName == func->name()) - funcList.append(func); - } - - const AbstractMetaClass *implementingClass = nullptr; - for (const auto &func : qAsConst(funcList)) { - implementingClass = func->implementingClass(); - if (implementingClass->name() == currentClass) - break; - } - - if (implementingClass) - return implementingClass->typeEntry()->qualifiedTargetLangName(); - } - - return QLatin1Char('~') + m_context; -} - QString QtXmlToSphinx::transform(const QString& doc) { Q_ASSERT(m_buffers.isEmpty()); @@ -452,7 +432,7 @@ QString QtXmlToSphinx::transform(const QString& doc) << reader.errorString() << " at " << reader.lineNumber() << ':' << reader.columnNumber() << '\n' << doc; m_output << message; - qCWarning(lcShibokenDoc).noquote().nospace() << message; + warn(message); break; } @@ -513,7 +493,8 @@ QString QtXmlToSphinx::readFromLocations(const QStringList &locations, const QSt << locations.join(QLatin1String("\", \"")); return QString(); // null } - qCDebug(lcShibokenDoc).noquote().nospace() << "snippet file " << path + qCDebug(m_generator->loggingCategory()).noquote().nospace() + << "snippet file " << path << " [" << identifier << ']' << " resolved to " << resolvedPath; return readFromLocation(resolvedPath, identifier, errorMessage); } @@ -708,11 +689,6 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader) static inline QString fallbackPathAttribute() { return QStringLiteral("path"); } -static inline bool snippetComparison() -{ - return ReportHandler::debugLevel() >= ReportHandler::FullDebug; -} - template // const char*/class Indentor void formatSnippet(TextStream &str, Indent indent, const QString &snippet) { @@ -752,26 +728,26 @@ void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader) QString identifier = reader.attributes().value(QLatin1String("identifier")).toString(); QString errorMessage; const QString pythonCode = - readFromLocations(m_generator->codeSnippetDirs(), location, identifier, &errorMessage); + readFromLocations(m_parameters.codeSnippetDirs, location, identifier, &errorMessage); if (!errorMessage.isEmpty()) - qCWarning(lcShibokenDoc, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage))); + warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)); // Fall back to C++ snippet when "path" attribute is present. // Also read fallback snippet when comparison is desired. QString fallbackCode; - if ((pythonCode.isEmpty() || snippetComparison()) + if ((pythonCode.isEmpty() || m_parameters.snippetComparison) && reader.attributes().hasAttribute(fallbackPathAttribute())) { const QString fallback = reader.attributes().value(fallbackPathAttribute()).toString(); if (QFileInfo::exists(fallback)) { if (pythonCode.isEmpty()) - qCWarning(lcShibokenDoc, "%s", qPrintable(msgFallbackWarning(reader, m_context, m_lastTagName, location, identifier, fallback))); + warn(msgFallbackWarning(reader, m_context, m_lastTagName, location, identifier, fallback)); fallbackCode = readFromLocation(fallback, identifier, &errorMessage); if (!errorMessage.isEmpty()) - qCWarning(lcShibokenDoc, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage))); + warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)); } } - if (!pythonCode.isEmpty() && !fallbackCode.isEmpty() && snippetComparison()) - qCDebug(lcShibokenDoc, "%s", qPrintable(msgSnippetComparison(location, identifier, pythonCode, fallbackCode))); + if (!pythonCode.isEmpty() && !fallbackCode.isEmpty() && m_parameters.snippetComparison) + debug(msgSnippetComparison(location, identifier, pythonCode, fallbackCode)); if (!consecutiveSnippet) m_output << "::\n\n"; @@ -817,10 +793,7 @@ void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader) m_tableHasHeader = false; } else if (token == QXmlStreamReader::EndElement) { // write the table on m_output - m_currentTable.setHeaderEnabled(m_tableHasHeader); - m_currentTable.normalize(); - m_output << ensureEndl; - m_currentTable.format(m_output); + formatCurrentTable(); m_currentTable.clear(); } } @@ -914,10 +887,7 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader) } break; case EnumeratedList: - m_currentTable.setHeaderEnabled(m_tableHasHeader); - m_currentTable.normalize(); - m_output << ensureEndl; - m_currentTable.format(m_output); + formatCurrentTable(); break; } } @@ -965,32 +935,23 @@ QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, result->type = LinkContext::Method; const auto rawlinklist = QStringView{result->linkRef}.split(QLatin1Char('.')); if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) { - QString context = resolveContextForMethod(rawlinklist.constLast().toString()); + const auto lastRawLink = rawlinklist.constLast().toString(); + QString context = m_generator->resolveContextForMethod(m_context, lastRawLink); if (!result->linkRef.startsWith(context)) result->linkRef.prepend(context + QLatin1Char('.')); } else { - result->linkRef = expandFunction(result->linkRef); + result->linkRef = m_generator->expandFunction(result->linkRef); } } else if (type == functionLinkType() && m_context.isEmpty()) { result->type = LinkContext::Function; } else if (type == classLinkType()) { result->type = LinkContext::Class; - if (const TypeEntry *type = TypeDatabase::instance()->findType(result->linkRef)) { - result->linkRef = type->qualifiedTargetLangName(); - } else { // fall back to the old heuristic if the type wasn't found. - const auto rawlinklist = QStringView{result->linkRef}.split(QLatin1Char('.')); - QStringList splittedContext = m_context.split(QLatin1Char('.')); - if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) { - splittedContext.removeLast(); - result->linkRef.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.')) - + QLatin1Char('.')); - } - } + result->linkRef = m_generator->expandClass(m_context, result->linkRef); } else if (type == QLatin1String("enum")) { result->type = LinkContext::Attribute; } else if (type == QLatin1String("page")) { // Module, external web page or reference - if (result->linkRef == m_generator->moduleName()) + if (result->linkRef == m_parameters.moduleName) result->type = LinkContext::Module; else if (result->linkRef.startsWith(QLatin1String("http"))) result->type = LinkContext::External; @@ -1049,7 +1010,7 @@ void QtXmlToSphinx::handleLinkEnd(LinkContext *linkContext) // by qdoc to a matching subdirectory under the "rst/PySide6/" directory static bool copyImage(const QString &href, const QString &docDataDir, const QString &context, const QString &outputDir, - QString *errorMessage) + const QLoggingCategory &lc, QString *errorMessage) { const QChar slash = QLatin1Char('/'); const int lastSlash = href.lastIndexOf(slash); @@ -1092,7 +1053,7 @@ static bool copyImage(const QString &href, const QString &docDataDir, << source.errorString(); return false; } - qCDebug(lcShibokenDoc()).noquote().nospace() << __FUNCTION__ << " href=\"" + qCDebug(lc).noquote().nospace() << __FUNCTION__ << " href=\"" << href << "\", context=\"" << context << "\", docDataDir=\"" << docDataDir << "\", outputDir=\"" << outputDir << "\", copied \"" << source.fileName() << "\"->\"" << targetFileName << '"'; @@ -1103,10 +1064,12 @@ bool QtXmlToSphinx::copyImage(const QString &href) const { QString errorMessage; const bool result = - ::copyImage(href, m_generator->docDataDir(), m_context, - m_generator->outputDirectory(), &errorMessage); + ::copyImage(href, m_parameters.docDataDir, m_context, + m_parameters.outputDirectory, + m_generator->loggingCategory(), + &errorMessage); if (!result) - qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + warn(errorMessage); return result; } @@ -1171,8 +1134,10 @@ void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader) void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader) { QXmlStreamReader::TokenType token = reader.tokenType(); - if (token == QXmlStreamReader::StartElement) - qCDebug(lcShibokenDoc).noquote().nospace() << "Unknown QtDoc tag: \"" << reader.name().toString() << "\"."; + if (token == QXmlStreamReader::StartElement) { + qCDebug(m_generator->loggingCategory()).noquote().nospace() + << "Unknown QtDoc tag: \"" << reader.name().toString() << "\"."; + } } void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader) @@ -1259,11 +1224,11 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader) QXmlStreamReader::TokenType token = reader.tokenType(); if (token == QXmlStreamReader::Characters) { QString location = reader.text().toString(); - location.prepend(m_generator->libSourceDir() + QLatin1Char('/')); + location.prepend(m_parameters.libSourceDir + QLatin1Char('/')); QString errorMessage; QString code = readFromLocation(location, QString(), &errorMessage); if (!errorMessage.isEmpty()) - qCWarning(lcShibokenDoc, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage))); + warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)); m_output << "::\n\n"; Indentation indentation(m_output); if (code.isEmpty()) @@ -1274,26 +1239,6 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader) } } -bool QtXmlToSphinx::convertToRst(const QtDocGenerator *generator, - const QString &sourceFileName, - const QString &targetFileName, - const QString &context, QString *errorMessage) -{ - QFile sourceFile(sourceFileName); - if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - if (errorMessage) - *errorMessage = msgCannotOpenForReading(sourceFile); - return false; - } - const QString doc = QString::fromUtf8(sourceFile.readAll()); - sourceFile.close(); - - FileOut targetFile(targetFileName); - QtXmlToSphinx x(generator, doc, context); - targetFile.stream << x; - return targetFile.done(errorMessage) != FileOut::Failure; -} - void QtXmlToSphinx::Table::normalize() { if (m_normalized || isEmpty()) @@ -1355,10 +1300,7 @@ void QtXmlToSphinx::Table::format(TextStream& s) const if (isEmpty()) return; - if (!isNormalized()) { - qCDebug(lcShibokenDoc) << "Attempt to print an unnormalized table!"; - return; - } + Q_ASSERT(isNormalized()); // calc width and height of each column and row const int headerColumnCount = m_rows.constFirst().count(); @@ -1434,3 +1376,13 @@ void QtXmlToSphinx::stripPythonQualifiers(QString *s) if (lastSep != -1) s->remove(0, lastSep + 1); } + +void QtXmlToSphinx::warn(const QString &message) const +{ + qCWarning(m_generator->loggingCategory(), "%s", qPrintable(message)); +} + +void QtXmlToSphinx::debug(const QString &message) const +{ + qCDebug(m_generator->loggingCategory(), "%s", qPrintable(message)); +} diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h index feaff1563..6fb626e2b 100644 --- a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h +++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h @@ -40,7 +40,9 @@ QT_BEGIN_NAMESPACE class QXmlStreamReader; QT_END_NAMESPACE -class QtDocGenerator; + +class QtXmlToSphinxDocGeneratorInterface; +struct QtXmlToSphinxParameters; enum class WebXmlTag; @@ -112,17 +114,12 @@ public: bool m_normalized = false; }; - explicit QtXmlToSphinx(const QtDocGenerator *generator, + explicit QtXmlToSphinx(const QtXmlToSphinxDocGeneratorInterface *docGenerator, + const QtXmlToSphinxParameters ¶meters, const QString& doc, const QString& context = QString()); ~QtXmlToSphinx(); - static bool convertToRst(const QtDocGenerator *generator, - const QString &sourceFileName, - const QString &targetFileName, - const QString &context = QString(), - QString *errorMessage = nullptr); - QString result() const { return m_result; @@ -131,8 +128,6 @@ public: static void stripPythonQualifiers(QString *s); private: - QString resolveContextForMethod(const QString& methodName) const; - QString expandFunction(const QString& function) const; QString transform(const QString& doc); void handleHeadingTag(QXmlStreamReader& reader); @@ -171,6 +166,9 @@ private: void handleLinkText(LinkContext *linkContext, const QString &linktext) const; void handleLinkEnd(LinkContext *linkContext); + void warn(const QString &message) const; + void debug(const QString &message) const; + QStack m_tagStack; TextStream m_output; QString m_result; @@ -182,7 +180,8 @@ private: QScopedPointer m_seeAlsoContext; // for foo() bool m_tableHasHeader; QString m_context; - const QtDocGenerator* m_generator; + const QtXmlToSphinxDocGeneratorInterface *m_generator; + const QtXmlToSphinxParameters &m_parameters; bool m_insideBold; bool m_insideItalic; QString m_lastTagName; @@ -198,6 +197,7 @@ private: void writeTable(Table& table); bool copyImage(const QString &href) const; void callHandler(WebXmlTag t, QXmlStreamReader &); + void formatCurrentTable(); }; inline TextStream& operator<<(TextStream& s, const QtXmlToSphinx& xmlToSphinx) diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h new file mode 100644 index 000000000..c4bdedd21 --- /dev/null +++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTXMLTOSPHINXINTERFACE_H +#define QTXMLTOSPHINXINTERFACE_H + +#include + +QT_FORWARD_DECLARE_CLASS(QLoggingCategory) + +struct QtXmlToSphinxParameters +{ + QString moduleName; + QString docDataDir; + QString outputDirectory; + QString libSourceDir; + QStringList codeSnippetDirs; + bool snippetComparison = false; +}; + +class QtXmlToSphinxDocGeneratorInterface +{ +public: + virtual QString expandFunction(const QString &function) const = 0; + virtual QString expandClass(const QString &context, + const QString &name) const = 0; + virtual QString resolveContextForMethod(const QString &context, + const QString &methodName) const = 0; + + virtual const QLoggingCategory &loggingCategory() const = 0; + + virtual ~QtXmlToSphinxDocGeneratorInterface() = default; +}; + +#endif // QTXMLTOSPHINXINTERFACE_H -- cgit v1.2.3