aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2022-11-22 13:30:16 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2022-11-25 09:14:11 +0100
commitc6000ddef0d50c3c6068c92b8066a1b73be9ad45 (patch)
tree3a40e83f007bb130258e900efaa06617a7512edf
parent59f159de51345d122638e16ad395cb00433c0d04 (diff)
shiboken6: Generate property documentation
Previously, the documentation generator used to insert the property documentation at the getter/setter function documentation. The properties for use with true_property are hard to discover in this scheme. To fix this, add a separate TOC section and description list for the properties using the sphinx :py:property: directive and link to it from the functions and signals instead. This mimicks the C++ documentation. Task-number: PYSIDE-1106 Task-number: PYSIDE-1019 Pick-to: 6.4 Change-Id: I976fee91a02ca4c8a7c62c7d957ecaea59ac4ebc Reviewed-by: Christian Tismer <tismer@stackless.com> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r--sources/shiboken6/ApiExtractor/qtdocparser.cpp11
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp147
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.h9
3 files changed, 152 insertions, 15 deletions
diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp
index 6d8a0eba6..8daf1ad85 100644
--- a/sources/shiboken6/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp
@@ -123,17 +123,6 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
const AbstractMetaFunctionCPtr &func,
QString *errorMessage)
{
- // Properties
- if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) {
- const QPropertySpec &prop = metaClass->propertySpecs().at(func->propertySpecIndex());
- const auto index = classDocumentation.indexOfProperty(prop.name());
- if (index == -1) {
- *errorMessage = msgCannotFindDocumentation(sourceFileName, func.data());
- return {};
- }
- return classDocumentation.properties.at(index).description;
- }
-
// Search candidates by name and const-ness
FunctionDocumentationList candidates =
classDocumentation.findFunctionCandidates(func->name(), func->isConstant());
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
index 0e9b9e6ca..cf16efaa0 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
@@ -44,6 +44,17 @@ using namespace Qt::StringLiterals;
struct GeneratorDocumentation
{
+ struct Property
+ {
+ QString name;
+ Documentation documentation;
+ AbstractMetaType type;
+ AbstractMetaFunctionCPtr getter;
+ AbstractMetaFunctionCPtr setter;
+ AbstractMetaFunctionCPtr reset;
+ AbstractMetaFunctionCPtr notify;
+ };
+
AbstractMetaFunctionCList constructors;
AbstractMetaFunctionCList allFunctions; // Except constructors
AbstractMetaFunctionCList tocNormalFunctions; // Index lists
@@ -51,8 +62,26 @@ struct GeneratorDocumentation
AbstractMetaFunctionCList tocSignalFunctions;
AbstractMetaFunctionCList tocSlotFunctions;
AbstractMetaFunctionCList tocStaticFunctions;
+
+ QList<Property> properties;
};
+static bool operator<(const GeneratorDocumentation::Property &lhs,
+ const GeneratorDocumentation::Property &rhs)
+{
+ return lhs.name < rhs.name;
+}
+
+static QString propertyRefTarget(const AbstractMetaClass *cppClass, const QString &name)
+{
+ QString result = cppClass->fullName() + u'.' + name;
+ result.replace(u"::"_s, u"."_s);
+ // For sphinx referencing, disambiguate the target from the getter name
+ // by inserting an invisible "Hangul choseong filler" character.
+ result.insert(1, QChar(0x115F));
+ return result;
+}
+
static inline QString additionalDocumentationOption() { return QStringLiteral("additional-documentation"); }
static inline QString none() { return QStringLiteral("None"); }
@@ -129,6 +158,23 @@ static TextStream &operator<<(TextStream &s, const docRef &dr)
return s;
}
+// Format a short documentation reference (automatically dropping the prefix
+// by using '~'), usable for property/attributes ("attr").
+struct shortDocRef
+{
+ explicit shortDocRef(const char *kind, const QString &target) :
+ m_kind(kind), m_target(target) {}
+
+ const char *m_kind;
+ const QString &m_target;
+};
+
+static TextStream &operator<<(TextStream &s, const shortDocRef &sdr)
+{
+ s << ':' << sdr.m_kind << ":`~" << sdr.m_target << '`';
+ return s;
+}
+
struct functionRef : public docRef
{
explicit functionRef(const QString &name, const AbstractMetaClass *cppClass) :
@@ -152,6 +198,12 @@ static TextStream &operator<<(TextStream &s, const functionTocEntry &ft)
return s;
}
+struct propRef : public shortDocRef // Attribute/property (short) reference
+{
+ explicit propRef(const QString &target) :
+ shortDocRef("attr", target) {}
+};
+
QtDocGenerator::QtDocGenerator()
{
m_parameters.snippetComparison =
@@ -279,8 +331,9 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
const GeneratorDocumentation doc = generatorDocumentation(metaClass);
- if (!doc.allFunctions.isEmpty()) {
+ if (!doc.allFunctions.isEmpty() || !doc.properties.isEmpty()) {
s << "\nSynopsis\n--------\n\n";
+ writePropertyToc(s, doc, metaClass);
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);
@@ -298,6 +351,10 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
if (!metaClass->isNamespace())
writeConstructors(s, metaClass, doc.constructors);
+
+ if (!doc.properties.isEmpty())
+ writeProperties(s, doc, metaClass);
+
writeEnums(s, metaClass);
if (!metaClass->isNamespace())
writeFields(s, metaClass);
@@ -328,6 +385,54 @@ void QtDocGenerator::writeFunctionToc(TextStream &s, const QString &title,
}
}
+void QtDocGenerator::writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClass *cppClass)
+{
+ if (doc.properties.isEmpty())
+ return;
+
+ const QString title = u"Properties"_s;
+ s << title << '\n'
+ << Pad('^', title.size()) << '\n';
+
+ s << ".. container:: function_list\n\n" << indent;
+ for (const auto &prop : doc.properties) {
+ s << "* " << propRef(propertyRefTarget(cppClass, prop.name));
+ if (prop.documentation.hasBrief())
+ s << " - " << prop.documentation.brief();
+ s << '\n';
+ }
+ s << outdent << "\n\n";
+}
+
+void QtDocGenerator::writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClass *cppClass) const
+{
+ s << "\n.. note:: Properties can be used directly when "
+ << "``from __feature__ import true_property`` is used or via accessor "
+ << "functions otherwise.\n\n";
+
+ for (const auto &prop : doc.properties) {
+ const QString type = translateToPythonType(prop.type, cppClass, /* createRef */ false);
+ s << ".. py:property:: " << propertyRefTarget(cppClass, prop.name)
+ << "\n :type: " << type << "\n\n\n";
+ if (!prop.documentation.isEmpty())
+ writeFormattedText(s, prop.documentation.detailed(), Documentation::Native, cppClass);
+ s << "**Access functions:**\n";
+ if (!prop.getter.isNull())
+ s << " * " << functionTocEntry(prop.getter, cppClass) << '\n';
+ if (!prop.setter.isNull())
+ s << " * " << functionTocEntry(prop.setter, cppClass) << '\n';
+ if (!prop.reset.isNull())
+ s << " * " << functionTocEntry(prop.reset, cppClass) << '\n';
+ if (!prop.notify.isNull())
+ s << " * Signal " << functionTocEntry(prop.notify, cppClass) << '\n';
+ s << '\n';
+ }
+}
+
void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaClass *cppClass) const
{
static const QString section_title = u".. attribute:: "_s;
@@ -558,7 +663,8 @@ QString QtDocGenerator::functionSignature(const AbstractMetaClass *cppClass,
}
QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
- const AbstractMetaClass *cppClass) const
+ const AbstractMetaClass *cppClass,
+ bool createRef) const
{
static const QStringList nativeTypes =
{boolT(), floatT(), intT(), pyObjectT(), pyStrT()};
@@ -611,7 +717,10 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
} else {
auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry());
strType = k ? k->fullName() : type.name();
- strType = QStringLiteral(":any:`") + strType + u'`';
+ if (createRef) {
+ strType.prepend(u":any:`"_s);
+ strType.append(u'`');
+ }
}
return strType;
}
@@ -692,6 +801,19 @@ void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaClass *cppCl
writeFormattedDetailedText(s, func->documentation(), cppClass);
}
writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
+
+ if (auto propIndex = func->propertySpecIndex(); propIndex >= 0) {
+ const QString name = cppClass->propertySpecs().at(propIndex).name();
+ const QString target = propertyRefTarget(cppClass, name);
+ if (func->isPropertyReader())
+ s << "\nGetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyWriter())
+ s << "\nSetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyResetter())
+ s << "\nReset function of property " << propRef(target) << " .\n\n";
+ else if (func->attributes().testFlag(AbstractMetaFunction::Attribute::PropertyNotify))
+ s << "\nNotification signal of property " << propRef(target) << " .\n\n";
+ }
}
static void writeFancyToc(TextStream& s, const QStringList& items)
@@ -1089,6 +1211,25 @@ GeneratorDocumentation
else
result.tocNormalFunctions.append(func);
}
+
+ // Find the property getters/setters
+ for (const auto &spec: cppClass->propertySpecs()) {
+ GeneratorDocumentation::Property property;
+ property.name = spec.name();
+ property.type = spec.type();
+ property.documentation = spec.documentation();
+ if (!spec.read().isEmpty())
+ property.getter = AbstractMetaFunction::find(result.allFunctions, spec.read());
+ if (!spec.write().isEmpty())
+ property.setter = AbstractMetaFunction::find(result.allFunctions, spec.write());
+ if (!spec.reset().isEmpty())
+ property.reset = AbstractMetaFunction::find(result.allFunctions, spec.reset());
+ if (!spec.notify().isEmpty())
+ property.notify = AbstractMetaFunction::find(result.tocSignalFunctions, spec.notify());
+ result.properties.append(property);
+ }
+ std::sort(result.properties.begin(), result.properties.end());
+
return result;
}
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
index 9b1735593..af4b60d2e 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
@@ -68,6 +68,12 @@ private:
static void writeFunctionToc(TextStream &s, const QString &title,
const AbstractMetaClass *cppClass,
const AbstractMetaFunctionCList &functions);
+ void writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClass *cppClass);
+ void writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClass *cppClass) const;
void writeParameterType(TextStream &s, const AbstractMetaClass *cppClass,
const AbstractMetaArgument &arg) const;
@@ -93,7 +99,8 @@ private:
void writeAdditionalDocumentation() const;
bool writeInheritanceFile();
- QString translateToPythonType(const AbstractMetaType &type, const AbstractMetaClass *cppClass) const;
+ QString translateToPythonType(const AbstractMetaType &type, const AbstractMetaClass *cppClass,
+ bool createRef = true) const;
bool convertToRst(const QString &sourceFileName,
const QString &targetFileName,