summaryrefslogtreecommitdiffstats
path: root/src/tools/qdoc/cppcodeparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/qdoc/cppcodeparser.cpp')
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp381
1 files changed, 223 insertions, 158 deletions
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index 5c25eeedc4..3e63432047 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -272,37 +272,42 @@ void CppCodeParser::doneParsingSourceFiles()
qdb_->treeRoot()->makeUndocumentedChildrenInternal();
}
+static QSet<QString> topicCommands_;
/*!
Returns the set of strings reopresenting the topic commands.
*/
-QSet<QString> CppCodeParser::topicCommands()
+const QSet<QString>& CppCodeParser::topicCommands()
{
- return QSet<QString>() << COMMAND_CLASS
- << COMMAND_DITAMAP
- << COMMAND_ENUM
- << COMMAND_EXAMPLE
- << COMMAND_EXTERNALPAGE
- << COMMAND_FILE
- << COMMAND_FN
- << COMMAND_GROUP
- << COMMAND_HEADERFILE
- << COMMAND_MACRO
- << COMMAND_MODULE
- << COMMAND_NAMESPACE
- << COMMAND_PAGE
- << COMMAND_PROPERTY
- << COMMAND_TYPEDEF
- << COMMAND_VARIABLE
- << COMMAND_QMLCLASS
- << COMMAND_QMLTYPE
- << COMMAND_QMLPROPERTY
- << COMMAND_QMLATTACHEDPROPERTY
- << COMMAND_QMLSIGNAL
- << COMMAND_QMLATTACHEDSIGNAL
- << COMMAND_QMLMETHOD
- << COMMAND_QMLATTACHEDMETHOD
- << COMMAND_QMLBASICTYPE
- << COMMAND_QMLMODULE;
+ if (topicCommands_.isEmpty()) {
+ topicCommands_ << COMMAND_CLASS
+ << COMMAND_DITAMAP
+ << COMMAND_ENUM
+ << COMMAND_EXAMPLE
+ << COMMAND_EXTERNALPAGE
+ << COMMAND_FILE
+ << COMMAND_FN
+ << COMMAND_GROUP
+ << COMMAND_HEADERFILE
+ << COMMAND_MACRO
+ << COMMAND_MODULE
+ << COMMAND_NAMESPACE
+ << COMMAND_PAGE
+ << COMMAND_PROPERTY
+ << COMMAND_TYPEDEF
+ << COMMAND_VARIABLE
+ << COMMAND_QMLCLASS
+ << COMMAND_QMLTYPE
+ << COMMAND_QMLPROPERTY
+ << COMMAND_QMLPROPERTYGROUP
+ << COMMAND_QMLATTACHEDPROPERTY
+ << COMMAND_QMLSIGNAL
+ << COMMAND_QMLATTACHEDSIGNAL
+ << COMMAND_QMLMETHOD
+ << COMMAND_QMLATTACHEDMETHOD
+ << COMMAND_QMLBASICTYPE
+ << COMMAND_QMLMODULE;
+ }
+ return topicCommands_;
}
/*!
@@ -607,10 +612,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
(command == COMMAND_QMLATTACHEDSIGNAL) ||
(command == COMMAND_QMLATTACHEDMETHOD)) {
QString module;
- QString element;
+ QString qmlType;
QString type;
- if (splitQmlMethodArg(arg.first,type,module,element)) {
- QmlClassNode* qmlClass = qdb_->findQmlType(module,element);
+ if (splitQmlMethodArg(arg.first,type,module,qmlType)) {
+ QmlClassNode* qmlClass = qdb_->findQmlType(module,qmlType);
if (qmlClass) {
bool attached = false;
Node::Type nodeType = Node::QmlMethod;
@@ -643,28 +648,57 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
/*!
+ A QML property group argument has the form...
+
+ <QML-module>::<QML-type>::<name>
+
+ This function splits the argument into those parts.
+ A <QML-module> is the QML equivalent of a C++ namespace.
+ So this function splits \a arg on "::" and stores the
+ parts in \a module, \a qmlType, and \a name, and returns
+ true. If any part is not found, a qdoc warning is emitted
+ and false is returned.
+ */
+bool CppCodeParser::splitQmlPropertyGroupArg(const QString& arg,
+ QString& module,
+ QString& qmlType,
+ QString& name)
+{
+ QStringList colonSplit = arg.split("::");
+ if (colonSplit.size() == 3) {
+ module = colonSplit[0];
+ qmlType = colonSplit[1];
+ name = colonSplit[2];
+ return true;
+ }
+ QString msg = "Unrecognizable QML module/component qualifier for " + arg;
+ location().warning(tr(msg.toLatin1().data()));
+ return false;
+}
+
+/*!
A QML property argument has the form...
- <type> <element>::<name>
- <type> <QML-module>::<element>::<name>
+ <type> <QML-type>::<name>
+ <type> <QML-module>::<QML-type>::<name>
This function splits the argument into one of those
two forms. The three part form is the old form, which
was used before the creation of Qt Quick 2 and Qt
Components. A <QML-module> is the QML equivalent of a
C++ namespace. So this function splits \a arg on "::"
- and stores the parts in \a type, \a module, \a element,
+ and stores the parts in \a type, \a module, \a qmlType,
and \a name, and returns true. If any part other than
\a module is not found, a qdoc warning is emitted and
false is returned.
- \note The two elements \e{Component} and \e{QtObject} never
- have a module qualifier.
+ \note The two QML types \e{Component} and \e{QtObject}
+ never have a module qualifier.
*/
bool CppCodeParser::splitQmlPropertyArg(const QString& arg,
QString& type,
QString& module,
- QString& element,
+ QString& qmlType,
QString& name)
{
QStringList blankSplit = arg.split(QLatin1Char(' '));
@@ -673,13 +707,13 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg,
QStringList colonSplit(blankSplit[1].split("::"));
if (colonSplit.size() == 3) {
module = colonSplit[0];
- element = colonSplit[1];
+ qmlType = colonSplit[1];
name = colonSplit[2];
return true;
}
if (colonSplit.size() == 2) {
module.clear();
- element = colonSplit[0];
+ qmlType = colonSplit[0];
name = colonSplit[1];
return true;
}
@@ -696,21 +730,21 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg,
/*!
A QML signal or method argument has the form...
- <type> <element>::<name>(<param>, <param>, ...)
- <type> <QML-module>::<element>::<name>(<param>, <param>, ...)
+ <type> <QML-type>::<name>(<param>, <param>, ...)
+ <type> <QML-module>::<QML-type>::<name>(<param>, <param>, ...)
This function splits the argument into one of those two
- forms, sets \a module, \a element, and \a name, and returns
+ forms, sets \a module, \a qmlType, and \a name, and returns
true. If the argument doesn't match either form, an error
message is emitted and false is returned.
- \note The two elements \e{Component} and \e{QtObject} never
+ \note The two QML types \e{Component} and \e{QtObject} never
have a module qualifier.
*/
bool CppCodeParser::splitQmlMethodArg(const QString& arg,
QString& type,
QString& module,
- QString& element)
+ QString& qmlType)
{
QStringList colonSplit(arg.split("::"));
if (colonSplit.size() > 1) {
@@ -719,22 +753,22 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg,
type = blankSplit[0];
if (colonSplit.size() > 2) {
module = blankSplit[1];
- element = colonSplit[1];
+ qmlType = colonSplit[1];
}
else {
module.clear();
- element = blankSplit[1];
+ qmlType = blankSplit[1];
}
}
else {
type.clear();
if (colonSplit.size() > 2) {
module = colonSplit[0];
- element = colonSplit[1];
+ qmlType = colonSplit[1];
}
else {
module.clear();
- element = colonSplit[0];
+ qmlType = colonSplit[0];
}
}
return true;
@@ -750,79 +784,118 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg,
Currently, this function is called only for \e{qmlproperty}
and \e{qmlattachedproperty}.
*/
-Node* CppCodeParser::processTopicCommandGroup(const Doc& doc,
- const QString& command,
- const ArgList& args)
+void CppCodeParser::processQmlProperties(const Doc& doc, NodeList& nodes, DocList& docs)
{
- QmlPropGroupNode* qmlPropGroup = 0;
- if ((command == COMMAND_QMLPROPERTY) ||
- (command == COMMAND_QMLATTACHEDPROPERTY)) {
- QString arg;
- QString type;
- QString module;
- QString element;
- QString property;
- QmlClassNode* qmlClass = 0;
- bool attached = (command == COMMAND_QMLATTACHEDPROPERTY);
- ArgList::ConstIterator argsIter = args.constBegin();
- arg = argsIter->first;
- if (splitQmlPropertyArg(arg,type,module,element,property)) {
- qmlClass = qdb_->findQmlType(module,element);
- if (qmlClass) {
- qmlPropGroup = new QmlPropGroupNode(qmlClass,property); //,attached);
- qmlPropGroup->setLocation(doc.startLocation());
- }
+ QString arg;
+ QString type;
+ QString topic;
+ QString module;
+ QString qmlType;
+ QString property;
+ QmlPropertyNode* qpn = 0;
+ QmlClassNode* qmlClass = 0;
+ QmlPropertyGroupNode* qpgn = 0;
+
+ Topic qmlPropertyGroupTopic;
+ const TopicList& topics = doc.topicsUsed();
+ for (int i=0; i<topics.size(); ++i) {
+ if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP) {
+ qmlPropertyGroupTopic = topics.at(i);
+ break;
}
- if (qmlPropGroup) {
- if (qmlClass->hasProperty(property)) {
- doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg));
+ }
+ if (qmlPropertyGroupTopic.isEmpty() && topics.size() > 1) {
+ qmlPropertyGroupTopic = topics.at(0);
+ qmlPropertyGroupTopic.topic = COMMAND_QMLPROPERTYGROUP;
+ arg = qmlPropertyGroupTopic.args;
+ if (splitQmlPropertyArg(arg, type, module, qmlType, property)) {
+ int i = property.indexOf('.');
+ if (i != -1) {
+ property = property.left(i);
+ qmlPropertyGroupTopic.args = module + "::" + qmlType + "::" + property;
+ doc.location().warning(tr("No QML property group command found; using \\%1 %2")
+ .arg(COMMAND_QMLPROPERTYGROUP).arg(qmlPropertyGroupTopic.args));
}
else {
- QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached);
- qmlPropNode->setLocation(doc.startLocation());
+ /*
+ Assumption: No '.' in the property name
+ means there is no property group.
+ */
+ qmlPropertyGroupTopic.clear();
+ }
+ }
+ }
+
+ if (!qmlPropertyGroupTopic.isEmpty()) {
+ arg = qmlPropertyGroupTopic.args;
+ if (splitQmlPropertyGroupArg(arg, module, qmlType, property)) {
+ qmlClass = qdb_->findQmlType(module, qmlType);
+ if (qmlClass) {
+ qpgn = new QmlPropertyGroupNode(qmlClass, property);
+ qpgn->setLocation(doc.startLocation());
}
- ++argsIter;
- while (argsIter != args.constEnd()) {
- arg = argsIter->first;
- if (splitQmlPropertyArg(arg,type,module,element,property)) {
- if (qmlClass->hasProperty(property)) {
- doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg));
+ }
+ if (topics.size() == 1) {
+ nodes.append(qpgn);
+ docs.append(doc);
+ return;
+ }
+ }
+ for (int i=0; i<topics.size(); ++i) {
+ if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP)
+ continue;
+ topic = topics.at(i).topic;
+ arg = topics.at(i).args;
+ if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) {
+ bool attached = (topic == COMMAND_QMLATTACHEDPROPERTY);
+ if (splitQmlPropertyArg(arg, type, module, qmlType, property)) {
+ qmlClass = qdb_->findQmlType(module, qmlType);
+ if (qmlClass) {
+ if (qmlClass->hasQmlProperty(property) != 0) {
+ QString msg = tr("QML property documented multiple times: '%1'").arg(arg);
+ doc.startLocation().warning(msg);
+ }
+ else if (qpgn) {
+ qpn = new QmlPropertyNode(qpgn, property, type, attached);
+ qpn->setLocation(doc.startLocation());
}
else {
- QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup,
- property,
- type,
- attached);
- qmlPropNode->setLocation(doc.startLocation());
+ qpn = new QmlPropertyNode(qmlClass, property, type, attached);
+ qpn->setLocation(doc.startLocation());
+ nodes.append(qpn);
+ docs.append(doc);
}
}
- ++argsIter;
}
}
}
- return qmlPropGroup;
}
+static QSet<QString> otherMetaCommands_;
/*!
Returns the set of strings representing the common metacommands
plus some other metacommands.
*/
-QSet<QString> CppCodeParser::otherMetaCommands()
+const QSet<QString>& CppCodeParser::otherMetaCommands()
{
- return commonMetaCommands() << COMMAND_INHEADERFILE
- << COMMAND_OVERLOAD
- << COMMAND_REIMP
- << COMMAND_RELATES
- << COMMAND_CONTENTSPAGE
- << COMMAND_NEXTPAGE
- << COMMAND_PREVIOUSPAGE
- << COMMAND_INDEXPAGE
- << COMMAND_STARTPAGE
- << COMMAND_QMLINHERITS
- << COMMAND_QMLINSTANTIATES
- << COMMAND_QMLDEFAULT
- << COMMAND_QMLREADONLY
- << COMMAND_QMLABSTRACT;
+ if (otherMetaCommands_.isEmpty()) {
+ otherMetaCommands_ = commonMetaCommands();
+ otherMetaCommands_ << COMMAND_INHEADERFILE
+ << COMMAND_OVERLOAD
+ << COMMAND_REIMP
+ << COMMAND_RELATES
+ << COMMAND_CONTENTSPAGE
+ << COMMAND_NEXTPAGE
+ << COMMAND_PREVIOUSPAGE
+ << COMMAND_INDEXPAGE
+ << COMMAND_STARTPAGE
+ << COMMAND_QMLINHERITS
+ << COMMAND_QMLINSTANTIATES
+ << COMMAND_QMLDEFAULT
+ << COMMAND_QMLREADONLY
+ << COMMAND_QMLABSTRACT;
+ }
+ return otherMetaCommands_;
}
/*!
@@ -855,8 +928,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_REIMP) {
- if (node->parent() && !node->parent()->isInternal()) {
- if (node != 0 && node->type() == Node::Function) {
+ if (node != 0 && node->parent() && !node->parent()->isInternal()) {
+ if (node->type() == Node::Function) {
FunctionNode *func = (FunctionNode *) node;
const FunctionNode *from = func->reimplementedFrom();
if (from == 0) {
@@ -961,8 +1034,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
qpn->setDefault();
}
- else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) {
- QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
+ else if (node->type() == Node::QmlPropertyGroup) {
+ QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node);
NodeList::ConstIterator p = qpgn->childNodes().constBegin();
while (p != qpgn->childNodes().constEnd()) {
if ((*p)->type() == Node::QmlProperty) {
@@ -978,8 +1051,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
qpn->setReadOnly(1);
}
- else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) {
- QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
+ else if (node->type() == Node::QmlPropertyGroup) {
+ QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node);
NodeList::ConstIterator p = qpgn->childNodes().constBegin();
while (p != qpgn->childNodes().constEnd()) {
if ((*p)->type() == Node::QmlProperty) {
@@ -2067,10 +2140,9 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
bool CppCodeParser::matchDocsAndStuff()
{
ExtraFuncData extra;
- QSet<QString> topicCommandsAllowed = topicCommands();
- QSet<QString> otherMetacommandsAllowed = otherMetaCommands();
- QSet<QString> metacommandsAllowed = topicCommandsAllowed +
- otherMetacommandsAllowed;
+ const QSet<QString>& topicCommandsAllowed = topicCommands();
+ const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands();
+ const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed;
while (tok != Tok_Eoi) {
if (tok == Tok_Doc) {
@@ -2087,25 +2159,22 @@ bool CppCodeParser::matchDocsAndStuff()
/*
Doc parses the comment.
*/
- Doc doc(start_loc,end_loc,comment,metacommandsAllowed);
-
+ Doc doc(start_loc,end_loc,comment,metacommandsAllowed, topicCommandsAllowed);
QString topic;
- ArgList args;
-
- QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed();
+ bool isQmlPropertyTopic = false;
- /*
- There should be one topic command in the set,
- or none. If the set is empty, then the comment
- should be a function description.
- */
- if (topicCommandsUsed.count() > 0) {
- topic = *topicCommandsUsed.constBegin();
- args = doc.metaCommandArgs(topic);
+ const TopicList& topics = doc.topicsUsed();
+ if (!topics.isEmpty()) {
+ topic = topics[0].topic;
+ if ((topic == COMMAND_QMLPROPERTY) ||
+ (topic == COMMAND_QMLPROPERTYGROUP) ||
+ (topic == COMMAND_QMLATTACHEDPROPERTY)) {
+ isQmlPropertyTopic = true;
+ }
}
-
+ // if (isQmlPropertyTopic && doc.location().fileName().endsWith("qquickitem.cpp")) {
NodeList nodes;
- QList<Doc> docs;
+ DocList docs;
if (topic.isEmpty()) {
QStringList parentPath;
@@ -2133,43 +2202,39 @@ bool CppCodeParser::matchDocsAndStuff()
.arg(COMMAND_FN).arg(COMMAND_PAGE));
}
}
+ else if (isQmlPropertyTopic) {
+ Doc nodeDoc = doc;
+ processQmlProperties(nodeDoc, nodes, docs);
+ }
else {
- /*
- There is a topic command. Process it.
- */
- if ((topic == COMMAND_QMLPROPERTY) ||
- (topic == COMMAND_QMLATTACHEDPROPERTY)) {
+ ArgList args;
+ const QSet<QString>& topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed();
+ if (topicCommandsUsed.count() > 0) {
+ topic = *topicCommandsUsed.constBegin();
+ args = doc.metaCommandArgs(topic);
+ }
+ if (topicCommandsUsed.count() > 1) {
+ QString topics;
+ QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin();
+ while (t != topicCommandsUsed.constEnd()) {
+ topics += " \\" + *t + ",";
+ ++t;
+ }
+ topics[topics.lastIndexOf(',')] = '.';
+ int i = topics.lastIndexOf(',');
+ topics[i] = ' ';
+ topics.insert(i+1,"and");
+ doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics));
+ }
+ ArgList::ConstIterator a = args.constBegin();
+ while (a != args.constEnd()) {
Doc nodeDoc = doc;
- Node *node = processTopicCommandGroup(nodeDoc, topic,args);
+ Node *node = processTopicCommand(nodeDoc,topic,*a);
if (node != 0) {
nodes.append(node);
docs.append(nodeDoc);
}
- }
- else {
- if (topicCommandsUsed.count() > 1) {
- QString topics;
- QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin();
- while (t != topicCommandsUsed.constEnd()) {
- topics += " \\" + *t + ",";
- ++t;
- }
- topics[topics.lastIndexOf(',')] = '.';
- int i = topics.lastIndexOf(',');
- topics[i] = ' ';
- topics.insert(i+1,"and");
- doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics));
- }
- ArgList::ConstIterator a = args.constBegin();
- while (a != args.constEnd()) {
- Doc nodeDoc = doc;
- Node *node = processTopicCommand(nodeDoc,topic,*a);
- if (node != 0) {
- nodes.append(node);
- docs.append(nodeDoc);
- }
- ++a;
- }
+ ++a;
}
}
@@ -2262,7 +2327,7 @@ bool CppCodeParser::makeFunctionNode(const QString& signature,
the \a type.
\a parent is the QML class node. The QML module and QML
- element names have already been consumed to find \a parent.
+ type names have already been consumed to find \a parent.
What remains in \a sig is the method signature. The method
must be a child of \a parent.
*/