From 0f3c3156c4955500134ccbdc40b0e2f254442ad1 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 14 Jan 2021 13:13:45 +0100 Subject: qdoc: Allow overriding documentation from abstract QML base types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QDoc replicates property/function documentation from abstract QML base types to the reference of the inheriting type. Attempting to override a member documentation for the inheriting type resulted in duplication: both the base and inheriting docs were rendered. As the decision on what's shown on the type reference is deferred to constructing the sections, implement this logic there. Modify FunctionNode::compare() so that we can compare methods from different parents, allowing us to override a specific overload of a method. Pick-to: 6.0 Fixes: QTBUG-89913 Change-Id: I3fb56c747e72b5a6ff387667e035a959e8f1c479 Reviewed-by: Topi Reiniƶ --- src/qdoc/aggregate.cpp | 28 ++++++++++++---------------- src/qdoc/cppcodeparser.cpp | 2 +- src/qdoc/functionnode.cpp | 13 ++++++++----- src/qdoc/functionnode.h | 2 +- src/qdoc/sections.cpp | 15 +++++++++++++++ 5 files changed, 37 insertions(+), 23 deletions(-) (limited to 'src/qdoc') diff --git a/src/qdoc/aggregate.cpp b/src/qdoc/aggregate.cpp index 16b6d5031..50fe81bc3 100644 --- a/src/qdoc/aggregate.cpp +++ b/src/qdoc/aggregate.cpp @@ -102,20 +102,17 @@ Node *Aggregate::findChildNode(const QString &name, Node::Genus genus, int findF if (node) return node; } else { - NodeList nodes = m_nonfunctionMap.values(name); - if (!nodes.isEmpty()) { - for (int i = 0; i < nodes.size(); ++i) { - Node *node = nodes.at(i); - if (genus == node->genus()) { - if (findFlags & TypesOnly) { - if (!node->isTypedef() && !node->isClassNode() && !node->isQmlType() - && !node->isQmlBasicType() && !node->isJsType() - && !node->isJsBasicType() && !node->isEnumType()) - continue; - } else if (findFlags & IgnoreModules && node->isModule()) + const NodeList &nodes = m_nonfunctionMap.values(name); + for (auto *node : nodes) { + if (genus == node->genus()) { + if (findFlags & TypesOnly) { + if (!node->isTypedef() && !node->isClassNode() && !node->isQmlType() + && !node->isQmlBasicType() && !node->isJsType() + && !node->isJsBasicType() && !node->isEnumType()) continue; - return node; - } + } else if (findFlags & IgnoreModules && node->isModule()) + continue; + return node; } } } @@ -166,9 +163,8 @@ void Aggregate::findChildren(const QString &name, NodeVector &nodes) const */ Node *Aggregate::findNonfunctionChild(const QString &name, bool (Node::*isMatch)() const) { - NodeList nodes = m_nonfunctionMap.values(name); - for (int i = 0; i < nodes.size(); ++i) { - Node *node = nodes.at(i); + const NodeList &nodes = m_nonfunctionMap.values(name); + for (auto *node : nodes) { if ((node->*(isMatch))()) return node; } diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index d49566ba9..c3f673b8d 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -791,7 +791,7 @@ FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QStri macro->setLocation(location); macro->setReturnType(returnType); macro->setParameters(params); - if (oldMacroNode && macro->compare(oldMacroNode)) { + if (macro->compare(oldMacroNode)) { location.warning(QStringLiteral("\\macro %1 documented more than once").arg(macroArg)); oldMacroNode->doc().location().warning(QStringLiteral("(The previous doc is here)")); } diff --git a/src/qdoc/functionnode.cpp b/src/qdoc/functionnode.cpp index 8f00e508f..53694e5b5 100644 --- a/src/qdoc/functionnode.cpp +++ b/src/qdoc/functionnode.cpp @@ -546,16 +546,19 @@ void FunctionNode::debug() const } /*! - Compares this FunctionNode to the FunctionNode pointed to - by \a functionNode. Returns true if they describe the same function. + Compares this FunctionNode to \a node. If \a sameParent is \c true, compares + also the parent of the two nodes. Returns \c true if they describe + the same function. */ -bool FunctionNode::compare(const FunctionNode *functionNode) const +bool FunctionNode::compare(const Node *node, bool sameParent) const { - if (functionNode == nullptr) + if (!node || !node->isFunction()) return false; + + const auto *functionNode = static_cast(node); if (metaness() != functionNode->metaness()) return false; - if (parent() != functionNode->parent()) + if (sameParent && parent() != functionNode->parent()) return false; if (m_returnType != functionNode->returnType()) return false; diff --git a/src/qdoc/functionnode.h b/src/qdoc/functionnode.h index bb8e4b28c..55870b1cc 100644 --- a/src/qdoc/functionnode.h +++ b/src/qdoc/functionnode.h @@ -170,7 +170,7 @@ public: bool hasTag(const QString &tag) const override { return (m_tag == tag); } void setTag(const QString &tag) { m_tag = tag; } const QString &tag() const { return m_tag; } - bool compare(const FunctionNode *functionNode) const; + bool compare(const Node *node, bool sameParent = true) const; bool isIgnored() const; bool hasOverloads() const; void clearOverloadFlag() { m_overloadFlag = false; } diff --git a/src/qdoc/sections.cpp b/src/qdoc/sections.cpp index 9544311c1..1b3d0ab76 100644 --- a/src/qdoc/sections.cpp +++ b/src/qdoc/sections.cpp @@ -1014,6 +1014,21 @@ void Sections::buildStdQmlTypeRefPageSections() if (n->isInternal()) continue; + // Skip overridden property/function documentation from abstract base type + if (qtn != aggregate_ && qtn->isAbstract()) { + NodeList candidates; + aggregate_->findChildren(n->name(), candidates); + if (std::any_of(candidates.cbegin(), candidates.cend(), [&n](const Node *c) { + if (c->nodeType() == n->nodeType()) { + if (!n->isFunction() || static_cast(n)->compare(c, false)) + return true; + } + return false; + })) { + continue; + } + } + if (!n->isSharedCommentNode() || n->isPropertyGroup()) allMembers.add(classMap, n); -- cgit v1.2.1