summaryrefslogtreecommitdiff
path: root/src/qdoc/cppcodeparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/cppcodeparser.cpp')
-rw-r--r--src/qdoc/cppcodeparser.cpp1043
1 files changed, 315 insertions, 728 deletions
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp
index b700823e5..91e3b78d8 100644
--- a/src/qdoc/cppcodeparser.cpp
+++ b/src/qdoc/cppcodeparser.cpp
@@ -33,10 +33,8 @@
#include <qfile.h>
#include <stdio.h>
#include <errno.h>
-#include "codechunk.h"
#include "config.h"
#include "cppcodeparser.h"
-#include "tokenizer.h"
#include "qdocdatabase.h"
#include <qdebug.h>
#include "generator.h"
@@ -45,30 +43,26 @@ QT_BEGIN_NAMESPACE
/* qmake ignore Q_OBJECT */
-static bool inMacroCommand_ = false;
QStringList CppCodeParser::exampleFiles;
QStringList CppCodeParser::exampleDirs;
QSet<QString> CppCodeParser::excludeDirs;
QSet<QString> CppCodeParser::excludeFiles;
static QSet<QString> topicCommands_;
-static QSet<QString> otherMetaCommands_;
+static QSet<QString> metaCommands_;
/*!
The constructor initializes some regular expressions
- and calls reset().
+ and initializes the tokenizer variables.
*/
CppCodeParser::CppCodeParser()
- : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::")
{
- reset();
if (topicCommands_.isEmpty()) {
topicCommands_ << COMMAND_CLASS
<< COMMAND_DITAMAP
<< COMMAND_ENUM
<< COMMAND_EXAMPLE
<< COMMAND_EXTERNALPAGE
- << COMMAND_FILE
<< COMMAND_FN
<< COMMAND_GROUP
<< COMMAND_HEADERFILE
@@ -99,37 +93,24 @@ CppCodeParser::CppCodeParser()
<< COMMAND_JSMETHOD
<< COMMAND_JSATTACHEDMETHOD
<< COMMAND_JSBASICTYPE
- << COMMAND_JSMODULE;
- }
- 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
- << COMMAND_ABSTRACT;
+ << COMMAND_JSMODULE
+ << COMMAND_STRUCT
+ << COMMAND_UNION;
+ }
+ if (metaCommands_.isEmpty()) {
+ metaCommands_ = commonMetaCommands();
+ metaCommands_ << COMMAND_CONTENTSPAGE
+ << COMMAND_INHEADERFILE
+ << COMMAND_NEXTPAGE
+ << COMMAND_OVERLOAD
+ << COMMAND_PREVIOUSPAGE
+ << COMMAND_QMLINSTANTIATES
+ << COMMAND_REIMP
+ << COMMAND_RELATES;
}
}
/*!
- The destructor is trivial.
- */
-CppCodeParser::~CppCodeParser()
-{
- // nothing.
-}
-
-/*!
The constructor initializes a map of special node types
for identifying important nodes. And it initializes
some filters for identifying and excluding certain kinds of files.
@@ -142,13 +123,26 @@ void CppCodeParser::initializeParser(const Config &config)
All these can appear in a C++ namespace. Don't add
anything that can't be in a C++ namespace.
*/
- nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace);
- nodeTypeMap.insert(COMMAND_CLASS, Node::Class);
- nodeTypeMap.insert(COMMAND_ENUM, Node::Enum);
- nodeTypeMap.insert(COMMAND_TYPEALIAS, Node::Typedef);
- nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef);
- nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
- nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable);
+ nodeTypeMap_.insert(COMMAND_NAMESPACE, Node::Namespace);
+ nodeTypeMap_.insert(COMMAND_CLASS, Node::Class);
+ nodeTypeMap_.insert(COMMAND_STRUCT, Node::Struct);
+ nodeTypeMap_.insert(COMMAND_UNION, Node::Union);
+ nodeTypeMap_.insert(COMMAND_ENUM, Node::Enum);
+ nodeTypeMap_.insert(COMMAND_TYPEALIAS, Node::Typedef);
+ nodeTypeMap_.insert(COMMAND_TYPEDEF, Node::Typedef);
+ nodeTypeMap_.insert(COMMAND_PROPERTY, Node::Property);
+ nodeTypeMap_.insert(COMMAND_VARIABLE, Node::Variable);
+
+ nodeTypeTestFuncMap_.insert(COMMAND_NAMESPACE, &Node::isNamespace);
+ nodeTypeTestFuncMap_.insert(COMMAND_CLASS, &Node::isClassNode);
+ nodeTypeTestFuncMap_.insert(COMMAND_STRUCT, &Node::isStruct);
+ nodeTypeTestFuncMap_.insert(COMMAND_UNION, &Node::isUnion);
+ nodeTypeTestFuncMap_.insert(COMMAND_ENUM, &Node::isEnumType);
+ nodeTypeTestFuncMap_.insert(COMMAND_TYPEALIAS, &Node::isTypedef);
+ nodeTypeTestFuncMap_.insert(COMMAND_TYPEDEF, &Node::isTypedef);
+ nodeTypeTestFuncMap_.insert(COMMAND_PROPERTY, &Node::isProperty);
+ nodeTypeTestFuncMap_.insert(COMMAND_VARIABLE, &Node::isVariable);
+
exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES);
exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS);
@@ -179,21 +173,14 @@ void CppCodeParser::initializeParser(const Config &config)
*/
void CppCodeParser::terminateParser()
{
- nodeTypeMap.clear();
+ nodeTypeMap_.clear();
+ nodeTypeTestFuncMap_.clear();
excludeDirs.clear();
excludeFiles.clear();
CodeParser::terminateParser();
}
/*!
- Returns "Cpp".
- */
-QString CppCodeParser::language()
-{
- return "Cpp";
-}
-
-/*!
Returns a list of extensions for header files.
*/
QStringList CppCodeParser::headerFileNameFilter()
@@ -229,7 +216,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
if (command == COMMAND_FN) {
Q_UNREACHABLE();
}
- else if (nodeTypeMap.contains(command)) {
+ else if (nodeTypeMap_.contains(command)) {
/*
We should only get in here if the command refers to
something that can appear in a C++ namespace,
@@ -238,21 +225,24 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
this way to allow the writer to refer to the entity
without including the namespace qualifier.
*/
- Node::NodeType type = nodeTypeMap[command];
+ Node::NodeType type = nodeTypeMap_[command];
QStringList words = arg.first.split(QLatin1Char(' '));
- QStringList path = words[0].split("::");
- Node *node = 0;
-
- node = qdb_->findNodeInOpenNamespace(path, type);
- if (node == 0)
- node = qdb_->findNodeByNameAndType(path, type);
- if (node == 0) {
+ QStringList path;
+ int idx = 0;
+ Node *node = nullptr;
+
+ if (type == Node::Variable && words.size() > 1)
+ idx = words.size() - 1;
+ path = words[idx].split("::");
+
+ node = qdb_->findNodeInOpenNamespace(path, nodeTypeTestFuncMap_[command]);
+ if (node == nullptr)
+ node = qdb_->findNodeByNameAndType(path, nodeTypeTestFuncMap_[command]);
+ if (node == nullptr) {
if (isWorthWarningAbout(doc)) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
.arg(arg.first).arg(command));
}
- lastPath_ = path;
-
}
else if (node->isAggregate()) {
if (type == Node::Namespace) {
@@ -263,7 +253,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
/*
This treats a class as a namespace.
*/
- if ((type == Node::Class) || (type == Node::Namespace)) {
+ if ((type == Node::Class) ||
+ (type == Node::Namespace) ||
+ (type == Node::Struct) ||
+ (type == Node::Union)) {
if (path.size() > 1) {
path.pop_back();
QString ns = path.join(QLatin1String("::"));
@@ -277,33 +270,19 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
if (Config::generateExamples) {
ExampleNode* en = new ExampleNode(qdb_->primaryTreeRoot(), arg.first);
en->setLocation(doc.startLocation());
- createExampleFileNodes(en);
+ setExampleFileLists(en);
return en;
}
}
else if (command == COMMAND_EXTERNALPAGE) {
- DocumentNode* dn = new DocumentNode(qdb_->primaryTreeRoot(),
- arg.first,
- Node::ExternalPage,
- Node::ArticlePage);
- dn->setLocation(doc.startLocation());
- return dn;
- }
- else if (command == COMMAND_FILE) {
- DocumentNode* dn = new DocumentNode(qdb_->primaryTreeRoot(),
- arg.first,
- Node::File,
- Node::NoPageType);
- dn->setLocation(doc.startLocation());
- return dn;
+ ExternalPageNode* epn = new ExternalPageNode(qdb_->primaryTreeRoot(), arg.first);
+ epn->setLocation(doc.startLocation());
+ return epn;
}
else if (command == COMMAND_HEADERFILE) {
- DocumentNode* dn = new DocumentNode(qdb_->primaryTreeRoot(),
- arg.first,
- Node::HeaderFile,
- Node::ApiPage);
- dn->setLocation(doc.startLocation());
- return dn;
+ HeaderNode* hn = new HeaderNode(qdb_->primaryTreeRoot(), arg.first);
+ hn->setLocation(doc.startLocation());
+ return hn;
}
else if (command == COMMAND_GROUP) {
CollectionNode* cn = qdb_->addGroup(arg.first);
@@ -350,35 +329,26 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
ptype = Node::TutorialPage;
else if (t == "faq")
ptype = Node::FAQPage;
- else if (t == "ditamap")
- ptype = Node::DitaMapPage;
else if (t == "attribution")
ptype = Node::AttributionPage;
}
- DocumentNode* dn = 0;
- if (ptype == Node::DitaMapPage)
- dn = new DitaMapNode(qdb_->primaryTreeRoot(), args[0]);
- else
- dn = new DocumentNode(qdb_->primaryTreeRoot(), args[0], Node::Page, ptype);
- dn->setLocation(doc.startLocation());
- return dn;
- }
- else if (command == COMMAND_DITAMAP) {
- DocumentNode* dn = new DitaMapNode(qdb_->primaryTreeRoot(), arg.first);
- dn->setLocation(doc.startLocation());
- return dn;
- }
- else if ((command == COMMAND_QMLTYPE) || (command == COMMAND_JSTYPE)) {
+ PageNode* pn = new PageNode(qdb_->primaryTreeRoot(), args[0], ptype);
+ pn->setLocation(doc.startLocation());
+ return pn;
+ } else if (command == COMMAND_QMLTYPE) {
QmlTypeNode* qcn = new QmlTypeNode(qdb_->primaryTreeRoot(), arg.first);
- if (command == COMMAND_JSTYPE)
- qcn->setGenus(Node::JS);
qcn->setLocation(doc.startLocation());
return qcn;
- }
- else if ((command == COMMAND_QMLBASICTYPE) || (command == COMMAND_JSBASICTYPE)) {
+ } else if (command == COMMAND_JSTYPE) {
+ QmlTypeNode* qcn = new QmlTypeNode(qdb_->primaryTreeRoot(), arg.first, Node::JsType);
+ qcn->setLocation(doc.startLocation());
+ return qcn;
+ } else if (command == COMMAND_QMLBASICTYPE) {
QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first);
- if (command == COMMAND_JSBASICTYPE)
- n->setGenus(Node::JS);
+ n->setLocation(doc.startLocation());
+ return n;
+ } else if (command == COMMAND_JSBASICTYPE) {
+ QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first, Node::JsBasicType);
n->setLocation(doc.startLocation());
return n;
}
@@ -392,7 +362,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
(command == COMMAND_JSATTACHEDMETHOD)) {
Q_UNREACHABLE();
}
- return 0;
+ return nullptr;
}
/*!
@@ -494,9 +464,9 @@ void CppCodeParser::processQmlProperties(const Doc& doc,
QString module;
QString qmlTypeName;
QString property;
- QmlPropertyNode* qpn = 0;
- QmlTypeNode* qmlType = 0;
- QmlPropertyGroupNode* qpgn = 0;
+ QmlPropertyNode* qpn = nullptr;
+ QmlTypeNode* qmlType = nullptr;
+ QmlPropertyGroupNode* qpgn = nullptr;
Topic qmlPropertyGroupTopic;
const TopicList& topics = doc.topicsUsed();
@@ -554,14 +524,13 @@ void CppCodeParser::processQmlProperties(const Doc& doc,
arg = topics.at(i).args;
if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY) ||
(topic == COMMAND_JSPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY)) {
- bool attached = ((topic == COMMAND_QMLATTACHEDPROPERTY) ||
- (topic == COMMAND_JSATTACHEDPROPERTY));
+ bool attached = topic.contains(QLatin1String("attached"));
if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property, doc.location())) {
Aggregate* aggregate = qdb_->findQmlType(module, qmlTypeName);
if (!aggregate)
aggregate = qdb_->findQmlBasicType(module, qmlTypeName);
if (aggregate) {
- if (aggregate->hasQmlProperty(property, attached) != 0) {
+ if (aggregate->hasQmlProperty(property, attached) != nullptr) {
QString msg = tr("QML property documented multiple times: '%1'").arg(arg);
doc.startLocation().warning(msg);
}
@@ -593,48 +562,60 @@ void CppCodeParser::processQmlProperties(const Doc& doc,
Returns the set of strings representing the common metacommands
plus some other metacommands.
*/
-const QSet<QString>& CppCodeParser::otherMetaCommands()
+const QSet<QString>& CppCodeParser::metaCommands()
{
- return otherMetaCommands_;
+ return metaCommands_;
}
/*!
Process the metacommand \a command in the context of the
\a node associated with the topic command and the \a doc.
\a arg is the argument to the metacommand.
+
+ \a node is guaranteed to be non-null.
*/
-void CppCodeParser::processOtherMetaCommand(const Doc& doc,
- const QString& command,
- const ArgLocPair& argLocPair,
- Node *node)
+void CppCodeParser::processMetaCommand(const Doc &doc,
+ const QString &command,
+ const ArgLocPair &argLocPair,
+ Node *node)
{
QString arg = argLocPair.first;
if (command == COMMAND_INHEADERFILE) {
- if (node != 0 && node->isAggregate()) {
- ((Aggregate *) node)->addInclude(arg);
- }
- else {
+ if (node->isAggregate())
+ static_cast<Aggregate*>(node)->addIncludeFile(arg);
+ else
doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_INHEADERFILE));
- }
}
else if (command == COMMAND_OVERLOAD) {
- if (node && (node->isFunction() || node->isSharedCommentNode()))
- node->setOverloadFlag(true);
+ /*
+ Note that this might set the overload flag of the
+ primary function. This is ok because the overload
+ flags and overload numbers will be resolved later
+ in resolveOverloadNumbers().
+ */
+ if (node->isFunction())
+ static_cast<FunctionNode*>(node)->setOverloadFlag();
+ else if (node->isSharedCommentNode())
+ static_cast<SharedCommentNode*>(node)->setOverloadFlags();
else
doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_OVERLOAD));
}
else if (command == COMMAND_REIMP) {
- if (node != 0 && node->parent() && !node->parent()->isInternal()) {
- if (node->type() == Node::Function) {
- FunctionNode *func = (FunctionNode *) node;
- if (func->reimplementedFrom().isEmpty() && isWorthWarningAbout(doc)) {
+ if (node->parent() && !node->parent()->isInternal()) {
+ if (node->isFunction()) {
+ FunctionNode *fn = static_cast<FunctionNode*>(node);
+ // The clang visitor class will have set the
+ // qualified name of the ovverridden function.
+ // If the name of the overridden function isn't
+ // set, issue a warning.
+ if (fn->overridesThis().isEmpty() && isWorthWarningAbout(doc)) {
doc.location().warning(tr("Cannot find base function for '\\%1' in %2()")
.arg(COMMAND_REIMP).arg(node->name()),
tr("The function either doesn't exist in any "
"base class with the same signature or it "
"exists but isn't virtual."));
}
- func->setReimplemented(true);
+ fn->setReimpFlag();
}
else {
doc.location().warning(tr("Ignored '\\%1' in %2").arg(COMMAND_REIMP).arg(node->name()));
@@ -643,20 +624,42 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
else if (command == COMMAND_RELATES) {
QStringList path = arg.split("::");
- Node* n = qdb_->findRelatesNode(path);
- if (!n) {
- // Store just a string to write to the index file
- if (Generator::preparing())
- node->setRelates(arg);
- else
- doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES));
+ Aggregate *aggregate = qdb_->findRelatesNode(path);
+ if (!aggregate)
+ aggregate = new ProxyNode(node->root(), arg);
- }
- else if (node->parent() != n)
- node->setRelates(static_cast<Aggregate*>(n));
- else
- doc.location().warning(tr("Invalid use of '\\%1' (already a member of '%2')")
+ if (node->parent() == aggregate) { // node is already a child of aggregate
+ doc.location().warning(tr("Invalid '\\%1' (already a member of '%2')")
.arg(COMMAND_RELATES, arg));
+ } else {
+ if (node->isAggregate()) {
+ doc.location().warning(tr("Invalid '\\%1' not allowed in '\\%2'")
+ .arg(COMMAND_RELATES, node->nodeTypeString()));
+ } else if (!node->isRelatedNonmember() &&
+ !node->parent()->name().isEmpty() &&
+ !node->parent()->isHeader()) {
+ if (!doc.isInternal()) {
+ doc.location().warning(tr("Invalid '\\%1' ('%2' must be global)")
+ .arg(COMMAND_RELATES, node->name()));
+ }
+ } else if (!node->isRelatedNonmember() && !node->parent()->isHeader()) {
+ aggregate->adoptChild(node);
+ node->setRelatedNonmember(true);
+ } else {
+ /*
+ There are multiple \relates commands. This
+ one is not the first, so clone the node as
+ a child of aggregate.
+ */
+ Node *clone = node->clone(aggregate);
+ if (clone == nullptr) {
+ doc.location().warning(tr("Invalid '\\%1' (multiple uses not allowed in '%2')")
+ .arg(COMMAND_RELATES, node->nodeTypeString()));
+ } else {
+ clone->setRelatedNonmember(true);
+ }
+ }
+ }
}
else if (command == COMMAND_CONTENTSPAGE) {
setLink(node, Node::ContentsLink, arg);
@@ -667,9 +670,6 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_PREVIOUSPAGE) {
setLink(node, Node::PreviousLink, arg);
}
- else if (command == COMMAND_INDEXPAGE) {
- setLink(node, Node::IndexLink, arg);
- }
else if (command == COMMAND_STARTPAGE) {
setLink(node, Node::StartLink, arg);
}
@@ -693,63 +693,82 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
doc.location().warning(tr("\\instantiates is only allowed in \\qmltype"));
}
else if (command == COMMAND_QMLDEFAULT) {
- if (node->type() == Node::QmlProperty) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setDefault();
- }
- 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) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(*p);
- qpn->setDefault();
- }
- ++p;
- }
- }
+ node->markDefault();
}
else if (command == COMMAND_QMLREADONLY) {
- if (node->type() == Node::QmlProperty) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setReadOnly(1);
- }
- 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) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(*p);
- qpn->setReadOnly(1);
- }
- ++p;
- }
- }
+ node->markReadOnly(1);
}
else if ((command == COMMAND_QMLABSTRACT) || (command == COMMAND_ABSTRACT)) {
if (node->isQmlType() || node->isJsType())
node->setAbstract(true);
- }
- else {
- processCommonMetaCommand(doc.location(),command,argLocPair,node);
+ } else if (command == COMMAND_DEPRECATED) {
+ node->setStatus(Node::Obsolete);
+ } else if (command == COMMAND_INGROUP || command == COMMAND_INPUBLICGROUP) {
+ // Note: \ingroup and \inpublicgroup are the same (and now recognized as such).
+ qdb_->addToGroup(arg, node);
+ } else if (command == COMMAND_INMODULE) {
+ qdb_->addToModule(arg,node);
+ } else if (command == COMMAND_INQMLMODULE) {
+ qdb_->addToQmlModule(arg,node);
+ } else if (command == COMMAND_INJSMODULE) {
+ qdb_->addToJsModule(arg, node);
+ } else if (command == COMMAND_MAINCLASS) {
+ node->doc().location().warning(tr("'\\mainclass' is deprecated. Consider '\\ingroup mainclasses'"));
+ } else if (command == COMMAND_OBSOLETE) {
+ node->setStatus(Node::Obsolete);
+ } else if (command == COMMAND_NONREENTRANT) {
+ node->setThreadSafeness(Node::NonReentrant);
+ } else if (command == COMMAND_PRELIMINARY) {
+ // \internal wins.
+ if (!node->isInternal())
+ node->setStatus(Node::Preliminary);
+ } else if (command == COMMAND_INTERNAL) {
+ if (!showInternal())
+ node->markInternal();
+ } else if (command == COMMAND_REENTRANT) {
+ node->setThreadSafeness(Node::Reentrant);
+ } else if (command == COMMAND_SINCE) {
+ node->setSince(arg);
+ } else if (command == COMMAND_WRAPPER) {
+ node->setWrapper();
+ } else if (command == COMMAND_PAGEKEYWORDS) {
+ node->addPageKeywords(arg);
+ } else if (command == COMMAND_THREADSAFE) {
+ node->setThreadSafeness(Node::ThreadSafe);
+ } else if (command == COMMAND_TITLE) {
+ if (!node->setTitle(arg))
+ doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE));
+ else if (node->isExample())
+ qdb_->addExampleNode(static_cast<ExampleNode*>(node));
+ } else if (command == COMMAND_SUBTITLE) {
+ if (!node->setSubtitle(arg))
+ doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
+ } else if (command == COMMAND_QTVARIABLE) {
+ node->setQtVariable(arg);
+ if (!node->isModule() && !node->isQmlModule())
+ doc.location().warning(tr("Command '\\%1' is only meanigfule in '\\module' and '\\qmlmodule'.")
+ .arg(COMMAND_QTVARIABLE));
+ } else if (command == COMMAND_NOAUTOLIST) {
+ node->setNoAutoList(true);
}
}
/*!
- The topic command has been processed resulting in the \a doc
- and \a node passed in here. Process the other meta commands,
- which are found in \a doc, in the context of the topic \a node.
+ The topic command has been processed, and now \a doc and
+ \a node are passed to this function to get the metacommands
+ from \a doc and process them one at a time. \a node is the
+ node where \a doc resides.
*/
-void CppCodeParser::processOtherMetaCommands(const Doc& doc, Node *node)
+void CppCodeParser::processMetaCommands(const Doc &doc, Node *node)
{
- QStringList metaCommands = doc.metaCommandsUsed().toList();
- metaCommands.sort();
- QStringList::ConstIterator cmd = metaCommands.constBegin();
- while (cmd != metaCommands.constEnd()) {
+ QStringList metaCommandsUsed = doc.metaCommandsUsed().toList();
+ metaCommandsUsed.sort(); // TODO: why are these sorted? mws 24/12/2018
+ QStringList::ConstIterator cmd = metaCommandsUsed.constBegin();
+ while (cmd != metaCommandsUsed.constEnd()) {
ArgList args = doc.metaCommandArgs(*cmd);
ArgList::ConstIterator arg = args.constBegin();
while (arg != args.constEnd()) {
- processOtherMetaCommand(doc, *cmd, *arg, node);
+ processMetaCommand(doc, *cmd, *arg, node);
++arg;
}
++cmd;
@@ -757,437 +776,9 @@ void CppCodeParser::processOtherMetaCommands(const Doc& doc, Node *node)
}
/*!
- Resets the C++ code parser to its default initialized state.
- */
-void CppCodeParser::reset()
-{
- tokenizer = 0;
- tok = 0;
- access = Node::Public;
- metaness_ = FunctionNode::Plain;
- lastPath_.clear();
- physicalModuleName.clear();
-}
-
-/*!
- Get the next token from the file being parsed and store it
- in the token variable.
- */
-void CppCodeParser::readToken()
-{
- tok = tokenizer->getToken();
-}
-
-/*!
- Return the current location in the file being parsed,
- i.e. the file name, line number, and column number.
- */
-const Location& CppCodeParser::location()
-{
- return tokenizer->location();
-}
-
-/*!
- Return the previous string read from the file being parsed.
- */
-QString CppCodeParser::previousLexeme()
-{
- return tokenizer->previousLexeme();
-}
-
-/*!
- Return the current string string from the file being parsed.
- */
-QString CppCodeParser::lexeme()
-{
- return tokenizer->lexeme();
-}
-
-bool CppCodeParser::match(int target)
-{
- if (tok == target) {
- readToken();
- return true;
- }
- return false;
-}
-
-/*!
- Skip to \a target. If \a target is found before the end
- of input, return true. Otherwise return false.
- */
-bool CppCodeParser::skipTo(int target)
-{
- while ((tok != Tok_Eoi) && (tok != target))
- readToken();
- return tok == target;
-}
-
-bool CppCodeParser::matchModuleQualifier(QString& name)
-{
- bool matches = (lexeme() == QString('.'));
- if (matches) {
- do {
- name += lexeme();
- readToken();
- } while ((tok == Tok_Ident) || (lexeme() == QString('.')));
- }
- return matches;
-}
-
-bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType)
-{
- bool matches = (tok == Tok_LeftAngle);
- if (matches) {
- int leftAngleDepth = 0;
- int parenAndBraceDepth = 0;
- do {
- if (tok == Tok_LeftAngle) {
- leftAngleDepth++;
- }
- else if (tok == Tok_RightAngle) {
- leftAngleDepth--;
- }
- else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) {
- ++parenAndBraceDepth;
- }
- else if (tok == Tok_RightParen || tok == Tok_RightBrace) {
- if (--parenAndBraceDepth < 0)
- return false;
- }
- if (dataType != 0)
- dataType->append(lexeme());
- readToken();
- } while (leftAngleDepth > 0 && tok != Tok_Eoi);
- }
- return matches;
-}
-
-bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp)
-{
- /*
- This code is really hard to follow... sorry. The loop is there to match
- Alpha::Beta::Gamma::...::Omega.
- */
- for (;;) {
- bool virgin = true;
-
- if (tok != Tok_Ident) {
- /*
- There is special processing for 'Foo::operator int()'
- and such elsewhere. This is the only case where we
- return something with a trailing gulbrandsen ('Foo::').
- */
- if (tok == Tok_operator)
- return true;
-
- /*
- People may write 'const unsigned short' or
- 'short unsigned const' or any other permutation.
- */
- while (match(Tok_const) || match(Tok_volatile))
- dataType->append(previousLexeme());
- QString pending;
- while (tok == Tok_signed || tok == Tok_int || tok == Tok_unsigned ||
- tok == Tok_short || tok == Tok_long || tok == Tok_int64) {
- if (tok == Tok_signed)
- pending = lexeme();
- else {
- if (tok == Tok_unsigned && !pending.isEmpty())
- dataType->append(pending);
- pending.clear();
- dataType->append(lexeme());
- }
- readToken();
- virgin = false;
- }
- if (!pending.isEmpty()) {
- dataType->append(pending);
- pending.clear();
- }
- while (match(Tok_const) || match(Tok_volatile))
- dataType->append(previousLexeme());
-
- if (match(Tok_Tilde))
- dataType->append(previousLexeme());
- }
-
- if (virgin) {
- if (match(Tok_Ident)) {
- /*
- This is a hack until we replace this "parser"
- with the real one used in Qt Creator.
- */
- if (!inMacroCommand_ && lexeme() == "(" &&
- ((previousLexeme() == "QT_PREPEND_NAMESPACE") || (previousLexeme() == "NS"))) {
- readToken();
- readToken();
- dataType->append(previousLexeme());
- readToken();
- }
- else
- dataType->append(previousLexeme());
- }
- else if (match(Tok_void) || match(Tok_int) || match(Tok_char) ||
- match(Tok_double) || match(Tok_Ellipsis)) {
- dataType->append(previousLexeme());
- }
- else {
- return false;
- }
- }
- else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) {
- dataType->append(previousLexeme());
- }
-
- matchTemplateAngles(dataType);
-
- while (match(Tok_const) || match(Tok_volatile))
- dataType->append(previousLexeme());
-
- if (match(Tok_Gulbrandsen))
- dataType->append(previousLexeme());
- else
- break;
- }
-
- while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) ||
- match(Tok_Caret) || match(Tok_Ellipsis))
- dataType->append(previousLexeme());
-
- if (match(Tok_LeftParenAster)) {
- /*
- A function pointer. This would be rather hard to handle without a
- tokenizer hack, because a type can be followed with a left parenthesis
- in some cases (e.g., 'operator int()'). The tokenizer recognizes '(*'
- as a single token.
- */
- dataType->append(" "); // force a space after the type
- dataType->append(previousLexeme());
- dataType->appendHotspot();
- if (var != 0 && match(Tok_Ident))
- *var = previousLexeme();
- if (!match(Tok_RightParen))
- return false;
- dataType->append(previousLexeme());
- if (!match(Tok_LeftParen))
- return false;
- dataType->append(previousLexeme());
-
- /* parse the parameters. Ignore the parameter name from the type */
- while (tok != Tok_RightParen && tok != Tok_Eoi) {
- QString dummy;
- if (!matchDataType(dataType, &dummy))
- return false;
- if (match(Tok_Comma))
- dataType->append(previousLexeme());
- }
- if (!match(Tok_RightParen))
- return false;
- dataType->append(previousLexeme());
- }
- else {
- /*
- The common case: Look for an optional identifier, then for
- some array brackets.
- */
- dataType->appendHotspot();
-
- if (var != 0) {
- if (match(Tok_Ident)) {
- *var = previousLexeme();
- }
- else if (match(Tok_Comment)) {
- /*
- A neat hack: Commented-out parameter names are
- recognized by qdoc. It's impossible to illustrate
- here inside a C-style comment, because it requires
- an asterslash. It's also impossible to illustrate
- inside a C++-style comment, because the explanation
- does not fit on one line.
- */
- if (varComment.exactMatch(previousLexeme()))
- *var = varComment.cap(1);
- }
- else if (match(Tok_LeftParen)) {
- *var = "(";
- while (tok != Tok_RightParen && tok != Tok_Eoi) {
- (*var).append(lexeme());
- readToken();
- }
- (*var).append(")");
- readToken();
- if (match(Tok_LeftBracket)) {
- (*var).append("[");
- while (tok != Tok_RightBracket && tok != Tok_Eoi) {
- (*var).append(lexeme());
- readToken();
- }
- (*var).append("]");
- readToken();
- }
- }
- else if (qProp && (match(Tok_default) || match(Tok_final) || match(Tok_override))) {
- // Hack to make 'default', 'final' and 'override' work again in Q_PROPERTY
- *var = previousLexeme();
- }
- }
-
- if (tok == Tok_LeftBracket) {
- int bracketDepth0 = tokenizer->bracketDepth();
- while ((tokenizer->bracketDepth() >= bracketDepth0 &&
- tok != Tok_Eoi) ||
- tok == Tok_RightBracket) {
- dataType->append(lexeme());
- readToken();
- }
- }
- }
- return true;
-}
-
-/*!
- Parse the next function parameter, if there is one, and
- append it to parameter vector \a pvect. Return true if
- a parameter is parsed and appended to \a pvect.
- Otherwise return false.
- */
-bool CppCodeParser::matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal)
-{
- if (match(Tok_QPrivateSignal)) {
- isQPrivateSignal = true;
- return true;
- }
-
- Parameter p;
- CodeChunk chunk;
- if (!matchDataType(&chunk, &p.name_)) {
- return false;
- }
- p.dataType_ = chunk.toString();
- chunk.clear();
- match(Tok_Comment);
- if (match(Tok_Equal)) {
- int pdepth = tokenizer->parenDepth();
- while (tokenizer->parenDepth() >= pdepth &&
- (tok != Tok_Comma || (tokenizer->parenDepth() > pdepth)) &&
- tok != Tok_Eoi) {
- chunk.append(lexeme());
- readToken();
- }
- }
- p.defaultValue_ = chunk.toString();
- pvect.append(p);
- return true;
-}
-
-/*!
- Match a C++ \c using clause. Return \c true if the match
- is successful. Otherwise false.
-
- If the \c using clause is for a namespace, an open namespace
- <is inserted for qdoc to look in to find things.
-
- If the \c using clause is a base class member function, the
- member function is added to \a parent as an unresolved
- \c using clause.
- */
-bool CppCodeParser::matchUsingDecl(Aggregate* parent)
-{
- bool usingNamespace = false;
- readToken(); // skip 'using'
-
- if (tok == Tok_namespace) {
- usingNamespace = true;
- readToken();
- }
-
- int openLeftAngles = 0;
- int openLeftParens = 0;
- bool usingOperator = false;
- QString name;
- while (tok != Tok_Semicolon) {
- if ((tok != Tok_Ident) && (tok != Tok_Gulbrandsen)) {
- if (tok == Tok_LeftAngle) {
- ++openLeftAngles;
- }
- else if (tok == Tok_RightAngle) {
- if (openLeftAngles <= 0)
- return false;
- --openLeftAngles;
- }
- else if (tok == Tok_Comma) {
- if (openLeftAngles <= 0)
- return false;
- }
- else if (tok == Tok_operator) {
- usingOperator = true;
- }
- else if (tok == Tok_SomeOperator) {
- if (!usingOperator)
- return false;
- }
- else if (tok == Tok_LeftParen) {
- ++openLeftParens;
- }
- else if (tok == Tok_RightParen) {
- if (openLeftParens <= 0)
- return false;
- --openLeftParens;
- }
- else {
- return false;
- }
- }
- name += lexeme();
- readToken();
- }
-
- if (usingNamespace) {
- // 'using namespace Foo;'.
- qdb_->insertOpenNamespace(name);
- }
- else if (parent && parent->isClass()) {
- ClassNode* cn = static_cast<ClassNode*>(parent);
- cn->addUnresolvedUsingClause(name);
- }
- return true;
-}
-
-/*!
- This function uses a Tokenizer to parse the \a parameters of a
- function into the parameter vector \a {pvect}.
- */
-bool CppCodeParser::parseParameters(const QString& parameters,
- QVector<Parameter>& pvect,
- bool& isQPrivateSignal)
-{
- Tokenizer* outerTokenizer = tokenizer;
- int outerTok = tok;
-
- QByteArray latin1 = parameters.toLatin1();
- Tokenizer stringTokenizer(Location(), latin1);
- stringTokenizer.setParsingFnOrMacro(true);
- tokenizer = &stringTokenizer;
- readToken();
-
- inMacroCommand_ = false;
- do {
- if (!matchParameter(pvect, isQPrivateSignal))
- return false;
- } while (match(Tok_Comma));
-
- tokenizer = outerTokenizer;
- tok = outerTok;
- return true;
-}
-
-/*!
Parse QML/JS signal/method topic commands.
*/
-Node* CppCodeParser::parseOtherFuncArg(const QString& topic,
- const Location& location,
- const QString& funcArg)
+FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Location &location, const QString &funcArg)
{
QString funcName;
QString returnType;
@@ -1207,7 +798,7 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic,
if (colonSplit.size() < 2) {
QString msg = "Unrecognizable QML module/component qualifier for " + funcArg;
location.warning(tr(msg.toLatin1().data()));
- return 0;
+ return nullptr;
}
QString moduleName;
QString elementName;
@@ -1220,23 +811,10 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic,
funcName = colonSplit.last();
Aggregate *aggregate = qdb_->findQmlType(moduleName, elementName);
- bool attached = false;
if (!aggregate)
aggregate = qdb_->findQmlBasicType(moduleName, elementName);
if (!aggregate)
- return 0;
-
- Node::NodeType nodeType = Node::QmlMethod;
- if (topic == COMMAND_QMLSIGNAL || topic == COMMAND_JSSIGNAL) {
- nodeType = Node::QmlSignal;
- } else if (topic == COMMAND_QMLATTACHEDSIGNAL || topic == COMMAND_JSATTACHEDSIGNAL) {
- nodeType = Node::QmlSignal;
- attached = true;
- } else if (topic == COMMAND_QMLATTACHEDMETHOD || topic == COMMAND_JSATTACHEDMETHOD) {
- attached = true;
- } else {
- Q_ASSERT(topic == COMMAND_QMLMETHOD || topic == COMMAND_JSMETHOD);
- }
+ return nullptr;
QString params;
QStringList leftParenSplit = funcArg.split('(');
@@ -1245,70 +823,74 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic,
if (rightParenSplit.size() > 0)
params = rightParenSplit[0];
}
- FunctionNode *funcNode = static_cast<FunctionNode*>(new FunctionNode(nodeType, aggregate, funcName, attached));
- funcNode->setAccess(Node::Public);
- funcNode->setLocation(location);
- funcNode->setReturnType(returnType);
- funcNode->setParameters(params);
- return funcNode;
+
+ FunctionNode::Metaness metaness = FunctionNode::getMetanessFromTopic(topic);
+ bool attached = topic.contains(QLatin1String("attached"));
+ FunctionNode *fn = new FunctionNode(metaness, aggregate, funcName, attached);
+ fn->setAccess(Node::Public);
+ fn->setLocation(location);
+ fn->setReturnType(returnType);
+ fn->setParameters(params);
+ return fn;
}
/*!
- Parse the \macro arguments ad hoc, without using any actual parser.
+ Parse the macro arguments in \a macroArg ad hoc, without using
+ any actual parser. If successful, return a pointer to the new
+ FunctionNode for the macro. Otherwise return null. \a location
+ is used for reporting errors.
*/
-Node* CppCodeParser::parseMacroArg(const Location& location, const QString& macroArg)
+FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QString &macroArg)
{
- FunctionNode* newMacroNode = 0;
QStringList leftParenSplit = macroArg.split('(');
- if (leftParenSplit.size() > 0) {
- QString macroName;
- FunctionNode* oldMacroNode = 0;
- QStringList blankSplit = leftParenSplit[0].split(' ');
- if (blankSplit.size() > 0) {
- macroName = blankSplit.last();
- oldMacroNode = static_cast<FunctionNode*>(qdb_->findMacroNode(macroName));
- }
- QString returnType;
- if (blankSplit.size() > 1) {
- blankSplit.removeLast();
- returnType = blankSplit.join(' ');
- }
- QString params;
- if (leftParenSplit.size() > 1) {
- const QString &afterParen = leftParenSplit.at(1);
- int rightParen = afterParen.indexOf(')');
- if (rightParen >= 0)
- params = afterParen.left(rightParen);
- }
- int i = 0;
- while (i < macroName.length() && !macroName.at(i).isLetter())
- i++;
- if (i > 0) {
- returnType += QChar(' ') + macroName.left(i);
- macroName = macroName.mid(i);
- }
- newMacroNode = static_cast<FunctionNode*>(new FunctionNode(qdb_->primaryTreeRoot(), macroName));
- newMacroNode->setAccess(Node::Public);
- newMacroNode->setLocation(location);
- if (params.isEmpty())
- newMacroNode->setMetaness(FunctionNode::MacroWithoutParams);
- else
- newMacroNode->setMetaness(FunctionNode::MacroWithParams);
- newMacroNode->setReturnType(returnType);
- newMacroNode->setParameters(params);
- if (oldMacroNode && newMacroNode->compare(oldMacroNode)) {
- location.warning(tr("\\macro %1 documented more than once").arg(macroArg));
- oldMacroNode->doc().location().warning(tr("(The previous doc is here)"));
- }
+ if (leftParenSplit.isEmpty())
+ return nullptr;
+ QString macroName;
+ FunctionNode* oldMacroNode = nullptr;
+ QStringList blankSplit = leftParenSplit[0].split(' ');
+ if (blankSplit.size() > 0) {
+ macroName = blankSplit.last();
+ oldMacroNode = qdb_->findMacroNode(macroName);
}
- return newMacroNode;
+ QString returnType;
+ if (blankSplit.size() > 1) {
+ blankSplit.removeLast();
+ returnType = blankSplit.join(' ');
+ }
+ QString params;
+ if (leftParenSplit.size() > 1) {
+ const QString &afterParen = leftParenSplit.at(1);
+ int rightParen = afterParen.indexOf(')');
+ if (rightParen >= 0)
+ params = afterParen.left(rightParen);
+ }
+ int i = 0;
+ while (i < macroName.length() && !macroName.at(i).isLetter())
+ i++;
+ if (i > 0) {
+ returnType += QChar(' ') + macroName.left(i);
+ macroName = macroName.mid(i);
+ }
+ FunctionNode::Metaness metaness = FunctionNode::MacroWithParams;
+ if (params.isEmpty())
+ metaness = FunctionNode::MacroWithoutParams;
+ FunctionNode* macro = new FunctionNode(metaness, qdb_->primaryTreeRoot(), macroName);
+ macro->setAccess(Node::Public);
+ macro->setLocation(location);
+ macro->setReturnType(returnType);
+ macro->setParameters(params);
+ if (oldMacroNode && macro->compare(oldMacroNode)) {
+ location.warning(tr("\\macro %1 documented more than once").arg(macroArg));
+ oldMacroNode->doc().location().warning(tr("(The previous doc is here)"));
+ }
+ return macro;
}
-void CppCodeParser::createExampleFileNodes(DocumentNode *dn)
+void CppCodeParser::setExampleFileLists(PageNode *pn)
{
- QString examplePath = dn->name();
+ QString examplePath = pn->name();
QString proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".pro";
- QString fullPath = Config::findFile(dn->doc().location(),
+ QString fullPath = Config::findFile(pn->doc().location(),
exampleFiles,
exampleDirs,
proFileName);
@@ -1316,13 +898,13 @@ void CppCodeParser::createExampleFileNodes(DocumentNode *dn)
if (fullPath.isEmpty()) {
QString tmp = proFileName;
proFileName = examplePath + QLatin1Char('/') + "qbuild.pro";
- fullPath = Config::findFile(dn->doc().location(),
+ fullPath = Config::findFile(pn->doc().location(),
exampleFiles,
exampleDirs,
proFileName);
if (fullPath.isEmpty()) {
proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".qmlproject";
- fullPath = Config::findFile(dn->doc().location(),
+ fullPath = Config::findFile(pn->doc().location(),
exampleFiles,
exampleDirs,
proFileName);
@@ -1330,8 +912,8 @@ void CppCodeParser::createExampleFileNodes(DocumentNode *dn)
QString details = QLatin1String("Example directories: ") + exampleDirs.join(QLatin1Char(' '));
if (!exampleFiles.isEmpty())
details += QLatin1String(", example files: ") + exampleFiles.join(QLatin1Char(' '));
- dn->location().warning(tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName), details);
- dn->location().warning(tr(" EXAMPLE PATH DOES NOT EXIST: %1").arg(examplePath), details);
+ pn->location().warning(tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName), details);
+ pn->location().warning(tr(" EXAMPLE PATH DOES NOT EXIST: %1").arg(examplePath), details);
return;
}
}
@@ -1369,20 +951,15 @@ void CppCodeParser::createExampleFileNodes(DocumentNode *dn)
exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro *.qmlproject qmldir");
}
- foreach (const QString &exampleFile, exampleFiles) {
- DocumentNode *fileNode = new DocumentNode(dn,
- exampleFile.mid(sizeOfBoringPartOfName),
- Node::File,
- Node::NoPageType);
- if (fileNode->name().endsWith(".qml"))
- fileNode->setGenus(Node::QML);
- }
- foreach (const QString &imageFile, imageFiles) {
- new DocumentNode(dn,
- imageFile.mid(sizeOfBoringPartOfName),
- Node::Image,
- Node::NoPageType);
- }
+ int i = 0;
+ foreach (const QString &exampleFile, exampleFiles)
+ exampleFiles[i++] = exampleFile.mid(sizeOfBoringPartOfName);
+ i = 0;
+ foreach (const QString &imageFile, imageFiles)
+ imageFiles[i++] = imageFile.mid(sizeOfBoringPartOfName);
+ ExampleNode* en = static_cast<ExampleNode*>(pn);
+ en->setFiles(exampleFiles);
+ en->setImages(imageFiles);
}
/*!
@@ -1439,17 +1016,19 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL
processQmlProperties(doc, nodes, docs, true);
} else {
ArgList args = doc.metaCommandArgs(topic);
- Node *node = 0;
+ Node *node = nullptr;
if (args.size() == 1) {
- if (topic == COMMAND_FN)
- node = parserForLanguage("Clang")->parseFnArg(doc.location(), args[0].first);
- else if (topic == COMMAND_MACRO)
+ if (topic == COMMAND_FN) {
+ if (showInternal() || !doc.isInternal())
+ node = parserForLanguage("Clang")->parseFnArg(doc.location(), args[0].first);
+ } else if (topic == COMMAND_MACRO) {
node = parseMacroArg(doc.location(), args[0].first);
- else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic))
+ } else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic)) {
node = parseOtherFuncArg(topic, doc.location(), args[0].first);
- else
+ } else {
node = processTopicCommand(doc, topic, args[0]);
- if (node != 0) {
+ }
+ if (node != nullptr) {
nodes.append(node);
docs.append(doc);
}
@@ -1457,15 +1036,18 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL
QVector<SharedCommentNode*> sharedCommentNodes;
ArgList::ConstIterator arg = args.constBegin();
while (arg != args.constEnd()) {
- if (topic == COMMAND_FN)
- node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg->first);
- else if (topic == COMMAND_MACRO)
+ node = nullptr;
+ if (topic == COMMAND_FN) {
+ if (showInternal() || !doc.isInternal())
+ node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg->first);
+ } else if (topic == COMMAND_MACRO) {
node = parseMacroArg(doc.location(), arg->first);
- else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic))
+ } else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic)) {
node = parseOtherFuncArg(topic, doc.location(), arg->first);
- else
+ } else {
node = processTopicCommand(doc, topic, *arg);
- if (node != 0) {
+ }
+ if (node != nullptr) {
bool found = false;
for (SharedCommentNode *scn : sharedCommentNodes) {
if (scn->parent() == node->parent()) {
@@ -1487,22 +1069,27 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL
}
}
-void CppCodeParser::processOtherMetaCommands(NodeList &nodes, DocList& docs)
+void CppCodeParser::processMetaCommands(NodeList &nodes, DocList &docs)
{
NodeList::Iterator n = nodes.begin();
QList<Doc>::Iterator d = docs.begin();
while (n != nodes.end()) {
- processOtherMetaCommands(*d, *n);
- (*n)->setDoc(*d);
- checkModuleInclusion(*n);
- if ((*n)->isAggregate() && ((Aggregate *)*n)->includes().isEmpty()) {
- Aggregate *m = static_cast<Aggregate *>(*n);
- while (m->parent() && m->physicalModuleName().isEmpty())
- m = m->parent();
- if (m == *n)
- ((Aggregate *)*n)->addInclude((*n)->name());
- else
- ((Aggregate *)*n)->setIncludes(m->includes());
+ if (*n != nullptr) {
+ processMetaCommands(*d, *n);
+ (*n)->setDoc(*d);
+ checkModuleInclusion(*n);
+ if ((*n)->isAggregate()) {
+ Aggregate *aggregate = static_cast<Aggregate *>(*n);
+ if (aggregate->includeFiles().isEmpty()) {
+ Aggregate *parent = aggregate;
+ while (parent->physicalModuleName().isEmpty() && (parent->parent() != nullptr))
+ parent = parent->parent();
+ if (parent == aggregate)
+ aggregate->addIncludeFile(aggregate->name());
+ else
+ aggregate->setIncludeFiles(parent->includeFiles());
+ }
+ }
}
++d;
++n;