diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-11-22 08:04:43 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-11-24 12:40:38 +0100 |
commit | 04c13d32ffb2c36e701bd843db349d4e1acfce77 (patch) | |
tree | b044639191f3adbf88c02a6ce558409c90516fb4 | |
parent | 56f3ecf68c67c45b42caa7940218d6be42156539 (diff) |
shiboken6: Refactor function documentation generation
The code used to extract and sort the functions in several places.
Unify this by storing all function lists in a struct.
Remove unused table from the function index block.
Rename parseArgDocStyle() to formatArgs and add the parentheses
there.
Add stream helpers for formatting references for use in subsequent
patches.
Pick-to: 6.4
Task-number: PYSIDE-1106
Change-Id: Ic7934d2bce8f7a411294c6be5f1d7e103c16b8a1
Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r-- | sources/shiboken6/generator/generator.h | 4 | ||||
-rw-r--r-- | sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp | 225 | ||||
-rw-r--r-- | sources/shiboken6/generator/qtdoc/qtdocgenerator.h | 20 |
3 files changed, 138 insertions, 111 deletions
diff --git a/sources/shiboken6/generator/generator.h b/sources/shiboken6/generator/generator.h index 8bfbb49ad..131ad427d 100644 --- a/sources/shiboken6/generator/generator.h +++ b/sources/shiboken6/generator/generator.h @@ -106,6 +106,8 @@ public: */ static QString moduleName(); + static QString pythonOperatorFunctionName(const QString &cppOpFuncName); + protected: /// Helper for determining the file name static QString fileNameForContextHelper(const GeneratorContext &context, @@ -143,8 +145,6 @@ protected: const AbstractMetaClass *context, Options options = NoOption) const; - static QString pythonOperatorFunctionName(const QString &cppOpFuncName); - /** * Returns the package name. */ diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp index dee776cd4..0e9b9e6ca 100644 --- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp @@ -42,14 +42,24 @@ using namespace Qt::StringLiterals; +struct GeneratorDocumentation +{ + AbstractMetaFunctionCList constructors; + AbstractMetaFunctionCList allFunctions; // Except constructors + AbstractMetaFunctionCList tocNormalFunctions; // Index lists + AbstractMetaFunctionCList tocVirtuals; + AbstractMetaFunctionCList tocSignalFunctions; + AbstractMetaFunctionCList tocSlotFunctions; + AbstractMetaFunctionCList tocStaticFunctions; +}; + static inline QString additionalDocumentationOption() { return QStringLiteral("additional-documentation"); } static inline QString none() { return QStringLiteral("None"); } static bool shouldSkip(const AbstractMetaFunctionCPtr &func) { - // Constructors go to separate section - if (DocParser::skipForQuery(func) || func->isConstructor()) + if (DocParser::skipForQuery(func)) return true; // Search a const clone (QImage::bits() vs QImage::bits() const) @@ -95,6 +105,53 @@ static inline QVersionNumber versionOf(const TypeEntryCPtr &te) return QVersionNumber(); } +// Format a documentation reference (meth/attr): ":meth:`name<target>`" +// We do not use the short form ":meth:`~target`" since that adds parentheses () +// for functions where we list the parameters instead. +struct docRef +{ + explicit docRef(const char *kind, const QString &name, const AbstractMetaClass *cppClass) : + m_kind(kind), m_name(name), m_cppClass(cppClass) {} + + const char *m_kind; + const QString &m_name; + const AbstractMetaClass *m_cppClass; +}; + +static TextStream &operator<<(TextStream &s, const docRef &dr) +{ + QString className = dr.m_cppClass->fullName(); + className.replace(u"::"_s, u"."_s); + s << ':' << dr.m_kind << ":`" << dr.m_name << '<'; + if (!dr.m_name.startsWith(className)) + s << className << '.'; + s << dr.m_name << ">`"; + return s; +} + +struct functionRef : public docRef +{ + explicit functionRef(const QString &name, const AbstractMetaClass *cppClass) : + docRef("meth", name, cppClass) {} +}; + +struct functionTocEntry // Format a TOC entry for a function +{ + explicit functionTocEntry(const AbstractMetaFunctionCPtr& func, + const AbstractMetaClass *cppClass) : + m_func(func), m_cppClass(cppClass) {} + + AbstractMetaFunctionCPtr m_func; + const AbstractMetaClass *m_cppClass; +}; + +static TextStream &operator<<(TextStream &s, const functionTocEntry &ft) +{ + s << functionRef(QtDocGenerator::getFuncName(ft.m_func), ft.m_cppClass) + << ' ' << QtDocGenerator::formatArgs(ft.m_func); + return s; +} + QtDocGenerator::QtDocGenerator() { m_parameters.snippetComparison = @@ -220,11 +277,16 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC if (metaClass->attributes().testFlag(AbstractMetaClass::Deprecated)) s << rstDeprecationNote("class"); - writeFunctionList(s, metaClass); + const GeneratorDocumentation doc = generatorDocumentation(metaClass); - //Function list - auto functionList = metaClass->functions(); - std::sort(functionList.begin(), functionList.end(), functionSort); + if (!doc.allFunctions.isEmpty()) { + s << "\nSynopsis\n--------\n\n"; + writeFunctionToc(s, u"Functions"_s, metaClass, doc.tocNormalFunctions); + writeFunctionToc(s, u"Virtual functions"_s, metaClass, doc.tocVirtuals); + writeFunctionToc(s, u"Slots"_s, metaClass, doc.tocSlotFunctions); + writeFunctionToc(s, u"Signals"_s, metaClass, doc.tocSignalFunctions); + writeFunctionToc(s, u"Static functions"_s, metaClass, doc.tocStaticFunctions); + } s << "\nDetailed Description\n" "--------------------\n\n" @@ -235,96 +297,33 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC writeFormattedDetailedText(s, documentation, metaClass); if (!metaClass->isNamespace()) - writeConstructors(s, metaClass); + writeConstructors(s, metaClass, doc.constructors); writeEnums(s, metaClass); if (!metaClass->isNamespace()) writeFields(s, metaClass); - - QStringList uniqueFunctions; - for (const auto &func : std::as_const(functionList)) { - if (shouldSkip(func)) - continue; - - if (func->isStatic()) - s << ".. py:staticmethod:: "; - else - s << ".. py:method:: "; - - writeFunction(s, metaClass, func, !uniqueFunctions.contains(func->name())); - uniqueFunctions.append(func->name()); + QString lastName; + for (const auto &func : std::as_const(doc.allFunctions)) { + const bool indexed = func->name() != lastName; + lastName = func->name(); + s << (func->isStatic() ? ".. py:staticmethod:: " : ".. py:method:: "); + writeFunction(s, metaClass, func, indexed); } writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, nullptr); } -void QtDocGenerator::writeFunctionList(TextStream &s, const AbstractMetaClass *cppClass) -{ - QStringList functionList; - QStringList virtualList; - QStringList signalList; - QStringList slotList; - QStringList staticFunctionList; - - const auto &classFunctions = cppClass->functions(); - for (const auto &func : classFunctions) { - if (shouldSkip(func)) - continue; - - QString className; - if (!func->isConstructor()) - className = cppClass->fullName() + u'.'; - else if (func->implementingClass() && func->implementingClass()->enclosingClass()) - className = func->implementingClass()->enclosingClass()->fullName() + u'.'; - QString funcName = getFuncName(func); - - QString str = u"def :meth:`"_s; - - str += funcName; - str += u'<'; - if (!funcName.startsWith(className)) - str += className; - str += funcName; - str += u">` ("_s; - str += parseArgDocStyle(cppClass, func); - str += u')'; - - if (func->isStatic()) - staticFunctionList << str; - else if (func->isVirtual()) - virtualList << str; - else if (func->isSignal()) - signalList << str; - else if (func->isSlot()) - slotList << str; - else - functionList << str; - } - - if (!functionList.isEmpty() || !staticFunctionList.isEmpty()) { - QtXmlToSphinx::Table functionTable; - - s << "\nSynopsis\n--------\n\n"; - - writeFunctionBlock(s, u"Functions"_s, functionList); - writeFunctionBlock(s, u"Virtual functions"_s, virtualList); - writeFunctionBlock(s, u"Slots"_s, slotList); - writeFunctionBlock(s, u"Signals"_s, signalList); - writeFunctionBlock(s, u"Static functions"_s, staticFunctionList); - } -} - -void QtDocGenerator::writeFunctionBlock(TextStream &s, const QString& title, QStringList& functions) +void QtDocGenerator::writeFunctionToc(TextStream &s, const QString &title, + const AbstractMetaClass *cppClass, + const AbstractMetaFunctionCList &functions) { if (!functions.isEmpty()) { s << title << '\n' << Pad('^', title.size()) << '\n'; - std::sort(functions.begin(), functions.end()); - s << ".. container:: function_list\n\n" << indent; - for (const QString &func : std::as_const(functions)) - s << "* " << func << '\n'; + for (const auto &func : functions) + s << "* def " << functionTocEntry(func, cppClass) << '\n'; s << outdent << "\n\n"; } } @@ -353,25 +352,19 @@ void QtDocGenerator::writeFields(TextStream &s, const AbstractMetaClass *cppClas } } -void QtDocGenerator::writeConstructors(TextStream &s, const AbstractMetaClass *cppClass) const +void QtDocGenerator::writeConstructors(TextStream &s, const AbstractMetaClass *cppClass, + const AbstractMetaFunctionCList &constructors) const { static const QString sectionTitle = u".. class:: "_s; - auto lst = cppClass->queryFunctions(FunctionQueryOption::AnyConstructor - | FunctionQueryOption::Visible); - for (auto i = lst.size() - 1; i >= 0; --i) { - if (lst.at(i)->isModifiedRemoved() || lst.at(i)->functionType() == AbstractMetaFunction::MoveConstructorFunction) - lst.removeAt(i); - } - bool first = true; QHash<QString, AbstractMetaArgument> arg_map; - if (lst.isEmpty()) { + if (constructors.isEmpty()) { s << sectionTitle << cppClass->fullName(); } else { QByteArray pad; - for (const auto &func : std::as_const(lst)) { + for (const auto &func : constructors) { s << pad; if (first) { first = false; @@ -405,14 +398,13 @@ void QtDocGenerator::writeConstructors(TextStream &s, const AbstractMetaClass *c s << '\n'; - for (const auto &func : std::as_const(lst)) + for (const auto &func : constructors) writeFormattedDetailedText(s, func->documentation(), cppClass); } -QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass * /* cppClass */, - const AbstractMetaFunctionCPtr &func) +QString QtDocGenerator::formatArgs(const AbstractMetaFunctionCPtr &func) { - QString ret; + QString ret = u"("_s; int optArgs = 0; const AbstractMetaArgumentList &arguments = func->arguments(); @@ -453,7 +445,7 @@ QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass * /* cppClass * } } - ret += QString(optArgs, u']'); + ret += QString(optArgs, u']') + u')'; return ret; } @@ -558,14 +550,11 @@ bool QtDocGenerator::writeInjectDocumentation(TextStream &s, QString QtDocGenerator::functionSignature(const AbstractMetaClass *cppClass, const AbstractMetaFunctionCPtr &func) { - QString funcName; - - funcName = cppClass->fullName(); + QString funcName = cppClass->fullName(); if (!func->isConstructor()) funcName += u'.' + getFuncName(func); - return funcName + u'(' + parseArgDocStyle(cppClass, func) - + u')'; + return funcName + formatArgs(func); } QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type, @@ -627,7 +616,7 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type, return strType; } -QString QtDocGenerator::getFuncName(const AbstractMetaFunctionCPtr& cppFunc) +QString QtDocGenerator::getFuncName(const AbstractMetaFunctionCPtr &cppFunc) { QString result = cppFunc->name(); if (cppFunc->isOperatorOverload()) { @@ -1071,6 +1060,38 @@ bool QtDocGenerator::convertToRst(const QString &sourceFileName, return true; } +GeneratorDocumentation + QtDocGenerator::generatorDocumentation(const AbstractMetaClass *cppClass) const +{ + GeneratorDocumentation result; + const auto allFunctions = cppClass->functions(); + result.allFunctions.reserve(allFunctions.size()); + for (const auto &func : allFunctions) { + if (!shouldSkip(func)) { + if (func->isConstructor()) + result.constructors.append(func); + else + result.allFunctions.append(func); + } + } + + std::sort(result.allFunctions.begin(), result.allFunctions.end(), functionSort); + + for (const auto &func : std::as_const(result.allFunctions)) { + if (func->isStatic()) + result.tocStaticFunctions.append(func); + else if (func->isVirtual()) + result.tocVirtuals.append(func); + else if (func->isSignal()) + result.tocSignalFunctions.append(func); + else if (func->isSlot()) + result.tocSlotFunctions.append(func); + else + result.tocNormalFunctions.append(func); + } + return result; +} + // QtXmlToSphinxDocGeneratorInterface QString QtDocGenerator::expandFunction(const QString &function) const { diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h index 1c82610a2..9b1735593 100644 --- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h @@ -15,6 +15,8 @@ class DocParser; +struct GeneratorDocumentation; + /** * The DocGenerator generates documentation from library being binded. */ @@ -43,6 +45,9 @@ public: const QLoggingCategory &loggingCategory() const override; QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &) const override; + static QString getFuncName(const AbstractMetaFunctionCPtr &cppFunc); + static QString formatArgs(const AbstractMetaFunctionCPtr &func); + protected: bool shouldGenerate(const TypeEntryCPtr &) const override; static QString fileNameSuffix(); @@ -60,13 +65,15 @@ private: const AbstractMetaFunctionCPtr &func, bool indexed = true); void writeFunctionParametersType(TextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunctionCPtr &func) const; - static void writeFunctionList(TextStream &s, const AbstractMetaClass *cppClass); - static void writeFunctionBlock(TextStream &s, const QString& title, - QStringList& functions); + static void writeFunctionToc(TextStream &s, const QString &title, + const AbstractMetaClass *cppClass, + const AbstractMetaFunctionCList &functions); void writeParameterType(TextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument &arg) const; - void writeConstructors(TextStream &s, const AbstractMetaClass *cppClass) const; + void writeConstructors(TextStream &s, + const AbstractMetaClass *cppClass, + const AbstractMetaFunctionCList &constructors) const; void writeFormattedText(TextStream &s, const QString &doc, Documentation::Format format, @@ -86,16 +93,15 @@ private: void writeAdditionalDocumentation() const; bool writeInheritanceFile(); - static QString parseArgDocStyle(const AbstractMetaClass *cppClass, - const AbstractMetaFunctionCPtr &func); QString translateToPythonType(const AbstractMetaType &type, const AbstractMetaClass *cppClass) const; - static QString getFuncName(const AbstractMetaFunctionCPtr& cppFunc); bool convertToRst(const QString &sourceFileName, const QString &targetFileName, const QString &context = QString(), QString *errorMessage = nullptr) const; + GeneratorDocumentation generatorDocumentation(const AbstractMetaClass *cppClass) const; + QString m_extraSectionDir; QStringList m_functionList; QMap<QString, QStringList> m_packages; |