diff options
author | Topi Reinio <topi.reinio@theqtcompany.com> | 2016-06-21 11:59:13 +0200 |
---|---|---|
committer | Topi Reiniƶ <topi.reinio@theqtcompany.com> | 2016-08-16 11:27:18 +0000 |
commit | 3c5fa29f78816d8cc7fd9fa6e9462e2a9f283f64 (patch) | |
tree | 67dc25d7396fbdb45dd0e8983f0ea3cc5e3749a9 | |
parent | 72901b9295394034ac52cd6174e6b50fa19a317d (diff) | |
download | qttools-3c5fa29f78816d8cc7fd9fa6e9462e2a9f283f64.tar.gz |
qdoc: Improve resolution of QML type inheritance
QDoc maintains a global map of base types for all QML types. This
caused issues whenever QML modules have conflicting type names;
for example, types from Qt Quick Controls (v1) were incorrectly
marked as deriving from QQC v2 'Control' type.
To improve the situation, make following changes:
- Manage 'inherited by' map in a single location. Types are
added to this map in a pre-generate step
(QDocDatabase::resolveQmlInheritance()) after parsing all
sources. This allows better control of searching - if the
QML type node has an import list, the search is now
always based on it.
- Add a safeguard against using a base type from a module
with major version different to the import statement.
- Use node pointers as keys in 'Inherited by' map,
instead of type-name strings.
Task-number: QTBUG-53529
Change-Id: I6665a520c9197fa90e84d67b12e3405b5b3f0901
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Reviewed-by: Martin Smith <martin.smith@theqtcompany.com>
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 1 | ||||
-rw-r--r-- | src/qdoc/generator.cpp | 4 | ||||
-rw-r--r-- | src/qdoc/htmlgenerator.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/node.cpp | 17 | ||||
-rw-r--r-- | src/qdoc/node.h | 10 | ||||
-rw-r--r-- | src/qdoc/qdocdatabase.cpp | 10 | ||||
-rw-r--r-- | src/qdoc/qmlvisitor.cpp | 5 |
7 files changed, 22 insertions, 27 deletions
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 5b7792d32..57cd1e917 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -970,7 +970,6 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (node->isQmlType() || node->isJsType()) { QmlTypeNode* qmlType = static_cast<QmlTypeNode*>(node); qmlType->setQmlBaseName(arg); - QmlTypeNode::addInheritedBy(arg,node); } } else if (command == COMMAND_QMLINSTANTIATES) { diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index c043f5170..b91626460 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -1232,11 +1232,11 @@ void Generator::generateQmlInheritedBy(const QmlTypeNode* qcn, { if (qcn) { NodeList subs; - QmlTypeNode::subclasses(qcn->name(),subs); + QmlTypeNode::subclasses(qcn, subs); if (!subs.isEmpty()) { Text text; text << Atom::ParaLeft << "Inherited by "; - appendSortedQmlNames(text,qcn,subs); + appendSortedQmlNames(text, qcn, subs); text << Atom::ParaRight; generateText(text, qcn, marker); } diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index 2b88f007f..c4ce7e686 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -2360,7 +2360,7 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) //add the inherited-by to the map NodeList subs; - QmlTypeNode::subclasses(qcn->name(), subs); + QmlTypeNode::subclasses(qcn, subs); if (!subs.isEmpty()) { text.clear(); text << Atom::ParaLeft; diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 47c939f8b..d530c180b 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -2433,7 +2433,7 @@ QString PropertyNode::qualifiedDataType() const } bool QmlTypeNode::qmlOnly = false; -QMultiMap<QString,Node*> QmlTypeNode::inheritedBy; +QMultiMap<const Node*, Node*> QmlTypeNode::inheritedBy; /*! Constructs a Qml class node. The new node has the given @@ -2479,18 +2479,18 @@ void QmlTypeNode::terminate() Record the fact that QML class \a base is inherited by QML class \a sub. */ -void QmlTypeNode::addInheritedBy(const QString& base, Node* sub) +void QmlTypeNode::addInheritedBy(const Node *base, Node* sub) { if (sub->isInternal()) return; - if (inheritedBy.constFind(base,sub) == inheritedBy.constEnd()) - inheritedBy.insert(base,sub); + if (!inheritedBy.contains(base, sub)) + inheritedBy.insert(base, sub); } /*! Loads the list \a subs with the nodes of all the subclasses of \a base. */ -void QmlTypeNode::subclasses(const QString& base, NodeList& subs) +void QmlTypeNode::subclasses(const Node *base, NodeList &subs) { subs.clear(); if (inheritedBy.count(base) > 0) { @@ -2498,13 +2498,6 @@ void QmlTypeNode::subclasses(const QString& base, NodeList& subs) } } -QmlTypeNode* QmlTypeNode::qmlBaseNode() -{ - if (!qmlBaseNode_ && !qmlBaseName_.isEmpty()) { - qmlBaseNode_ = QDocDatabase::qdocDB()->findQmlType(qmlBaseName_); - } - return qmlBaseNode_; -} /*! If this QML type node has a base type node, diff --git a/src/qdoc/node.h b/src/qdoc/node.h index 4b3549961..eeb16e1b4 100644 --- a/src/qdoc/node.h +++ b/src/qdoc/node.h @@ -640,7 +640,7 @@ public: virtual bool isInternal() const Q_DECL_OVERRIDE { return (status() == Internal); } virtual QString qmlFullBaseName() const Q_DECL_OVERRIDE; virtual QString obsoleteLink() const Q_DECL_OVERRIDE { return obsoleteLink_; } - virtual void setObsoleteLink(const QString& t) Q_DECL_OVERRIDE { obsoleteLink_ = t; }; + virtual void setObsoleteLink(const QString& t) Q_DECL_OVERRIDE { obsoleteLink_ = t; } virtual QString logicalModuleName() const Q_DECL_OVERRIDE; virtual QString logicalModuleVersion() const Q_DECL_OVERRIDE; virtual QString logicalModuleIdentifier() const Q_DECL_OVERRIDE; @@ -652,17 +652,17 @@ public: const QString& qmlBaseName() const { return qmlBaseName_; } void setQmlBaseName(const QString& name) { qmlBaseName_ = name; } bool qmlBaseNodeNotSet() const { return (qmlBaseNode_ == 0); } - virtual QmlTypeNode* qmlBaseNode() Q_DECL_OVERRIDE; + virtual QmlTypeNode* qmlBaseNode() Q_DECL_OVERRIDE { return qmlBaseNode_; } void setQmlBaseNode(QmlTypeNode* b) { qmlBaseNode_ = b; } void requireCppClass() { cnodeRequired_ = true; } bool cppClassRequired() const { return cnodeRequired_; } - static void addInheritedBy(const QString& base, Node* sub); - static void subclasses(const QString& base, NodeList& subs); + static void addInheritedBy(const Node *base, Node* sub); + static void subclasses(const Node *base, NodeList& subs); static void terminate(); public: static bool qmlOnly; - static QMultiMap<QString,Node*> inheritedBy; + static QMultiMap<const Node*, Node*> inheritedBy; private: bool abstract_; diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp index 09471c6e3..3b47d6b6e 100644 --- a/src/qdoc/qdocdatabase.cpp +++ b/src/qdoc/qdocdatabase.cpp @@ -1475,15 +1475,20 @@ void QDocDatabase::resolveQmlInheritance(Aggregate* root) QmlTypeNode* qcn = static_cast<QmlTypeNode*>(child); if (qcn->qmlBaseNodeNotSet() && !qcn->qmlBaseName().isEmpty()) { QmlTypeNode* bqcn = static_cast<QmlTypeNode*>(previousSearches.value(qcn->qmlBaseName())); - if (bqcn && (bqcn != qcn)) + if (bqcn && (bqcn != qcn)) { qcn->setQmlBaseNode(bqcn); + QmlTypeNode::addInheritedBy(bqcn, qcn); + } else { if (!qcn->importList().isEmpty()) { const ImportList& imports = qcn->importList(); for (int i=0; i<imports.size(); ++i) { bqcn = findQmlType(imports[i], qcn->qmlBaseName()); - if (bqcn && (bqcn != qcn)) + if (bqcn && (bqcn != qcn)) { + if (bqcn->logicalModuleVersion()[0] != imports[i].version_[0]) + bqcn = 0; // Safeguard for QTBUG-53529 break; + } } } if (bqcn == 0) { @@ -1491,6 +1496,7 @@ void QDocDatabase::resolveQmlInheritance(Aggregate* root) } if (bqcn && (bqcn != qcn)) { qcn->setQmlBaseNode(bqcn); + QmlTypeNode::addInheritedBy(bqcn, qcn); previousSearches.insert(qcn->qmlBaseName(), bqcn); } #if 0 diff --git a/src/qdoc/qmlvisitor.cpp b/src/qdoc/qmlvisitor.cpp index 4f380262f..033b37e43 100644 --- a/src/qdoc/qmlvisitor.cpp +++ b/src/qdoc/qmlvisitor.cpp @@ -509,7 +509,6 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation, else if (node->isQmlType() || node->isJsType()) { QmlTypeNode *qmlType = static_cast<QmlTypeNode*>(node); qmlType->setQmlBaseName(args[0].first); - QmlTypeNode::addInheritedBy(args[0].first,node); } } else if (command == COMMAND_QMLDEFAULT) { @@ -592,10 +591,8 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition) component->setTitle(name); component->setImportList(importList); importList.clear(); - if (applyDocumentation(definition->firstSourceLocation(), component)) { - QmlTypeNode::addInheritedBy(type, component); + if (applyDocumentation(definition->firstSourceLocation(), component)) component->setQmlBaseName(type); - } current = component; } |