diff options
author | Topi Reinio <topi.reinio@qt.io> | 2022-07-05 21:48:11 +0200 |
---|---|---|
committer | Topi Reinio <topi.reinio@qt.io> | 2022-08-23 23:31:15 +0200 |
commit | 9ebd62831f1d3b2c314aebf416ca69f98955af2a (patch) | |
tree | e3f66035b904f96d72ade0ede244480c0760fdc2 | |
parent | edf871eba1bd47c1616e4ace31ad5c6e60bd9e63 (diff) |
qdoc: Store BINDABLE property members into PropertyNode
QDoc already recognized the BINDABLE attribute of Q_PROPERTY
but did not store the name of the associated member.
Store it in the list of a PropertyNode's access functions.
This information will be useful later when deciding on
whether to generate a warning for missing member functions;
functions that are associated with properties can be left
undocumented if the property itself is documented.
Add a static helper function PropertyNode that returns the
names of property access function roles. This is used when
writing the access functions into an .index file.
Convert access function-related enums to enum classes.
Change-Id: Idd59622a965895883acf3ae297297ba3f3cca20e
Reviewed-by: Luca Di Sera <luca.disera@qt.io>
-rw-r--r-- | src/qdoc/clangcodeparser.cpp | 11 | ||||
-rw-r--r-- | src/qdoc/codemarker.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/docbookgenerator.cpp | 16 | ||||
-rw-r--r-- | src/qdoc/functionnode.h | 6 | ||||
-rw-r--r-- | src/qdoc/generator.cpp | 14 | ||||
-rw-r--r-- | src/qdoc/htmlgenerator.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/propertynode.cpp | 34 | ||||
-rw-r--r-- | src/qdoc/propertynode.h | 20 | ||||
-rw-r--r-- | src/qdoc/qdocindexfiles.cpp | 45 | ||||
-rw-r--r-- | src/qdoc/tree.cpp | 23 | ||||
-rw-r--r-- | src/qdoc/xmlgenerator.cpp | 2 |
11 files changed, 88 insertions, 87 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index 4c46b8c53..7a2ea72a7 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -979,9 +979,9 @@ bool ClangVisitor::parseProperty(const QString &spelling, const Location &loc) if (i < parts.size()) { QString value = parts.at(i++); if (key == "READ") { - qdb_->addPropertyFunction(property, value, PropertyNode::Getter); + qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Getter); } else if (key == "WRITE") { - qdb_->addPropertyFunction(property, value, PropertyNode::Setter); + qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Setter); property->setWritable(true); } else if (key == "STORED") { property->setStored(value.toLower() == "true"); @@ -995,11 +995,12 @@ bool ClangVisitor::parseProperty(const QString &spelling, const Location &loc) property->setDesignable(false); } } else if (key == "BINDABLE") { - property->setPropertyType(PropertyNode::Bindable); + property->setPropertyType(PropertyNode::PropertyType::BindableProperty); + qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Bindable); } else if (key == "RESET") { - qdb_->addPropertyFunction(property, value, PropertyNode::Resetter); + qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Resetter); } else if (key == "NOTIFY") { - qdb_->addPropertyFunction(property, value, PropertyNode::Notifier); + qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Notifier); } else if (key == "SCRIPTABLE") { QString v = value.toLower(); if (v == "true") diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp index 9dbc23a6b..48e384f9d 100644 --- a/src/qdoc/codemarker.cpp +++ b/src/qdoc/codemarker.cpp @@ -171,7 +171,7 @@ QString CodeMarker::extraSynopsis(const Node *node, Section::Style style) break; case Node::Property: { auto propertyNode = static_cast<const PropertyNode *>(node); - if (propertyNode->propertyType() == PropertyNode::Bindable) + if (propertyNode->propertyType() == PropertyNode::PropertyType::BindableProperty) extra << "bindable"; if (!propertyNode->isWritable()) extra << "read-only"; diff --git a/src/qdoc/docbookgenerator.cpp b/src/qdoc/docbookgenerator.cpp index fcc75722e..07721296b 100644 --- a/src/qdoc/docbookgenerator.cpp +++ b/src/qdoc/docbookgenerator.cpp @@ -2280,7 +2280,7 @@ void DocBookGenerator::generateBody(const Node *node) if (fn && !fn->overridesThis().isEmpty()) generateReimplementsClause(fn); else if (node->isProperty()) { - if (static_cast<const PropertyNode *>(node)->propertyType() != PropertyNode::Standard) + if (static_cast<const PropertyNode *>(node)->propertyType() != PropertyNode::PropertyType::StandardProperty) generateAddendum(node, BindableProperty, nullptr, false); } if (!generateText(node->doc().body(), node)) { @@ -2955,7 +2955,7 @@ void DocBookGenerator::generateDocBookSynopsis(const Node *node) if (functionNode->hasAssociatedProperties()) { QStringList associatedProperties; - const NodeList &nodes = functionNode->associatedProperties(); + const auto &nodes = functionNode->associatedProperties(); for (const Node *n : nodes) { const auto pn = static_cast<const PropertyNode *>(n); associatedProperties << pn->name(); @@ -3636,7 +3636,7 @@ void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMar if (!node->isFunction()) return; const auto *fn = static_cast<const FunctionNode *>(node); - NodeList nodes = fn->associatedProperties(); + auto nodes = fn->associatedProperties(); if (nodes.isEmpty()) return; std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); @@ -3644,16 +3644,16 @@ void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMar QString msg; const auto pn = static_cast<const PropertyNode *>(node); switch (pn->role(fn)) { - case PropertyNode::Getter: + case PropertyNode::FunctionRole::Getter: msg = QStringLiteral("Getter function"); break; - case PropertyNode::Setter: + case PropertyNode::FunctionRole::Setter: msg = QStringLiteral("Setter function"); break; - case PropertyNode::Resetter: + case PropertyNode::FunctionRole::Resetter: msg = QStringLiteral("Resetter function"); break; - case PropertyNode::Notifier: + case PropertyNode::FunctionRole::Notifier: msg = QStringLiteral("Notifier signal"); break; default: @@ -3745,7 +3745,7 @@ void DocBookGenerator::generateDetailedMember(const Node *node, const PageNode * if (node->isProperty()) { const auto property = static_cast<const PropertyNode *>(node); - if (property->propertyType() == PropertyNode::Standard) { + if (property->propertyType() == PropertyNode::PropertyType::StandardProperty) { Section section(Section::Accessors, Section::Active); section.appendMembers(property->getters().toVector()); diff --git a/src/qdoc/functionnode.h b/src/qdoc/functionnode.h index 72b7edaec..0daeacc43 100644 --- a/src/qdoc/functionnode.h +++ b/src/qdoc/functionnode.h @@ -114,14 +114,12 @@ public: bool templateParams = false) const override; [[nodiscard]] const QString &overridesThis() const { return m_overridesThis; } - [[nodiscard]] const NodeList &associatedProperties() const { return m_associatedProperties; } + [[nodiscard]] const QList<PropertyNode *> &associatedProperties() const { return m_associatedProperties; } [[nodiscard]] bool hasAssociatedProperties() const { return !m_associatedProperties.isEmpty(); } [[nodiscard]] bool hasOneAssociatedProperty() const { return (m_associatedProperties.size() == 1); } - [[nodiscard]] Node *firstAssociatedProperty() const { return m_associatedProperties[0]; } - [[nodiscard]] QString element() const override { return parent()->name(); } [[nodiscard]] bool isAttached() const override { return m_attached; } [[nodiscard]] bool isQtQuickNode() const override { return parent()->isQtQuickNode(); } @@ -196,7 +194,7 @@ private: QStringList m_parentPath {}; QString m_overridesThis {}; QString m_tag {}; - NodeList m_associatedProperties {}; + QList<PropertyNode *> m_associatedProperties {}; Parameters m_parameters {}; }; diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index 726ca313f..b6b2d6935 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -549,7 +549,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) if (fn->isDtor()) anchorRef = "#dtor." + fn->name().mid(1); else if (fn->hasOneAssociatedProperty() && fn->doc().isEmpty()) - return fullDocumentLocation(fn->firstAssociatedProperty()); + return fullDocumentLocation(fn->associatedProperties()[0]); else if (fn->overloadNumber() > 0) anchorRef = QLatin1Char('#') + cleanRef(fn->name()) + QLatin1Char('-') + QString::number(fn->overloadNumber()); @@ -749,7 +749,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) if (fn && !fn->overridesThis().isEmpty()) generateReimplementsClause(fn, marker); else if (node->isProperty()) { - if (static_cast<const PropertyNode *>(node)->propertyType() != PropertyNode::Standard) + if (static_cast<const PropertyNode *>(node)->propertyType() != PropertyNode::PropertyType::StandardProperty) generateAddendum(node, BindableProperty, marker); } @@ -1299,7 +1299,7 @@ void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *ma if (!node->isFunction()) return; const auto *fn = static_cast<const FunctionNode *>(node); - NodeList nodes = fn->associatedProperties(); + auto nodes = fn->associatedProperties(); if (nodes.isEmpty()) return; std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); @@ -1307,16 +1307,16 @@ void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *ma QString msg; const auto *pn = static_cast<const PropertyNode *>(n); switch (pn->role(fn)) { - case PropertyNode::Getter: + case PropertyNode::FunctionRole::Getter: msg = QStringLiteral("Getter function"); break; - case PropertyNode::Setter: + case PropertyNode::FunctionRole::Setter: msg = QStringLiteral("Setter function"); break; - case PropertyNode::Resetter: + case PropertyNode::FunctionRole::Resetter: msg = QStringLiteral("Resetter function"); break; - case PropertyNode::Notifier: + case PropertyNode::FunctionRole::Notifier: msg = QStringLiteral("Notifier signal"); break; default: diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index 4772a589b..d5edaa0d2 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -3502,7 +3502,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node, const PageNode *rel if (node->isProperty()) { const auto property = static_cast<const PropertyNode *>(node); - if (property->propertyType() == PropertyNode::Standard) { + if (property->propertyType() == PropertyNode::PropertyType::StandardProperty) { Section section(Section::Accessors, Section::Active); section.appendMembers(property->getters().toVector()); diff --git a/src/qdoc/propertynode.cpp b/src/qdoc/propertynode.cpp index 4b1cb3daf..f355608aa 100644 --- a/src/qdoc/propertynode.cpp +++ b/src/qdoc/propertynode.cpp @@ -22,6 +22,29 @@ PropertyNode::PropertyNode(Aggregate *parent, const QString &name) : Node(Proper // nothing } + +/*! + Returns a string representing an access function \a role. +*/ +QString PropertyNode::roleName(FunctionRole role) +{ + switch (role) { + case FunctionRole::Getter: + return "getter"; + case FunctionRole::Setter: + return "setter"; + case FunctionRole::Resetter: + return "resetter"; + case FunctionRole::Notifier: + return "notifier"; + case FunctionRole::Bindable: + return "bindable"; + default: + break; + } + return QString(); +} + /*! Sets this property's \e {overridden from} property to \a baseProperty, which indicates that this property @@ -34,7 +57,7 @@ PropertyNode::PropertyNode(Aggregate *parent, const QString &name) : Node(Proper */ void PropertyNode::setOverriddenFrom(const PropertyNode *baseProperty) { - for (int i = 0; i < NumFunctionRoles; ++i) { + for (qsizetype i{0}; i < (qsizetype)FunctionRole::NumFunctionRoles; ++i) { if (m_functions[i].isEmpty()) m_functions[i] = baseProperty->m_functions[i]; } @@ -58,7 +81,7 @@ void PropertyNode::setOverriddenFrom(const PropertyNode *baseProperty) */ QString PropertyNode::qualifiedDataType() const { - if (m_propertyType != Standard || m_type.startsWith(QLatin1String("const "))) + if (m_propertyType != PropertyType::StandardProperty || m_type.startsWith(QLatin1String("const "))) return m_type; if (setters().isEmpty() && resetters().isEmpty()) { @@ -102,16 +125,15 @@ bool PropertyNode::hasAccessFunction(const QString &name) const } /*! - Returns true if function \a functionNode has role \a r for this - property. + Returns the role of \a functionNode for this property. */ PropertyNode::FunctionRole PropertyNode::role(const FunctionNode *functionNode) const { - for (int i = 0; i < 4; i++) { + for (qsizetype i{0}; i < (qsizetype)FunctionRole::NumFunctionRoles; i++) { if (m_functions[i].contains(const_cast<FunctionNode *>(functionNode))) return (FunctionRole)i; } - return Notifier; + return FunctionRole::Notifier; // TODO: Figure out a better way to handle 'not found'. } QT_END_NAMESPACE diff --git a/src/qdoc/propertynode.h b/src/qdoc/propertynode.h index 4a077075c..b0a13d8d8 100644 --- a/src/qdoc/propertynode.h +++ b/src/qdoc/propertynode.h @@ -17,9 +17,9 @@ class Aggregate; class PropertyNode : public Node { public: - enum PropertyType { Standard, Bindable }; - enum FunctionRole { Getter, Setter, Resetter, Notifier }; - enum { NumFunctionRoles = Notifier + 1 }; + enum class PropertyType { StandardProperty, BindableProperty }; + enum class FunctionRole { Getter, Setter, Resetter, Notifier, Bindable, NumFunctionRoles }; + static QString roleName(FunctionRole role); PropertyNode(Aggregate *parent, const QString &name); @@ -42,10 +42,10 @@ public: { return m_functions[(int)role]; } - [[nodiscard]] const NodeList &getters() const { return functions(Getter); } - [[nodiscard]] const NodeList &setters() const { return functions(Setter); } - [[nodiscard]] const NodeList &resetters() const { return functions(Resetter); } - [[nodiscard]] const NodeList ¬ifiers() const { return functions(Notifier); } + [[nodiscard]] const NodeList &getters() const { return functions(FunctionRole::Getter); } + [[nodiscard]] const NodeList &setters() const { return functions(FunctionRole::Setter); } + [[nodiscard]] const NodeList &resetters() const { return functions(FunctionRole::Resetter); } + [[nodiscard]] const NodeList ¬ifiers() const { return functions(FunctionRole::Notifier); } [[nodiscard]] bool hasAccessFunction(const QString &name) const; FunctionRole role(const FunctionNode *functionNode) const; [[nodiscard]] bool isStored() const { return fromFlagValue(m_stored, storedDefault()); } @@ -61,8 +61,8 @@ public: private: QString m_type {}; - PropertyType m_propertyType { Standard }; - NodeList m_functions[NumFunctionRoles] {}; + PropertyType m_propertyType { PropertyType::StandardProperty }; + NodeList m_functions[(qsizetype)FunctionRole::NumFunctionRoles] {}; FlagValue m_stored { FlagValueDefault }; FlagValue m_designable { FlagValueDefault }; FlagValue m_scriptable { FlagValueDefault }; @@ -88,7 +88,7 @@ inline void PropertyNode::addSignal(FunctionNode *function, FunctionRole role) inline NodeList PropertyNode::functions() const { NodeList list; - for (int i = 0; i < NumFunctionRoles; ++i) + for (qsizetype i{0}; i < (qsizetype)FunctionRole::NumFunctionRoles; ++i) list += m_functions[i]; return list; } diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp index 3d899ffcc..cca624db8 100644 --- a/src/qdoc/qdocindexfiles.cpp +++ b/src/qdoc/qdocindexfiles.cpp @@ -466,7 +466,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader &reader, Node *current, auto *propNode = new PropertyNode(parent, name); node = propNode; if (attributes.value(QLatin1String("bindable")) == QLatin1String("true")) - propNode->setPropertyType(PropertyNode::Bindable); + propNode->setPropertyType(PropertyNode::PropertyType::BindableProperty); if (!indexUrl.isEmpty()) location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html"); @@ -1107,45 +1107,18 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node, case Node::Property: { const auto *propertyNode = static_cast<const PropertyNode *>(node); - if (propertyNode->propertyType() == PropertyNode::Bindable) + if (propertyNode->propertyType() == PropertyNode::PropertyType::BindableProperty) writer.writeAttribute("bindable", "true"); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); - const auto &getters = propertyNode->getters(); - for (const auto *fnNode : getters) { - if (fnNode) { - const auto *functionNode = static_cast<const FunctionNode *>(fnNode); - writer.writeStartElement("getter"); - writer.writeAttribute("name", functionNode->name()); - writer.writeEndElement(); // getter - } - } - const auto &setters = propertyNode->setters(); - for (const auto *fnNode : setters) { - if (fnNode) { - const auto *functionNode = static_cast<const FunctionNode *>(fnNode); - writer.writeStartElement("setter"); - writer.writeAttribute("name", functionNode->name()); - writer.writeEndElement(); // setter - } - } - const auto &resetters = propertyNode->resetters(); - for (const auto *fnNode : resetters) { - if (fnNode) { - const auto *functionNode = static_cast<const FunctionNode *>(fnNode); - writer.writeStartElement("resetter"); - writer.writeAttribute("name", functionNode->name()); - writer.writeEndElement(); // resetter - } - } - const auto ¬ifiers = propertyNode->notifiers(); - for (const auto *fnNode : notifiers) { - if (fnNode) { - const auto *functionNode = static_cast<const FunctionNode *>(fnNode); - writer.writeStartElement("notifier"); - writer.writeAttribute("name", functionNode->name()); - writer.writeEndElement(); // notifier + // Property access function names + for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) { + auto role{(PropertyNode::FunctionRole)i}; + for (const auto *fnNode : propertyNode->functions(role)) { + writer.writeStartElement(PropertyNode::roleName(role)); + writer.writeAttribute("name", fnNode->name()); + writer.writeEndElement(); } } } break; diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp index ae27ba175..ee0dc5e01 100644 --- a/src/qdoc/tree.cpp +++ b/src/qdoc/tree.cpp @@ -222,6 +222,10 @@ void Tree::resolvePropertyOverriddenFromPtrs(Aggregate *n) } /*! + Resolves access functions associated with each PropertyNode stored + in \c m_unresolvedPropertyMap, and adds them into the property node. + This allows the property node to list the access functions when + generating their documentation. */ void Tree::resolveProperties() { @@ -229,10 +233,11 @@ void Tree::resolveProperties() propEntry != m_unresolvedPropertyMap.constEnd(); ++propEntry) { PropertyNode *property = propEntry.key(); Aggregate *parent = property->parent(); - QString getterName = (*propEntry)[PropertyNode::Getter]; - QString setterName = (*propEntry)[PropertyNode::Setter]; - QString resetterName = (*propEntry)[PropertyNode::Resetter]; - QString notifierName = (*propEntry)[PropertyNode::Notifier]; + QString getterName = (*propEntry)[PropertyNode::FunctionRole::Getter]; + QString setterName = (*propEntry)[PropertyNode::FunctionRole::Setter]; + QString resetterName = (*propEntry)[PropertyNode::FunctionRole::Resetter]; + QString notifierName = (*propEntry)[PropertyNode::FunctionRole::Notifier]; + QString bindableName = (*propEntry)[PropertyNode::FunctionRole::Bindable]; for (auto it = parent->constBegin(); it != parent->constEnd(); ++it) { if ((*it)->isFunction()) { @@ -240,13 +245,15 @@ void Tree::resolveProperties() if (function->access() == property->access() && (function->status() == property->status() || function->doc().isEmpty())) { if (function->name() == getterName) { - property->addFunction(function, PropertyNode::Getter); + property->addFunction(function, PropertyNode::FunctionRole::Getter); } else if (function->name() == setterName) { - property->addFunction(function, PropertyNode::Setter); + property->addFunction(function, PropertyNode::FunctionRole::Setter); } else if (function->name() == resetterName) { - property->addFunction(function, PropertyNode::Resetter); + property->addFunction(function, PropertyNode::FunctionRole::Resetter); } else if (function->name() == notifierName) { - property->addSignal(function, PropertyNode::Notifier); + property->addSignal(function, PropertyNode::FunctionRole::Notifier); + } else if (function->name() == bindableName) { + property->addFunction(function, PropertyNode::FunctionRole::Bindable); } } } diff --git a/src/qdoc/xmlgenerator.cpp b/src/qdoc/xmlgenerator.cpp index b3792a010..2ed23d549 100644 --- a/src/qdoc/xmlgenerator.cpp +++ b/src/qdoc/xmlgenerator.cpp @@ -265,7 +265,7 @@ QString XmlGenerator::refForNode(const Node *node) break; default: if (fn->hasOneAssociatedProperty() && fn->doc().isEmpty()) { - return refForNode(fn->firstAssociatedProperty()); + return refForNode(fn->associatedProperties()[0]); } else { ref = fn->name(); if (fn->overloadNumber() != 0) |