qdoc: inherited members do not show up for QML components

This was a regression bug owing to a big qdoc cleanup
for Qt5. But the way QML inheritance had been handled
was not a good design, so it has been changed here.
When a .qml file is parsed by qdoc, the base type of
the QML component is detected, and its name is stored
in qdoc's tree node for the component. After qdoc has
parsed all the QML files, it traverses the tree, and
for each QML component that has a base type name but
no base type node pointer yet, it searches the tree
for the base type node and stores the pointer to
the node in the node for the components. Then when
the output generator generates the doc page for the
component, it has access to all the inherited members
in the base type.

Task-number: QTBUG-29569
Change-Id: Ib4958d05f55fa48a572f8ca51ffd57712f29bbc7
Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
Reviewed-by: Martin Smith <martin.smith@digia.com>
This commit is contained in:
Martin Smith 2013-02-12 09:40:02 +01:00 committed by The Qt Project
parent d1fe252d6a
commit cd84491aad
10 changed files with 59 additions and 28 deletions

View File

@ -1165,8 +1165,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
}
++c;
}
if (qcn->qmlBase() != 0) {
qcn = static_cast<const QmlClassNode*>(qcn->qmlBase());
if (qcn->qmlBaseNode() != 0) {
qcn = static_cast<const QmlClassNode*>(qcn->qmlBaseNode());
if (!qcn->isAbstract())
qcn = 0;
}
@ -1241,8 +1241,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
}
++c;
}
if (qcn->qmlBase() != 0) {
qcn = static_cast<const QmlClassNode*>(qcn->qmlBase());
if (qcn->qmlBaseNode() != 0) {
qcn = static_cast<const QmlClassNode*>(qcn->qmlBaseNode());
if (!qcn->isAbstract())
qcn = 0;
}
@ -1287,7 +1287,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
}
++c;
}
const DocNode* dn = current->qmlBase();
const DocNode* dn = current->qmlBaseNode();
if (dn) {
if (dn->subType() == Node::QmlClass)
current = static_cast<const QmlClassNode*>(dn);

View File

@ -951,11 +951,10 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == arg)
doc.location().warning(tr("%1 tries to inherit itself").arg(arg));
else {
setLink(node, Node::InheritsLink, arg);
if (node->subType() == Node::QmlClass) {
QmlClassNode::addInheritedBy(arg,node);
}
else if (node->subType() == Node::QmlClass) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(arg);
QmlClassNode::addInheritedBy(arg,node);
}
}
else if (command == COMMAND_QMLINSTANTIATES) {

View File

@ -4198,7 +4198,7 @@ void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker*
{
if (!qcn)
return;
const DocNode* base = qcn->qmlBase();
const DocNode* base = qcn->qmlBaseNode();
if (base) {
writeStartTag(DT_qmlInherits);
//writeStartTag(DT_qmlTypeDef);

View File

@ -3869,7 +3869,7 @@ void HtmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* mar
{
if (!qcn)
return;
const DocNode* base = qcn->qmlBase();
const DocNode* base = qcn->qmlBaseNode();
if (base) {
Text text;
text << Atom::ParaLeft << "Inherits ";

View File

@ -2097,7 +2097,7 @@ QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
abstract_(false),
cnodeRequired_(false),
cnode_(0),
base_(0)
baseNode_(0)
{
int i = 0;
if (name.startsWith("QML:")) {

View File

@ -131,8 +131,7 @@ public:
NextLink,
PreviousLink,
ContentsLink,
IndexLink,
InheritsLink /*,
IndexLink /*,
GlossaryLink,
CopyrightLink,
ChapterLink,
@ -546,8 +545,10 @@ public:
virtual void setAbstract(bool b) { abstract_ = b; }
const ImportList& importList() const { return importList_; }
void setImportList(const ImportList& il) { importList_ = il; }
const DocNode* qmlBase() const { return base_; }
void setQmlBase(DocNode* b) { base_ = b; }
const QString& qmlBaseName() const { return baseName_; }
void setQmlBaseName(const QString& name) { baseName_ = name; }
const DocNode* qmlBaseNode() const { return baseNode_; }
void setQmlBaseNode(DocNode* b) { baseNode_ = b; }
void requireCppClass() { cnodeRequired_ = true; }
bool cppClassRequired() const { return cnodeRequired_; }
static void addInheritedBy(const QString& base, Node* sub);
@ -562,7 +563,8 @@ private:
bool abstract_;
bool cnodeRequired_;
ClassNode* cnode_;
DocNode* base_;
QString baseName_;
DocNode* baseNode_;
ImportList importList_;
};

View File

@ -623,6 +623,7 @@ const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key) const
to generating documentation.
*/
void QDocDatabase::resolveIssues() {
resolveQmlInheritance(treeRoot());
resolveTargets(treeRoot());
tree_->resolveCppToQmlLinks();
}
@ -821,6 +822,35 @@ QString QDocDatabase::findTarget(const QString& target, const Node* node) const
return QString();
}
/*!
For each QML Type node in the tree beginning at \a root,
if it has a QML base type name but its QML base type node
pointer is 0, use the QML base type name to look up the
base type node. If the node is found in the tree, set the
node's QML base type node pointer.
*/
void QDocDatabase::resolveQmlInheritance(InnerNode* root)
{
// Dop we need recursion?
foreach (Node* child, root->childNodes()) {
if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
if ((qcn->qmlBaseNode() == 0) && !qcn->qmlBaseName().isEmpty()) {
QmlClassNode* bqcn = findQmlType(QString(), qcn->qmlBaseName());
if (bqcn) {
qcn->setQmlBaseNode(bqcn);
}
#if 0
else {
qDebug() << "Unable to resolve QML base type:" << qcn->qmlBaseName()
<< "for QML type:" << qcn->name();
}
#endif
}
}
}
}
/*!
*/
void QDocDatabase::resolveTargets(InnerNode* root)

View File

@ -140,6 +140,7 @@ class QDocDatabase
Tree* tree() { return tree_; }
NamespaceNode* treeRoot() { return tree_->root(); }
void resolveInheritance() { tree_->resolveInheritance(); }
void resolveQmlInheritance(InnerNode* root);
void resolveIssues();
void fixInheritance() { tree_->fixInheritance(); }
void resolveProperties() { tree_->resolveProperties(); }

View File

@ -106,7 +106,7 @@ QmlDocVisitor::~QmlDocVisitor()
}
/*!
Returns the location of thre nearest comment above the \a offset.
Returns the location of the nearest comment above the \a offset.
*/
QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) const
{
@ -322,11 +322,10 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == args[0].first)
doc.location().warning(tr("%1 tries to inherit itself").arg(args[0].first));
else {
CodeParser::setLink(node, Node::InheritsLink, args[0].first);
if (node->subType() == Node::QmlClass) {
QmlClassNode::addInheritedBy(args[0].first,node);
}
else if (node->subType() == Node::QmlClass) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(args[0].first);
QmlClassNode::addInheritedBy(args[0].first,node);
}
}
else if (command == COMMAND_QMLDEFAULT) {
@ -389,11 +388,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
QmlClassNode *component = new QmlClassNode(current, name);
component->setTitle(name);
component->setImportList(importList);
if (applyDocumentation(definition->firstSourceLocation(), component)) {
QmlClassNode::addInheritedBy(type, component);
if (!component->links().contains(Node::InheritsLink))
component->setLink(Node::InheritsLink, type, type);
component->setQmlBaseName(type);
}
current = component;
}

View File

@ -399,10 +399,12 @@ void Tree::addPropertyFunction(PropertyNode* property,
/*!
This function resolves inheritance and reimplementation settings
for each class node found in the namspace beginning ar \a rootNode.
for each C++ class node found in the namspace beginning at \a rootNode.
If it finds another namespace node in the child list of \a rootNode,
it calls itself recursively. For each child of \a rootNode that is a
class node, it calls the other resolveInheritance() function.
This function does not resolve QML inheritance.
*/
void Tree::resolveInheritance(NamespaceNode* rootNode)
{