summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTopi Reinio <topi.reinio@theqtcompany.com>2016-06-21 11:59:13 +0200
committerTopi Reiniƶ <topi.reinio@theqtcompany.com>2016-08-16 11:27:18 +0000
commit3c5fa29f78816d8cc7fd9fa6e9462e2a9f283f64 (patch)
tree67dc25d7396fbdb45dd0e8983f0ea3cc5e3749a9
parent72901b9295394034ac52cd6174e6b50fa19a317d (diff)
downloadqttools-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.cpp1
-rw-r--r--src/qdoc/generator.cpp4
-rw-r--r--src/qdoc/htmlgenerator.cpp2
-rw-r--r--src/qdoc/node.cpp17
-rw-r--r--src/qdoc/node.h10
-rw-r--r--src/qdoc/qdocdatabase.cpp10
-rw-r--r--src/qdoc/qmlvisitor.cpp5
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;
}