summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2019-07-18 13:38:35 +0200
committerMartin Smith <martin.smith@qt.io>2019-07-22 14:43:40 +0200
commit466d87a7c92436e0da98005475065dc212cac71c (patch)
treee9ba90a816153c7b742109b7cdee2ebba23c94c2
parent1b9972cde24a8d8bb7f24ddbb196666456a1ce6b (diff)
downloadqttools-466d87a7c92436e0da98005475065dc212cac71c.tar.gz
qdoc: Fix the \reimp command output
When qdoc finds \reimp in a function node comment, it searches the parent class node's base classes to find the function node for the function that is overridden. When it finds this node it prints the "Reimpliments: Yyy::Xxx()" line in the current function node's documentation. This was not working correctly when the reimplemented function was in a different module. The problem was that the fact that the function in the base class had been documented was not recorded in the index file. This update fixes that problem. Now every element that was documented is given the "documented" attribute in the index file set to true. Sometimes, \reimp is used to say that a function reimplements an access function for a property in a base class. This update handles that case as well. See QToolButton::sizeHint(), for example. This change introduces a 6 new qdoc errors in QtBase about \reimp functions for which a documented base class function was not found. Change-Id: Idd444958c3118ade97642bf84781166e6ca8f036 Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r--src/qdoc/generator.cpp21
-rw-r--r--src/qdoc/node.cpp75
-rw-r--r--src/qdoc/node.h12
-rw-r--r--src/qdoc/qdocdatabase.cpp4
-rw-r--r--src/qdoc/qdocindexfiles.cpp17
5 files changed, 110 insertions, 19 deletions
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 71da36e3c..e80fa5a4c 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -1294,12 +1294,27 @@ void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *m
ClassNode* cn = static_cast<ClassNode*>(fn->parent());
const FunctionNode *overrides = cn->findOverriddenFunction(fn);
if (overrides && !overrides->isPrivate() && !overrides->parent()->isPrivate()) {
+ if (overrides->hasDoc()) {
+ Text text;
+ text << Atom::ParaLeft << "Reimplements: ";
+ QString fullName = overrides->parent()->name() + "::" + overrides->signature(false, true);
+ appendFullName(text, overrides->parent(), fullName, overrides);
+ text << "." << Atom::ParaRight;
+ generateText(text, fn, marker);
+ return;
+ }
+ }
+ const PropertyNode* sameName = cn->findOverriddenProperty(fn);
+ if (sameName && sameName->hasDoc()) {
Text text;
- text << Atom::ParaLeft << "Reimplements: ";
- QString fullName = overrides->parent()->name() + "::" + overrides->signature(false, true);
- appendFullName(text, overrides->parent(), fullName, overrides);
+ text << Atom::ParaLeft << "Reimplements an access function for property: ";
+ QString fullName = sameName->parent()->name() + "::" + sameName->name();
+ appendFullName(text, sameName->parent(), fullName, sameName);
text << "." << Atom::ParaRight;
generateText(text, fn, marker);
+ } else {
+ fn->doc().location().warning(tr("Illegal \\reimp; no documented virtual function for %1")
+ .arg(fn->plainSignature()));
}
}
}
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index c664aea63..2ec58dc3a 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -307,6 +307,7 @@ Node::Node(NodeType type, Aggregate *parent, const QString& name)
status_(Active),
indexNodeFlag_(false),
relatedNonmember_(false),
+ hadDoc_(false),
parent_(parent),
sharedCommentNode_(nullptr),
name_(name)
@@ -1084,7 +1085,7 @@ FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters
/*!
Find the function node that is a child of this node, such
that the function described has the same name and signature
- as the function described by the \a clone node.
+ as the function described by the function node \a clone.
*/
FunctionNode *Aggregate::findFunctionChild(const FunctionNode *clone)
{
@@ -1856,7 +1857,7 @@ FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
}
if (cn != nullptr) {
FunctionNode *result = cn->findFunctionChild(fn);
- if (result != nullptr && !result->isNonvirtual() && result->hasDoc())
+ if (result != nullptr && !result->isInternal() && !result->isNonvirtual() && result->hasDoc())
return result;
result = cn->findOverriddenFunction(fn);
if (result != nullptr && !result->isNonvirtual())
@@ -1868,6 +1869,44 @@ FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
}
/*!
+ \a fn is an overriding function in this class or in a class
+ derived from this class. Find the node for the property that
+ \a fn overrides in this class's children or in one of this
+ class's base classes. Return a pointer to the overridden
+ property or return 0.
+ */
+PropertyNode* ClassNode::findOverriddenProperty(const FunctionNode* fn)
+{
+ QList<RelatedClass>::Iterator bc = bases_.begin();
+ while (bc != bases_.end()) {
+ ClassNode *cn = bc->node_;
+ if (cn == nullptr) {
+ cn = QDocDatabase::qdocDB()->findClassNode(bc->path_);
+ bc->node_ = cn;
+ }
+ if (cn != nullptr) {
+ const NodeList &children = cn->childNodes();
+ NodeList::const_iterator i = children.begin();
+ while (i != children.end()) {
+ if ((*i)->isProperty()) {
+ PropertyNode *pn = static_cast<PropertyNode*>(*i);
+ if (pn->name() == fn->name() || pn->hasAccessFunction(fn->name())) {
+ if (pn->hasDoc())
+ return pn;
+ }
+ }
+ i++;
+ }
+ PropertyNode *result = cn->findOverriddenProperty(fn);
+ if (result != nullptr)
+ return result;
+ }
+ ++bc;
+ }
+ return nullptr;
+}
+
+/*!
Returns true if the class or struct represented by this class
node must be documented. If this function returns true, then
qdoc must find a qdoc comment for this class. If it returns
@@ -2732,6 +2771,38 @@ QString PropertyNode::qualifiedDataType() const
}
}
+/*!
+ Returns true if this property has an access function named \a name.
+ */
+bool PropertyNode::hasAccessFunction(const QString &name) const
+{
+ NodeList::const_iterator i = getters().begin();
+ while (i != getters().end()) {
+ if ((*i)->name() == name)
+ return true;
+ ++i;
+ }
+ i = setters().begin();
+ while (i != setters().end()) {
+ if ((*i)->name() == name)
+ return true;
+ ++i;
+ }
+ i = resetters().begin();
+ while (i != resetters().end()) {
+ if ((*i)->name() == name)
+ return true;
+ ++i;
+ }
+ i = notifiers().begin();
+ while (i != notifiers().end()) {
+ if ((*i)->name() == name)
+ return true;
+ ++i;
+ }
+ return false;
+}
+
bool QmlTypeNode::qmlOnly = false;
QMultiMap<const Node*, Node*> QmlTypeNode::inheritedBy;
diff --git a/src/qdoc/node.h b/src/qdoc/node.h
index 6deb9f8c0..b163541b9 100644
--- a/src/qdoc/node.h
+++ b/src/qdoc/node.h
@@ -258,6 +258,7 @@ public:
void setReconstitutedBrief(const QString &t) { reconstitutedBrief_ = t; }
void setParent(Aggregate* n) { parent_ = n; }
void setIndexNodeFlag(bool isIndexNode = true) { indexNodeFlag_ = isIndexNode; }
+ void setHadDoc() { hadDoc_ = true; }
virtual void setRelatedNonmember(bool b) { relatedNonmember_ = b; }
virtual void setOutputFileName(const QString& ) { }
virtual void addMember(Node* ) { }
@@ -307,7 +308,8 @@ public:
const Location& defLocation() const { return defLocation_; }
const Location& location() const { return (defLocation_.isEmpty() ? declLocation_ : defLocation_); }
const Doc& doc() const { return doc_; }
- bool hasDoc() const { return !doc_.isEmpty(); }
+ bool hasDoc() const { return (hadDoc_ || !doc_.isEmpty()); }
+ bool hadDoc() const { return hadDoc_; }
Status status() const { return status_; }
Status inheritedStatus() const;
ThreadSafeness threadSafeness() const;
@@ -369,6 +371,7 @@ private:
Status status_;
bool indexNodeFlag_ : 1;
bool relatedNonmember_ : 1;
+ bool hadDoc_ : 1;
Aggregate* parent_;
SharedCommentNode *sharedCommentNode_;
@@ -533,7 +536,7 @@ class NamespaceNode : public Aggregate
{
public:
NamespaceNode(Aggregate* parent, const QString& name) : Aggregate(Namespace, parent, name),
- seen_(false), documented_(false), tree_(nullptr), docNode_(nullptr) { }
+ seen_(false), tree_(nullptr), docNode_(nullptr) { }
virtual ~NamespaceNode();
Tree* tree() const override { return (parent() ? parent()->tree() : tree_); }
@@ -551,14 +554,11 @@ public:
bool hasDocumentedChildren() const;
void reportDocumentedChildrenInUndocumentedNamespace() const;
bool docMustBeGenerated() const override;
- void setDocumented() { documented_ = true; }
- bool wasDocumented() const { return documented_; }
void setDocNode(NamespaceNode* ns) { docNode_ = ns; }
NamespaceNode* docNode() const { return docNode_; }
private:
bool seen_;
- bool documented_;
Tree* tree_;
QString whereDocumented_;
NamespaceNode* docNode_;
@@ -633,6 +633,7 @@ public:
PropertyNode* findPropertyNode(const QString& name);
QmlTypeNode* findQmlBaseNode();
FunctionNode* findOverriddenFunction(const FunctionNode* fn);
+ PropertyNode* findOverriddenProperty(const FunctionNode* fn);
bool docMustBeGenerated() const override;
private:
@@ -1130,6 +1131,7 @@ public:
const NodeList &setters() const { return functions(Setter); }
const NodeList &resetters() const { return functions(Resetter); }
const NodeList &notifiers() const { return functions(Notifier); }
+ bool hasAccessFunction(const QString &name) const;
FunctionRole role(const FunctionNode* fn) const;
bool isStored() const { return fromFlagValue(stored_, storedDefault()); }
bool isDesignable() const { return fromFlagValue(designable_, designableDefault()); }
diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp
index aefed5615..ef2b5ab33 100644
--- a/src/qdoc/qdocdatabase.cpp
+++ b/src/qdoc/qdocdatabase.cpp
@@ -1185,14 +1185,14 @@ void QDocDatabase::resolveNamespaces()
ns = static_cast<NamespaceNode*>(n);
if (ns->isDocumentedHere())
break;
- else if (ns->wasDocumented())
+ else if (ns->hadDoc())
somewhere = ns;
ns = nullptr;
}
if (ns) {
foreach (Node *n, namespaces) {
NamespaceNode* NS = static_cast<NamespaceNode*>(n);
- if (NS->wasDocumented() && NS != ns) {
+ if (NS->hadDoc() && NS != ns) {
ns->doc().location().warning(tr("Namespace %1 documented more than once")
.arg(NS->name()));
NS->doc().location().warning(tr("...also seen here"));
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index 617c132f2..efd9adefd 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -204,11 +204,6 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
else if (!indexUrl.isNull())
location = Location(name.toLower() + ".html");
- if (attributes.hasAttribute(QLatin1String("documented"))) {
- if (attributes.value(QLatin1String("documented")) == QLatin1String("true"))
- ns->setDocumented();
- }
-
} else if (elementName == QLatin1String("class") || elementName == QLatin1String("struct") ||
elementName == QLatin1String("union")) {
Node::NodeType type = Node::Class;
@@ -604,6 +599,11 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
node->setSince(since);
}
+ if (attributes.hasAttribute(QLatin1String("documented"))) {
+ if (attributes.value(QLatin1String("documented")) == QLatin1String("true"))
+ node->setHadDoc();
+ }
+
QString groupsAttr = attributes.value(QLatin1String("groups")).toString();
if (!groupsAttr.isEmpty()) {
QStringList groupNames = groupsAttr.split(QLatin1Char(','));
@@ -936,6 +936,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
if (!node->since().isEmpty())
writer.writeAttribute("since", node->since());
+ if (node->hasDoc())
+ writer.writeAttribute("documented", "true");
+
QString brief = node->doc().trimmedBriefText(node->name()).toString();
switch (node->nodeType()) {
case Node::Class:
@@ -970,7 +973,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
case Node::HeaderFile:
{
const HeaderNode* hn = static_cast<const HeaderNode*>(node);
- writer.writeAttribute("documented", hn->hasDoc() ? "true" : "false");
if (!hn->physicalModuleName().isEmpty())
writer.writeAttribute("module", hn->physicalModuleName());
if (!hn->groupNames().isEmpty())
@@ -985,7 +987,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
case Node::Namespace:
{
const NamespaceNode* ns = static_cast<const NamespaceNode*>(node);
- writer.writeAttribute("documented", ns->hasDoc() ? "true" : "false");
if (!ns->physicalModuleName().isEmpty())
writer.writeAttribute("module", ns->physicalModuleName());
if (!ns->groupNames().isEmpty())
@@ -1333,6 +1334,8 @@ void QDocIndexFiles::generateFunctionSection(QXmlStreamWriter &writer, FunctionN
writer.writeAttribute("lineno", QString("%1").arg(declLocation.lineNo()));
}
+ if (fn->hasDoc())
+ writer.writeAttribute("documented", "true");
if (fn->isRelatedNonmember())
writer.writeAttribute("related", "true");
if (!fn->since().isEmpty())