summaryrefslogtreecommitdiff
path: root/src/qdoc/qmlvisitor.cpp
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2018-07-06 09:54:36 +0200
committerMartin Smith <martin.smith@qt.io>2018-10-23 14:15:23 +0000
commitfcdb57ed07d36b0b72f41da974550f505a162077 (patch)
treea456bc1ca3002fb1e90ab689f81247b65782c790 /src/qdoc/qmlvisitor.cpp
parent2144c9bb23e672ad76170ba605d8155dda0509cd (diff)
downloadqttools-fcdb57ed07d36b0b72f41da974550f505a162077.tar.gz
qdoc: Reorganize Qdoc's Node class hierarchy
This is a significant refactoring of QDoc's Node class hierarchy, which is meant to make maintenance of QDoc easier, and which will enable further development of QDoc as a library and plugin. Class DocumentNode is renamed to class PageNode, and it inherits the Node base class instead of inheriting class Aggregate. Class Aggregate inherits class PageNode instead of the Node base class. IOW, class DocumentNode and class Aggregate have swapped places in the class hierarchy, and DocumentNode has changed its name to PageNode. This makes the Node hierarchy more logical because: 1. Every entity that causes a documentation page to be written is a PageNode. 2. Only those PageNodes that can have children are Aggregates. Thus the HeaderFile subtype of the former DocumentNode has been promoted to class HeaderNode, which is a subclass of Aggregate. This makes sense because the old HeaderFile DocumentNode caused a documentation page to be generated, and that documentation page was very much like a class reference page. The \headerfile command is not used a lot in the Qt documentation but there are some useful cases, so it is worth making a subclass of Aggregate to handle them. The HeaderNode is now processed very much like the ClassNode and the NamespaceNode. Developers should be advised that isDocumentNode() is now isPageNode(), but isPageNode() can no longer be used to decide if an Aggregate* is a PageNode* (DocumentNode*), because Aggregate is now a subclass of PageNode. So a new convenience function is added: isTextPageNode(), which returns true if your Node* is a PageNode but not an Aggregate. IOW, isTextPageNode() returns true if the Node* is some kind of text page that doesn't represent a C++ or QML declaration. Class ExampleNode is a subclass of PageNode, not Aggregate. IOW, an ExampleNode no longer has children. Instead, the example files and example images that belong to the example are stored as string lists. It seems to work, but there might be problems in help files I haven't found yet. Class CollectionNode is now a subclass of Node instead of LeafNode. Class LeafNode is removed. All former subclasses of LeafNode are now subclasses of Node. This change also removes a lot of DITA bitrot. Work remaining to be done: 1. Remove the remaining DITA bitrot. 2. Consider letting QmlProperty and JsProperty be instances of Property and use the Genus value to distiguish them. 3. Also consider replacing QmlPropertyGroup and JsPropertyGroup with a single PropertyGroup and use the Genus value to distinguish them. This update also rearranges the parameters passed to the clang parser, and it removes some diff conflict lines that got saved by mistake. Change-Id: I918f83030c48d96db4a5588ab53458f221a5374e Reviewed-by: Martin Smith <martin.smith@qt.io> Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Diffstat (limited to 'src/qdoc/qmlvisitor.cpp')
-rw-r--r--src/qdoc/qmlvisitor.cpp71
1 files changed, 39 insertions, 32 deletions
diff --git a/src/qdoc/qmlvisitor.cpp b/src/qdoc/qmlvisitor.cpp
index d54378331..0bce4c376 100644
--- a/src/qdoc/qmlvisitor.cpp
+++ b/src/qdoc/qmlvisitor.cpp
@@ -204,9 +204,12 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod
if (topicsUsed.size() > 0) {
for (int i=0; i<topicsUsed.size(); ++i) {
QString topic = topicsUsed.at(i).topic;
+ if (!topic.startsWith(QLatin1String("qml")) && !topic.startsWith(QLatin1String("js")))
+ continue; // maybe a qdoc warning here? mws 18/07/18
QString args = topicsUsed.at(i).args;
- if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY) ||
- (topic == COMMAND_JSPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY)) {
+ if (topic == COMMAND_JSTYPE) {
+ node->changeType(Node::QmlType, Node::JsType);
+ } else if (topic.endsWith(QLatin1String("property"))) {
QmlPropArgs qpa;
if (splitQmlPropertyArg(doc, args, qpa)) {
if (qpa.name_ == nodePassedIn->name()) {
@@ -214,8 +217,7 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod
nodePassedIn->setDataType(qpa.type_);
}
else {
- bool isAttached = (topic == COMMAND_QMLATTACHEDPROPERTY) ||
- (topic == COMMAND_JSATTACHEDPROPERTY);
+ bool isAttached = topic.contains(QLatin1String("attached"));
QmlPropertyNode* n = parent->hasQmlProperty(qpa.name_, isAttached);
if (n == 0)
n = new QmlPropertyNode(parent, qpa.name_, qpa.type_, isAttached);
@@ -226,20 +228,19 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod
n->setDefault();
if (isAttached)
n->setReadOnly(0);
- if ((topic == COMMAND_JSPROPERTY) ||
- (topic == COMMAND_JSATTACHEDPROPERTY))
- n->setGenus(Node::JS);
+ if ((topic == COMMAND_JSPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY))
+ n->changeType(Node::QmlProperty, Node::JsProperty);
nodes.append(n);
}
}
else
qDebug() << " FAILED TO PARSE QML OR JS PROPERTY:" << topic << args;
- }
- else if ((topic == COMMAND_QMLMETHOD) || (topic == COMMAND_QMLATTACHEDMETHOD) ||
- (topic == COMMAND_JSMETHOD) || (topic == COMMAND_JSATTACHEDMETHOD)) {
+ } else if (topic.endsWith(QLatin1String("method"))) {
if (node->isFunction()) {
FunctionNode* fn = static_cast<FunctionNode*>(node);
QmlSignatureParser qsp(fn, args, doc.location());
+ if (topic == COMMAND_JSMETHOD || topic == COMMAND_JSATTACHEDMETHOD)
+ fn->changeMetaness(FunctionNode::QmlMethod, FunctionNode::JsMethod);
}
}
}
@@ -292,7 +293,7 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
/*
This code is really hard to follow... sorry. The loop is there to match
Alpha::Beta::Gamma::...::Omega.
- */
+ */
for (;;) {
bool virgin = true;
@@ -341,7 +342,7 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
/*
The usual case: Look for an optional identifier, then for
some array brackets.
- */
+ */
dataType->appendHotspot();
if ((var != 0) && match(Tok_Ident))
@@ -580,13 +581,18 @@ QString QmlDocVisitor::getFullyQualifiedId(QQmlJS::AST::UiQualifiedId *id)
qdoc database. Increment the object nesting level, which is used
to test whether we are at the public API level. The public level
is level 1.
-*/
+
+ Note that this visit() function creates the qdoc object node as a
+ QmlType. If it is actually a JsType, this fact is discovered when
+ the qdoc comment is applied to the node. The node's typet is then
+ changed to JsType.
+ */
bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
{
QString type = getFullyQualifiedId(definition->qualifiedTypeNameId);
nestingLevel++;
- if (current->type() == Node::Namespace) {
+ if (current->nodeType() == Node::Namespace) {
QmlTypeNode *component = new QmlTypeNode(current, name);
component->setTitle(name);
component->setImportList(importList);
@@ -680,7 +686,7 @@ QString qualifiedIdToString(QQmlJS::AST::UiQualifiedId *node)
Visits the public \a member declaration, which can be a
signal or a property. It is a custom signal or property.
Only visit the \a member if the nestingLevel is 1.
-*/
+ */
bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
{
if (nestingLevel > 1) {
@@ -692,19 +698,19 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
if (current->isQmlType() || current->isJsType()) {
QmlTypeNode *qmlType = static_cast<QmlTypeNode *>(current);
if (qmlType) {
-
+ FunctionNode::Metaness metaness = FunctionNode::QmlSignal;
+ if (qmlType->isJsType())
+ metaness = FunctionNode::JsSignal;
QString name = member->name.toString();
- FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false);
-
+ FunctionNode *newSignal = new FunctionNode(metaness, current, name);
QVector<Parameter> parameters;
for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
const QString type = qualifiedIdToString(it->type);
if (!type.isEmpty() && !it->name.isEmpty())
parameters.append(Parameter(type, QString(), it->name.toString()));
}
-
- qmlSignal->setParameters(parameters);
- applyDocumentation(member->firstSourceLocation(), qmlSignal);
+ newSignal->setParameters(parameters);
+ applyDocumentation(member->firstSourceLocation(), newSignal);
}
}
break;
@@ -718,11 +724,8 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
if (qmlType) {
QString name = member->name.toString();
QmlPropertyNode* qmlPropNode = qmlType->hasQmlProperty(name);
- if (qmlPropNode == 0) {
+ if (qmlPropNode == 0)
qmlPropNode = new QmlPropertyNode(qmlType, name, type, false);
- if (current->isJsType())
- qmlPropNode->setGenus(Node::JS);
- }
qmlPropNode->setReadOnly(member->isReadonlyMember);
if (member->isDefaultMember)
qmlPropNode->setDefault();
@@ -763,10 +766,11 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
if (current->isQmlType() || current->isJsType()) {
QmlTypeNode* qmlType = static_cast<QmlTypeNode*>(current);
if (qmlType) {
+ FunctionNode::Metaness metaness = FunctionNode::QmlMethod;
+ if (qmlType->isJsType())
+ metaness = FunctionNode::JsMethod;
QString name = fd->name.toString();
- FunctionNode* qmlMethod = new FunctionNode(Node::QmlMethod, current, name, false);
- if (current->isJsType())
- qmlMethod->setGenus(Node::JS);
+ FunctionNode* newMethod = new FunctionNode(metaness, current, name);
int overloads = 0;
NodeList::ConstIterator i = current->childNodes().constBegin();
while (i != current->childNodes().constEnd()) {
@@ -775,7 +779,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
i++;
}
if (overloads > 1)
- qmlMethod->setOverloadFlag(true);
+ newMethod->setOverloadFlag(true);
QVector<Parameter> parameters;
QQmlJS::AST::FormalParameterList* formals = fd->formals;
if (formals) {
@@ -784,9 +788,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
parameters.append(Parameter(QString(), QString(), fpl->element->bindingIdentifier.toString()));
fpl = fpl->next;
} while (fpl && fpl != formals);
- qmlMethod->setParameters(parameters);
+ newMethod->setParameters(parameters);
}
- applyDocumentation(fd->firstSourceLocation(), qmlMethod);
+ applyDocumentation(fd->firstSourceLocation(), newMethod);
}
}
return true;
@@ -820,7 +824,10 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* )
if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
QmlTypeNode* qmlType = static_cast<QmlTypeNode*>(current);
if (qmlType) {
- FunctionNode* qmlSH = new FunctionNode(Node::QmlSignalHandler,current,handler,false);
+ FunctionNode::Metaness metaness = FunctionNode::QmSignalHandler;
+ if (qmlType->isJsType())
+ metaness = FunctionNode::JsSignalHandler;
+ FunctionNode* qmlSH = new FunctionNode(metaness, current, handler);
applyDocumentation(sb->firstSourceLocation(), qmlSH);
}
}