summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2019-01-22 12:11:13 +0100
committerPaul Wicking <paul.wicking@qt.io>2019-02-06 13:19:48 +0000
commitbf8ee4c99d56c2bf770343b7db07f68a2c6a7617 (patch)
tree73095c02dbfbce7d0830f890aabaa58d2c0e9224
parentb3c9f6cb9eb104bf4fe86b377aee7875473f97b4 (diff)
qdoc: Major clean-up of FunctionNode and parameter processingv5.13.0-alpha1
This update was motivated by the need to correct two known issues in qdoc. First, linking to overloaded functions failed in some cases because the overloads were not numbered consistently, causing links to go to the wrong overload or to nowhere at all. Second, the mechanism for handling the \relates command didn't support using it to relate a function to more than one class. For example, there are many global qHash() functions spread around QtBase. Each is meant to compute a hash index for an object of some class type, so the object can be inserted into a QHash map for that class type. It is then desired to relate qHash(type Xxx, int seed) to both QHash<type> and class Xxx, so that the documentation for that qHash() function appears as a related non-member function of both QHash<type> and class Xxx. The example above also illustrates the overload numbering problem, because all these qHash() functions are overloads of the name qHash. To make matters worse, they are not all in the same module. Most of them are in QtCore, but a few are in QtNetwork, and this distribution problem will become worse over time as more qHash() functions are added. Prior to this update, qdoc was unable to relate a function to something in a different module, or it didn't always work. While designing a fix for these issues, it became clear that the processing of the FunctionNode and the function parameters would have to be rewritten. That's what this update does. These are the main points: 1. A new subclass of Node is added to act as a proxy for a class in another module. This ProxyNode acts as a place holder for the functions (and possibly other elements) that are related to a class in another module. This is used for the qHash() functions in QtNetwork that are related to QHash in QtCore. qdoc generates an html file named qtnetwork/qhash-proxy.html that contains the documentation for these functions. But these functions are listed as related non-members on the QHash class reference page in the qtcore output directory. They are listed there in the summary, but they link to the qhash-proxy.html page in qtnetwork. 2. A new, Parameters class is added to qdoc (parameters.h and parameters.cpp), and the class Parameter is moved there from node.h. class Parameters replaces the old QVector<Parameter> wherever it was used. This encapsulates all the parameter processing and matching in the Parameters class and simplifies the code at all the places where QVector<Parameter> had been used. 3. The assignment of overload numbers is now done in the normalizeOverloads() function, which is called after all the headers and sources have been processed but before the generate phase begins. This assignment is a simple renumbering now because all the overloads of a function are linked to each other via a nextOverload_ link in the FunctionNode. The first function named qHash() is inserted into the Aggregate node's function map, but subsequent qHash() FunctionNodes are not entered into the function map but are linked to the first qHash() via its nextOverload_ link. 4. The \relates command can now be used multiple times in a single qdoc comment. There remains some work to be done here because this currently only works for global entities, but there are several cases where \relates has been used in the qdoc comment of a member of a class. This will be fixed soon, I believe. When qdoc sees the first \relates Xxx command, for example for qHash(Yyy, seed), that qHash() is a child of the global namespace. qdoc allows it to remain as a child of the global namespace but it tells class Xxx to "adopt" that child (see Node::adoptChild()). This function makes this instance of qHash() be a child of class Xxx (in this case QHash<type>), so that the parent of this qHash() becomes Xxx. After this "adoption," qHash() is a child of both the global namespace and class Xxx, but qHash() only knows it is a child of Xxx, i.e. its parent pointer is Xxx. If this is the first qHash() to become a child of Xxx, it is inserted into the function map of Xxx, but its nextOverload_ link is not changed. This is because all the global qHash() functions have already been linked into the nextOverload_ linked list, and this list must not be changed. Hence, when qdoc searches for qHash(something) to make a link to it, it will find it as a child of the global namespace, but it will correctly link to it using its actual parent pointer. When qdoc sees the second \relates Yyy for this qHash() function, qdoc sees that this FunctionNode has already been made a related non-member of Xxx, so it can't let Yyy "adopt" it. Instead, it tells Yyy to clone this qHash(), which creates a shallow copy of it but resets its nextOverload_ pointer to nullptr. I believe this clone of qHash() won't be found in a search for a function named qHash(), because the global one (the adopted one) will be found first. Or, if it is found, a link to the clone will be generated, but that's ok because the documentation is identical. Note that the existence of qHash in two child lists is taken into account at destruction time. The only place where a Node is destroyed is in the destructor of Tree, which destroys the Node tree from the root down to the leaves. Each aggregate node is responsible for deleting each of its child nodes, but it only deletes a child node if it is the parent of that child node. All of the above revealed that some of the findFunctionNode() functions were either no longer needed or weren't being called in the first place, so they were deleted. This change is now ready for testing. Change-Id: I6da3e2e9e71d39a29d90e073ed614309a49e3d4c Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r--src/qdoc/clangcodeparser.cpp81
-rw-r--r--src/qdoc/codeparser.cpp16
-rw-r--r--src/qdoc/codeparser.h7
-rw-r--r--src/qdoc/cppcodemarker.cpp57
-rw-r--r--src/qdoc/cppcodeparser.cpp643
-rw-r--r--src/qdoc/cppcodeparser.h49
-rw-r--r--src/qdoc/generator.cpp237
-rw-r--r--src/qdoc/generator.h7
-rw-r--r--src/qdoc/helpprojectwriter.cpp51
-rw-r--r--src/qdoc/htmlgenerator.cpp217
-rw-r--r--src/qdoc/htmlgenerator.h11
-rw-r--r--src/qdoc/main.cpp43
-rw-r--r--src/qdoc/node.cpp1648
-rw-r--r--src/qdoc/node.h285
-rw-r--r--src/qdoc/parameters.cpp567
-rw-r--r--src/qdoc/parameters.h127
-rw-r--r--src/qdoc/puredocparser.cpp36
-rw-r--r--src/qdoc/puredocparser.h11
-rw-r--r--src/qdoc/qdoc.pro2
-rw-r--r--src/qdoc/qdocdatabase.cpp674
-rw-r--r--src/qdoc/qdocdatabase.h126
-rw-r--r--src/qdoc/qdocindexfiles.cpp534
-rw-r--r--src/qdoc/qdocindexfiles.h16
-rw-r--r--src/qdoc/qdoctagfiles.cpp54
-rw-r--r--src/qdoc/qmlcodeparser.cpp37
-rw-r--r--src/qdoc/qmlcodeparser.h1
-rw-r--r--src/qdoc/qmlvisitor.cpp115
-rw-r--r--src/qdoc/sections.cpp132
-rw-r--r--src/qdoc/tree.cpp403
-rw-r--r--src/qdoc/tree.h62
-rw-r--r--src/qdoc/webxmlgenerator.cpp27
-rw-r--r--src/qdoc/webxmlgenerator.h2
32 files changed, 3280 insertions, 2998 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index 460c94365..cace61b9c 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -244,7 +244,7 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction: {
- NodeList candidates;
+ NodeVector candidates;
parent->findChildren(functionName(cur), candidates);
if (candidates.isEmpty())
return nullptr;
@@ -256,19 +256,19 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
if (!candidate->isFunction(Node::CPP))
continue;
auto fn = static_cast<FunctionNode*>(candidate);
- const auto &funcParams = fn->parameters();
- const int actualArg = numArg - fn->isPrivateSignal();
- if (funcParams.count() != (actualArg + isVariadic))
+ const Parameters &parameters = fn->parameters();
+ const int actualArg = numArg - parameters.isPrivateSignal();
+ if (parameters.count() != actualArg + isVariadic)
continue;
if (fn->isConst() != bool(clang_CXXMethod_isConst(cur)))
continue;
- if (isVariadic && funcParams.last().dataType() != QLatin1String("..."))
+ if (isVariadic && parameters.last().type() != QLatin1String("..."))
continue;
bool different = false;
for (int i = 0; i < actualArg; i++) {
if (args.size() <= i)
args.append(fromCXString(clang_getTypeSpelling(clang_getArgType(funcType, i))));
- QString t1 = funcParams.at(i).dataType();
+ QString t1 = parameters.at(i).type();
QString t2 = args.at(i);
auto p2 = parent;
while (p2 && t1 != t2) {
@@ -323,7 +323,7 @@ static Node *findFunctionNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction: {
- NodeList candidates;
+ NodeVector candidates;
parent->findChildren(functionName(cur), candidates);
if (candidates.isEmpty())
return nullptr;
@@ -335,18 +335,18 @@ static Node *findFunctionNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
if (!candidate->isFunction(Node::CPP))
continue;
auto fn = static_cast<FunctionNode*>(candidate);
- const auto &funcParams = fn->parameters();
- if (funcParams.count() != (numArg + isVariadic))
+ const Parameters &parameters = fn->parameters();
+ if (parameters.count() != (numArg + isVariadic))
continue;
if (fn->isConst() != bool(clang_CXXMethod_isConst(cur)))
continue;
- if (isVariadic && funcParams.last().dataType() != QLatin1String("..."))
+ if (isVariadic && parameters.last().type() != QLatin1String("..."))
continue;
bool different = false;
for (int i = 0; i < numArg; i++) {
if (args.size() <= i)
args.append(fromCXString(clang_getTypeSpelling(clang_getArgType(funcType, i))));
- QString t1 = funcParams.at(i).dataType();
+ QString t1 = parameters.at(i).type();
QString t2 = args.at(i);
auto p2 = parent;
while (p2 && t1 != t2) {
@@ -691,15 +691,17 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
for (uint i = 0; i < numOverridden; ++i) {
QString path = reconstructQualifiedPathForCursor(overridden[i]);
if (!path.isEmpty()) {
- fn->setReimplementedFrom(path);
+ fn->setOverride(true);
+ fn->setOverridesThis(path);
break;
}
}
clang_disposeOverriddenCursors(overridden);
}
auto numArg = clang_getNumArgTypes(funcType);
- QVector<Parameter> pvect;
- pvect.reserve(numArg);
+ Parameters &parameters = fn->parameters();
+ parameters.clear();
+ parameters.reserve(numArg);
for (int i = 0; i < numArg; ++i) {
CXType argType = clang_getArgType(funcType, i);
if (fn->isCtor()) {
@@ -715,15 +717,16 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
else if (argType.kind == CXType_LValueReference)
fn->setMetaness(FunctionNode::CAssign);
}
- pvect.append(Parameter(adjustTypeName(fromCXString(clang_getTypeSpelling(argType)))));
+ parameters.append(adjustTypeName(fromCXString(clang_getTypeSpelling(argType))));
}
- if (pvect.size() > 0 && pvect.last().dataType().endsWith(QLatin1String("::QPrivateSignal"))) {
- pvect.pop_back(); // remove the QPrivateSignal argument
- fn->setPrivateSignal();
+ if (parameters.count() > 0) {
+ if (parameters.last().type().endsWith(QLatin1String("::QPrivateSignal"))) {
+ parameters.pop_back(); // remove the QPrivateSignal argument
+ parameters.setPrivateSignal();
+ }
}
if (clang_isFunctionTypeVariadic(funcType))
- pvect.append(Parameter(QStringLiteral("...")));
- fn->setParameters(pvect);
+ parameters.append(QStringLiteral("..."));
readParameterNamesAndAttributes(fn, cursor);
return CXChildVisit_Continue;
}
@@ -836,7 +839,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cursor)
{
- auto pvect = fn->parameters();
+ Parameters &parameters = fn->parameters();
// Visit the parameters and attributes
int i = 0;
visitChildrenLambda(cursor, [&](CXCursor cur) {
@@ -853,11 +856,11 @@ void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cu
} else if (kind == CXCursor_CXXOverrideAttr) {
fn->setOverride(true);
} else if (kind == CXCursor_ParmDecl) {
- if (i >= pvect.count())
+ if (i >= parameters.count())
return CXChildVisit_Break; // Attributes comes before parameters so we can break.
QString name = fromCXString(clang_getCursorSpelling(cur));
if (!name.isEmpty())
- pvect[i].setName(name);
+ parameters[i].setName(name);
// Find the default value
visitChildrenLambda(cur, [&](CXCursor cur) {
if (clang_isExpression(clang_getCursorKind(cur))) {
@@ -866,7 +869,7 @@ void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cu
defaultValue = defaultValue.midRef(1).trimmed().toString();
if (defaultValue.isEmpty())
defaultValue = QStringLiteral("...");
- pvect[i].setDefaultValue(defaultValue);
+ parameters[i].setDefaultValue(defaultValue);
return CXChildVisit_Break;
}
return CXChildVisit_Continue;
@@ -875,7 +878,6 @@ void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cu
}
return CXChildVisit_Continue;
});
- fn->setParameters(pvect);
}
void ClangVisitor::parseProperty(const QString& spelling, const Location& loc)
@@ -1109,7 +1111,6 @@ static const char *defaultArgs_[] = {
"-Wno-nullability-completeness",
"-I" CLANG_RESOURCE_DIR
};
-static QByteArray clangResourcePath = "-I";
/*!
Load the default arguments and the defines into \a args.
@@ -1154,7 +1155,6 @@ void ClangCodeParser::getMoreArgs()
*/
auto forest = qdb_->searchOrder();
- printParsingErrors_ = 0;
QByteArray version = qdb_->version().toUtf8();
QString basicIncludeDir = QDir::cleanPath(QString(Config::installDir + "/../include"));
moreArgs_ += "-I" + basicIncludeDir.toLatin1();
@@ -1326,6 +1326,11 @@ static float getUnpatchedVersion(QString t)
*/
void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QString& filePath)
{
+ /*
+ The set of open namespaces is cleared before parsing
+ each source file. The word "source" here means cpp file.
+ */
+ qdb_->clearOpenNamespaces();
currentFile_ = filePath;
flags_ = static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing);
index_ = clang_createIndex(1, 0);
@@ -1336,6 +1341,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
args_.push_back("-include-pch");
args_.push_back(pchName_.constData());
}
+ getMoreArgs();
for (const auto &p : qAsConst(moreArgs_))
args_.push_back(p.constData());
@@ -1356,7 +1362,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
CXToken *tokens;
unsigned int numTokens = 0;
- const QSet<QString>& metacommands = topicCommands() + otherMetaCommands();
+ const QSet<QString> &commands = topicCommands() + metaCommands();
clang_tokenize(tu, clang_getCursorExtent(cur), &tokens, &numTokens);
for (unsigned int i = 0; i < numTokens; ++i) {
@@ -1371,7 +1377,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
Doc::trimCStyleComment(loc,comment);
// Doc constructor parses the comment.
- Doc doc(loc, end_loc, comment, metacommands, topicCommands());
+ Doc doc(loc, end_loc, comment, commands, topicCommands());
if (hasTooManyTopics(doc))
continue;
@@ -1416,7 +1422,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
} else {
processTopicArgs(doc, topic, nodes, docs);
}
- processOtherMetaCommands(nodes, docs);
+ processMetaCommands(nodes, docs);
}
clang_disposeTokens(tu, tokens, numTokens);
@@ -1459,9 +1465,9 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg
QString params = rightParenSplit[0];
if (!params.isEmpty()) {
QStringList commaSplit = params.split(',');
- QVector<Parameter>& pvect = fn->parameters();
- if (pvect.size() == commaSplit.size()) {
- for (int i = 0; i < pvect.size(); ++i) {
+ Parameters &parameters = fn->parameters();
+ if (parameters.count() == commaSplit.size()) {
+ for (int i = 0; i < parameters.count(); ++i) {
QStringList blankSplit = commaSplit[i].split(' ');
if (blankSplit.size() > 0) {
QString pName = blankSplit.last();
@@ -1470,8 +1476,8 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg
j++;
if (j > 0)
pName = pName.mid(j);
- if (!pName.isEmpty() && pName != pvect[i].name())
- pvect[i].setName(pName);
+ if (!pName.isEmpty() && pName != parameters[i].name())
+ parameters[i].setName(pName);
}
}
}
@@ -1529,6 +1535,11 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg
ClangVisitor visitor(qdb_, allHeaders_);
bool ignoreSignature = false;
visitor.visitFnArg(cur, &fnNode, ignoreSignature);
+ /*
+ If the visitor couldn't find a FunctionNode for the
+ signature, then print the clang diagnostics if there
+ were any.
+ */
if (fnNode == nullptr) {
unsigned diagnosticCount = clang_getNumDiagnostics(tu);
if (diagnosticCount > 0 && (!Generator::preparing() || Generator::singleExec())) {
diff --git a/src/qdoc/codeparser.cpp b/src/qdoc/codeparser.cpp
index 48cb98c64..925f1c665 100644
--- a/src/qdoc/codeparser.cpp
+++ b/src/qdoc/codeparser.cpp
@@ -169,26 +169,32 @@ static QSet<QString> commonMetaCommands_;
const QSet<QString>& CodeParser::commonMetaCommands()
{
if (commonMetaCommands_.isEmpty()) {
- commonMetaCommands_ << COMMAND_DEPRECATED
+ commonMetaCommands_ << COMMAND_ABSTRACT
+ << COMMAND_DEPRECATED
<< COMMAND_INGROUP
+ << COMMAND_INJSMODULE
<< COMMAND_INMODULE
+ << COMMAND_INPUBLICGROUP
<< COMMAND_INQMLMODULE
<< COMMAND_INTERNAL
<< COMMAND_MAINCLASS
+ << COMMAND_NOAUTOLIST
<< COMMAND_NONREENTRANT
<< COMMAND_OBSOLETE
<< COMMAND_PAGEKEYWORDS
<< COMMAND_PRELIMINARY
- << COMMAND_INPUBLICGROUP
+ << COMMAND_QMLABSTRACT
+ << COMMAND_QMLDEFAULT
+ << COMMAND_QMLINHERITS
+ << COMMAND_QMLREADONLY
<< COMMAND_QTVARIABLE
<< COMMAND_REENTRANT
<< COMMAND_SINCE
+ << COMMAND_STARTPAGE
<< COMMAND_SUBTITLE
<< COMMAND_THREADSAFE
<< COMMAND_TITLE
- << COMMAND_WRAPPER
- << COMMAND_INJSMODULE
- << COMMAND_NOAUTOLIST;
+ << COMMAND_WRAPPER;
}
return commonMetaCommands_;
}
diff --git a/src/qdoc/codeparser.h b/src/qdoc/codeparser.h
index a6b72956e..7bf6bb807 100644
--- a/src/qdoc/codeparser.h
+++ b/src/qdoc/codeparser.h
@@ -35,12 +35,13 @@
QT_BEGIN_NAMESPACE
class Config;
+class Location;
class QString;
class QDocDatabase;
class CodeParser
{
- Q_DECLARE_TR_FUNCTIONS(QDoc::CodeParser)
+ Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser)
public:
CodeParser();
@@ -55,8 +56,6 @@ public:
virtual void parseSourceFile(const Location& location, const QString& filePath) = 0;
virtual void precompileHeaders() { }
virtual Node *parseFnArg(const Location &, const QString &) { return 0; }
- virtual Node *parseMacroArg(const Location &, const QString &) { return 0; }
- virtual Node *parseOtherFuncArg(const QString &, const Location &, const QString &) { return 0; }
bool isParsingH() const;
bool isParsingCpp() const;
@@ -83,10 +82,10 @@ protected:
QString moduleHeader_;
QString currentFile_;
QDocDatabase* qdb_;
- static bool showInternal_;
private:
static QList<CodeParser *> parsers;
+ static bool showInternal_;
static bool singleExec_;
};
diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp
index adeb2db1c..aad3c6dd7 100644
--- a/src/qdoc/cppcodemarker.cpp
+++ b/src/qdoc/cppcodemarker.cpp
@@ -148,19 +148,24 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
if (!func->isMacroWithoutParams()) {
synopsis += QLatin1Char('(');
if (!func->parameters().isEmpty()) {
- QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
- while (p != func->parameters().constEnd()) {
- if (p != func->parameters().constBegin())
+ const Parameters &parameters = func->parameters();
+ for (int i = 0; i < parameters.count(); i++) {
+ if (i > 0)
synopsis += ", ";
- bool hasName = !(*p).name().isEmpty();
- if (hasName)
- synopsis += typified((*p).dataType(), true);
- const QString &paramName = hasName ? (*p).name() : (*p).dataType();
- if (style != Section::AllMembers || !hasName)
+ QString name = parameters.at(i).name();
+ QString type = parameters.at(i).type();
+ QString value = parameters.at(i).defaultValue();
+ QString paramName;
+ if (!name.isEmpty()) {
+ synopsis += typified(type, true);
+ paramName = name;
+ } else {
+ paramName = type;
+ }
+ if (style != Section::AllMembers || name.isEmpty())
synopsis += "<@param>" + protect(paramName) + "</@param>";
- if (style != Section::AllMembers && !(*p).defaultValue().isEmpty())
- synopsis += " = " + protect((*p).defaultValue());
- ++p;
+ if (style != Section::AllMembers && !value.isEmpty())
+ synopsis += " = " + protect(value);
}
}
synopsis += QLatin1Char(')');
@@ -177,10 +182,6 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
synopsis.append(" override");
if (func->isPureVirtual())
synopsis.append(" = 0");
- else if (func->isDeleted())
- synopsis.append(" = delete");
- else if (func->isImplicit() || func->isDefaulted())
- synopsis.append(" = default");
if (func->isRef())
synopsis.append(" &");
else if (func->isRefRef())
@@ -195,15 +196,9 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
synopsis.append(" &");
else if (func->isRefRef())
synopsis.append(" &&");
- if (func->isImplicit() || func->isDefaulted())
- synopsis.append(" = default");
QStringList bracketed;
if (func->isStatic()) {
bracketed += "static";
- } else if (func->isDeleted()) {
- bracketed += "delete";
- } else if (func->isDefaulted()) {
- bracketed += "default";
} else if (!func->isNonvirtual()) {
if (func->isFinal())
bracketed += "final";
@@ -341,16 +336,20 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
synopsis = name;
synopsis += QLatin1Char('(');
if (!func->parameters().isEmpty()) {
- QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
- while (p != func->parameters().constEnd()) {
- if (p != func->parameters().constBegin())
+ const Parameters &parameters = func->parameters();
+ for (int i = 0; i < parameters.count(); i++) {
+ if (i > 0)
synopsis += ", ";
- bool hasName = !(*p).name().isEmpty();
- if (hasName)
- synopsis += typified((*p).dataType(), true);
- const QString &paramName = hasName ? (*p).name() : (*p).dataType();
+ QString name = parameters.at(i).name();
+ QString type = parameters.at(i).type();
+ QString paramName;
+ if (!name.isEmpty()) {
+ synopsis += typified(type, true);
+ paramName = name;
+ } else {
+ paramName = type;
+ }
synopsis += "<@param>" + protect(paramName) + "</@param>";
- ++p;
}
}
synopsis += QLatin1Char(')');
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp
index c80ab745b..a889c988e 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,23 +43,20 @@ 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
@@ -100,22 +95,16 @@ CppCodeParser::CppCodeParser()
<< 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_STARTPAGE
- << COMMAND_QMLINHERITS
- << COMMAND_QMLINSTANTIATES
- << COMMAND_QMLDEFAULT
- << COMMAND_QMLREADONLY
- << COMMAND_QMLABSTRACT
- << COMMAND_ABSTRACT;
+ if (metaCommands_.isEmpty()) {
+ metaCommands_ = commonMetaCommands();
+ metaCommands_ << COMMAND_CONTENTSPAGE
+ << COMMAND_INHEADERFILE
+ << COMMAND_NEXTPAGE
+ << COMMAND_OVERLOAD
+ << COMMAND_PREVIOUSPAGE
+ << COMMAND_QMLINSTANTIATES
+ << COMMAND_REIMP
+ << COMMAND_RELATES;
}
}
@@ -238,8 +227,6 @@ Node* CppCodeParser::processTopicCommand(const Doc& 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) {
@@ -556,48 +543,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->parent() && !node->parent()->isInternal()) {
if (node->isFunction()) {
- FunctionNode *func = (FunctionNode *) node;
- if (func->reimplementedFrom().isEmpty() && isWorthWarningAbout(doc)) {
+ 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()));
@@ -606,20 +605,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<PageNode*>(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);
@@ -653,38 +674,10 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
doc.location().warning(tr("\\instantiates is only allowed in \\qmltype"));
}
else if (command == COMMAND_QMLDEFAULT) {
- if (node->nodeType() == Node::QmlProperty) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setDefault();
- }
- else if (node->nodeType() == Node::QmlPropertyGroup) {
- QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node);
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->nodeType() == Node::QmlProperty) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(*p);
- qpn->setDefault();
- }
- ++p;
- }
- }
+ node->markDefault();
}
else if (command == COMMAND_QMLREADONLY) {
- if (node->nodeType() == Node::QmlProperty) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setReadOnly(1);
- }
- else if (node->nodeType() == Node::QmlPropertyGroup) {
- QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node);
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->nodeType() == 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())
@@ -711,21 +704,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
if (!node->isInternal())
node->setStatus(Node::Preliminary);
} else if (command == COMMAND_INTERNAL) {
- if (!showInternal()) {
- node->setAccess(Node::Private);
- node->setStatus(Node::Internal);
- if (node->nodeType() == Node::QmlPropertyGroup) {
- const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node);
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->nodeType() == Node::QmlProperty) {
- (*p)->setAccess(Node::Private);
- (*p)->setStatus(Node::Internal);
- }
- ++p;
- }
- }
- }
+ if (!showInternal())
+ node->markInternal();
} else if (command == COMMAND_REENTRANT) {
node->setThreadSafeness(Node::Reentrant);
} else if (command == COMMAND_SINCE) {
@@ -755,20 +735,21 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
/*!
- 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;
@@ -776,435 +757,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;
@@ -1224,7 +779,7 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic, const Location& loc
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;
@@ -1240,7 +795,7 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic, const Location& loc
if (!aggregate)
aggregate = qdb_->findQmlBasicType(moduleName, elementName);
if (!aggregate)
- return 0;
+ return nullptr;
QString params;
QStringList leftParenSplit = funcArg.split('(');
@@ -1266,7 +821,7 @@ Node* CppCodeParser::parseOtherFuncArg(const QString& topic, const Location& loc
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)
{
QStringList leftParenSplit = macroArg.split('(');
if (leftParenSplit.isEmpty())
@@ -1276,7 +831,7 @@ Node* CppCodeParser::parseMacroArg(const Location& location, const QString& macr
QStringList blankSplit = leftParenSplit[0].split(' ');
if (blankSplit.size() > 0) {
macroName = blankSplit.last();
- oldMacroNode = static_cast<FunctionNode*>(qdb_->findMacroNode(macroName));
+ oldMacroNode = qdb_->findMacroNode(macroName);
}
QString returnType;
if (blankSplit.size() > 1) {
@@ -1495,25 +1050,25 @@ 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()) {
if (*n != nullptr) {
- processOtherMetaCommands(*d, *n);
+ processMetaCommands(*d, *n);
(*n)->setDoc(*d);
checkModuleInclusion(*n);
if ((*n)->isAggregate()) {
Aggregate *aggregate = static_cast<Aggregate *>(*n);
- if (aggregate->includes().isEmpty()) {
+ if (aggregate->includeFiles().isEmpty()) {
Aggregate *parent = aggregate;
while (parent->physicalModuleName().isEmpty() && (parent->parent() != nullptr))
parent = parent->parent();
if (parent == aggregate)
- aggregate->addInclude(aggregate->name());
+ aggregate->addIncludeFile(aggregate->name());
else
- aggregate->setIncludes(parent->includes());
+ aggregate->setIncludeFiles(parent->includeFiles());
}
}
}
diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h
index 8964ef699..76669f965 100644
--- a/src/qdoc/cppcodeparser.h
+++ b/src/qdoc/cppcodeparser.h
@@ -29,18 +29,13 @@
#ifndef CPPCODEPARSER_H
#define CPPCODEPARSER_H
-#include <qregexp.h>
-
#include "codeparser.h"
QT_BEGIN_NAMESPACE
class ClassNode;
-class CodeChunk;
-class CppCodeParserPrivate;
class FunctionNode;
class Aggregate;
-class Tokenizer;
class CppCodeParser : public CodeParser
{
@@ -65,13 +60,8 @@ public:
QString language() override { return QStringLiteral("Cpp"); }
QStringList headerFileNameFilter() override;
QStringList sourceFileNameFilter() override;
- bool parseParameters(const QString& parameters, QVector<Parameter>& pvect, bool& isQPrivateSignal);
- Node *parseMacroArg(const Location &location, const QString &macroArg) override;
- Node *parseOtherFuncArg(const QString &topic,
- const Location &location,
- const QString &funcArg) override;
- const Location& declLoc() const { return declLoc_; }
- void setDeclLoc() { declLoc_ = location(); }
+ FunctionNode *parseMacroArg(const Location &location, const QString &macroArg);
+ FunctionNode *parseOtherFuncArg(const QString &topic, const Location &location, const QString &funcArg);
static bool isJSMethodTopic(const QString &t);
static bool isQMLMethodTopic(const QString &t);
static bool isJSPropertyTopic(const QString &t);
@@ -79,7 +69,7 @@ public:
protected:
static const QSet<QString>& topicCommands();
- static const QSet<QString>& otherMetaCommands();
+ static const QSet<QString>& metaCommands();
virtual Node* processTopicCommand(const Doc& doc,
const QString& command,
const ArgLocPair& arg);
@@ -95,46 +85,19 @@ protected:
QString& element,
QString& name,
const Location& location);
- virtual void processOtherMetaCommand(const Doc& doc,
- const QString& command,
- const ArgLocPair& argLocPair,
- Node *node);
- void processOtherMetaCommands(const Doc& doc, Node *node);
- void processOtherMetaCommands(NodeList &nodes, DocList& docs);
+ void processMetaCommand(const Doc &doc, const QString &command, const ArgLocPair &argLocPair, Node *node);
+ void processMetaCommands(const Doc &doc, Node *node);
+ void processMetaCommands(NodeList &nodes, DocList &docs);
void processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, DocList &docs);
bool hasTooManyTopics(const Doc &doc) const;
- protected:
- void reset();
- void readToken();
- const Location& location();
- QString previousLexeme();
- QString lexeme();
-
private:
- bool match(int target);
- bool skipTo(int target);
- bool matchModuleQualifier(QString& name);
- bool matchTemplateAngles(CodeChunk *type = 0);
- bool matchDataType(CodeChunk *type, QString *var = 0, bool qProp = false);
- bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal);
- bool matchUsingDecl(Aggregate* parent);
void setExampleFileLists(PageNode *pn);
protected:
QMap<QString, Node::NodeType> nodeTypeMap;
- Tokenizer *tokenizer;
- int tok;
- Node::Access access;
- FunctionNode::Metaness metaness_;
- QString physicalModuleName;
- QStringList lastPath_;
- QRegExp varComment;
- QRegExp sep;
- Location declLoc_;
private:
-
static QStringList exampleFiles;
static QStringList exampleDirs;
static QSet<QString> excludeDirs;
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 9d234475f..8a9e4b8e7 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -365,11 +365,9 @@ static void transmogrify(QString &input, QString &output)
QString Generator::fileBase(const Node *node) const
{
- if (node->relates())
- node = node->relates();
- else if (!node->isPageNode() && !node->isCollectionNode())
+ if (!node->isPageNode() && !node->isCollectionNode())
node = node->parent();
- if (node->isQmlPropertyGroup())
+ if (node->isQmlPropertyGroup() || node->isJsPropertyGroup())
node = node->parent();
if (node->hasFileNameBase())
@@ -403,9 +401,8 @@ QString Generator::fileBase(const Node *node) const
if (node->isExample()) {
base.append(QLatin1String("-example"));
}
- }
- else if (node->isQmlType() || node->isQmlBasicType() ||
- node->isJsType() || node->isJsBasicType()) {
+ } else if (node->isQmlType() || node->isQmlBasicType() ||
+ node->isJsType() || node->isJsBasicType()) {
base = node->name();
/*
To avoid file name conflicts in the html directory,
@@ -419,8 +416,10 @@ QString Generator::fileBase(const Node *node) const
+ QLatin1Char('-'));
}
base.prepend(outputPrefix(node));
- }
- else {
+ } else if (node->isProxyNode()) {
+ base = node->name();
+ base.append("-proxy");
+ } else {
const Node *p = node;
forever {
const Node *pp = p->parent();
@@ -600,10 +599,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
Node *parentNode = 0;
- if ((parentNode = node->relates())) {
- parentName = fullDocumentLocation(node->relates());
- }
- else if ((parentNode = node->parent())) {
+ if ((parentNode = node->parent())) {
if (parentNode->isQmlPropertyGroup() || parentNode->isJsPropertyGroup()) {
parentNode = parentNode->parent();
parentName = fullDocumentLocation(parentNode);
@@ -616,6 +612,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
switch (node->nodeType()) {
case Node::Class:
case Node::Namespace:
+ case Node::Proxy:
parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
break;
case Node::Function:
@@ -843,28 +840,25 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
generateText(text, node, marker);
out() << "</p>";
}
- else if (!node->isWrapper() && !node->isReimplemented()) {
+ else if (!node->isWrapper() && !node->isMarkedReimp()) {
if (!func->isIgnored()) // undocumented functions added by Q_OBJECT
node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature()));
}
- }
- else if (!node->isWrapper() && !node->isReimplemented()) {
- /*
- Don't require documentation of things defined in Q_GADGET
- */
+ } else if (!node->isWrapper() && !node->isMarkedReimp()) {
+ // Don't require documentation of things defined in Q_GADGET
if (node->name() != QLatin1String("QtGadgetHelper"))
node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature()));
}
}
else if (!node->isSharingComment()) {
if (node->isFunction()) {
- const FunctionNode *func = static_cast<const FunctionNode *>(node);
- if (!func->reimplementedFrom().isEmpty())
- generateReimplementedFrom(func, marker);
+ const FunctionNode *fn = static_cast<const FunctionNode *>(node);
+ if (!fn->overridesThis().isEmpty())
+ generateReimplementsClause(fn, marker);
}
if (!generateText(node->doc().body(), node, marker)) {
- if (node->isReimplemented())
+ if (node->isMarkedReimp())
return;
}
@@ -901,62 +895,48 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
} else if (node->isFunction()) {
- const FunctionNode *func = static_cast<const FunctionNode *>(node);
- QSet<QString> definedParams;
- QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
- while (p != func->parameters().constEnd()) {
- if (!(*p).name().isEmpty())
- definedParams.insert((*p).name());
- ++p;
- }
-
- QSet<QString> documentedParams = func->doc().parameterNames();
- QSet<QString> allParams = definedParams + documentedParams;
- if (allParams.count() > definedParams.count()
- || allParams.count() > documentedParams.count()) {
- QSet<QString>::ConstIterator a = allParams.constBegin();
- while (a != allParams.constEnd()) {
- if (!definedParams.contains(*a)) {
+ const FunctionNode *fn = static_cast<const FunctionNode *>(node);
+ QSet<QString> declaredNames;
+ fn->parameters().getNames(declaredNames);
+ QSet<QString> documentedNames = fn->doc().parameterNames();
+ if (declaredNames != documentedNames) {
+ QSet<QString>::const_iterator i = declaredNames.constBegin();
+ while (i != declaredNames.constEnd()) {
+ if (!documentedNames.contains(*i)) {
+ if (fn->isActive() || fn->isPreliminary()) {
+ if (!fn->isMarkedReimp() && !fn->isOverload()) {
+ fn->doc().location().warning(
+ tr("Undocumented parameter '%1' in %2")
+ .arg(*i).arg(node->plainFullName()));
+ }
+ }
+ }
+ ++i;
+ }
+ i = documentedNames.constBegin();
+ while (i != documentedNames.constEnd()) {
+ if (!declaredNames.contains(*i)) {
+ QString best = nearestName(*i, declaredNames);
QString details;
- QString best = nearestName(*a, definedParams);
if (!best.isEmpty())
details = tr("Maybe you meant '%1'?").arg(best);
-
- node->doc().location().warning(
- tr("No such parameter '%1' in %2").arg(*a).arg(node->plainFullName()),
- details);
- }
- else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
- bool needWarning = (func->status() > Node::Obsolete);
- if (func->overloadNumber() > 0) {
- FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name(), QString());
- if (primaryFunc) {
- foreach (const Parameter &param,
- primaryFunc->parameters()) {
- if (param.name() == *a) {
- needWarning = false;
- break;
- }
- }
- }
- }
- if (needWarning && !func->isReimplemented() && !func->isOverload())
- node->doc().location().warning(
- tr("Undocumented parameter '%1' in %2")
- .arg(*a).arg(node->plainFullName()));
+ fn->doc().location().warning(tr("No such parameter '%1' in %2")
+ .arg(*i).arg(fn->plainFullName()),
+ details);
}
- ++a;
+ ++i;
}
}
/*
- Something like this return value check should
- be implemented at some point.
+ This return value check should be implemented
+ for all functions with a return type.
+ mws 13/12/2018
*/
- if (func->status() > Node::Obsolete && func->returnType() == "bool"
- && func->reimplementedFrom() == 0 && !func->isOverload()) {
- QString body = func->doc().body().toString();
- if (!body.contains("return", Qt::CaseInsensitive))
- node->doc().location().warning(tr("Undocumented return value"));
+ if (!fn->isObsolete() && fn->returnsBool() &&
+ !fn->isMarkedReimp() && !fn->isOverload()) {
+ if (!fn->doc().body().contains("return"))
+ node->doc().location().warning(tr("Undocumented return value "
+ "(hint: use 'return' or 'returns' in the text"));
}
}
}
@@ -1146,6 +1126,16 @@ void Generator::generateDocumentation(Node* node)
beginSubPage(node, fileName(node));
generateCollectionNode(cn, marker);
endSubPage();
+ } else if (cn->isGenericCollection()) {
+ // Currently used only for the module's related orphans page
+ // but can be generalized for other kinds of collections if
+ // other use cases pop up.
+ QString name = cn->name().toLower();
+ name.replace(QChar(' '), QString("-"));
+ QString filename = cn->tree()->physicalModuleName() + "-" + name + "." + fileExtension();
+ beginSubPage(node, filename);
+ generateGenericCollectionPage(cn, marker);
+ endSubPage();
}
} else if (node->isTextPageNode()) {
beginSubPage(node, fileName(node));
@@ -1157,30 +1147,30 @@ void Generator::generateDocumentation(Node* node)
beginSubPage(node, fileName(node));
generateCppReferencePage(static_cast<Aggregate*>(node), marker);
endSubPage();
- }
- else if (node->isQmlType() || node->isJsType()) {
+ } else if (node->isQmlType() || node->isJsType()) {
beginSubPage(node, fileName(node));
QmlTypeNode* qcn = static_cast<QmlTypeNode*>(node);
generateQmlTypePage(qcn, marker);
endSubPage();
- }
- else if (node->isQmlBasicType() || node->isJsBasicType()) {
+ } else if (node->isQmlBasicType() || node->isJsBasicType()) {
beginSubPage(node, fileName(node));
QmlBasicTypeNode* qbtn = static_cast<QmlBasicTypeNode*>(node);
generateQmlBasicTypePage(qbtn, marker);
endSubPage();
+ } else if (node->isProxyNode()) {
+ beginSubPage(node, fileName(node));
+ generateProxyPage(static_cast<Aggregate*>(node), marker);
+ endSubPage();
}
}
}
if (node->isAggregate()) {
Aggregate* aggregate = static_cast<Aggregate*>(node);
- int i = 0;
- while (i < aggregate->childNodes().count()) {
- Node *c = aggregate->childNodes().at(i);
- if (c->isPageNode() && !c->isPrivate())
- generateDocumentation(c);
- ++i;
+ const NodeList &children = aggregate->childNodes();
+ foreach (Node *n, children) {
+ if (n->isPageNode() && !n->isPrivate())
+ generateDocumentation(n);
}
}
}
@@ -1258,17 +1248,17 @@ bool Generator::generateQmlText(const Text& text,
return result;
}
-void Generator::generateReimplementedFrom(const FunctionNode *fn, CodeMarker *marker)
+void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *marker)
{
- if (!fn->reimplementedFrom().isEmpty()) {
+ if (!fn->overridesThis().isEmpty()) {
if (fn->parent()->isClass()) {
ClassNode* cn = static_cast<ClassNode*>(fn->parent());
- const FunctionNode *from = cn->findOverriddenFunction(fn);
- if (from && from->access() != Node::Private && from->parent()->access() != Node::Private) {
+ const FunctionNode *overrides = cn->findOverriddenFunction(fn);
+ if (overrides && !overrides->isPrivate() && !overrides->parent()->isPrivate()) {
Text text;
- text << Atom::ParaLeft << "Reimplemented from ";
- QString fullName = from->parent()->name() + "::" + from->name() + "()";
- appendFullName(text, from->parent(), fullName, from);
+ text << Atom::ParaLeft << "Reimplements: ";
+ QString fullName = overrides->parent()->name() + "::" + overrides->signature(false, true);
+ appendFullName(text, overrides->parent(), fullName, overrides);
text << "." << Atom::ParaRight;
generateText(text, fn, marker);
}
@@ -1423,30 +1413,28 @@ static bool hasExceptions(const Node* node,
{
bool result = false;
Node::ThreadSafeness ts = node->threadSafeness();
- const Aggregate* a = static_cast<const Aggregate*>(node);
- NodeList::ConstIterator c = a->childNodes().constBegin();
- while (c != a->childNodes().constEnd()) {
- if (!(*c)->isObsolete()){
- switch ((*c)->threadSafeness()) {
+ const NodeList &children = static_cast<const Aggregate*>(node)->childNodes();
+ foreach (Node *n, children) {
+ if (!n->isObsolete()){
+ switch (n->threadSafeness()) {
case Node::Reentrant:
- reentrant.append(*c);
+ reentrant.append(n);
if (ts == Node::ThreadSafe)
result = true;
break;
case Node::ThreadSafe:
- threadsafe.append(*c);
+ threadsafe.append(n);
if (ts == Node::Reentrant)
result = true;
break;
case Node::NonReentrant:
- nonreentrant.append(*c);
+ nonreentrant.append(n);
result = true;
break;
default:
break;
}
}
- ++c;
}
return result;
}
@@ -1575,18 +1563,19 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
/*!
If the node is an overloaded signal, and a node with an example on how to connect to it
+
+ Someone didn't finish writing this comment, and I don't know what this
+ function is supposed to do, so I have not tried to complete the comment
+ yet.
*/
void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
{
if (!node->isFunction())
return;
const FunctionNode *func = static_cast<const FunctionNode *>(node);
- if (!func->isSignal())
- return;
- if (node->parent()->overloads(node->name()).count() <= 1)
+ if (!func->isSignal() || !func->hasOverloads())
return;
-
// Compute a friendly name for the object of that instance.
// e.g: "QAbstractSocket" -> "abstractSocket"
QString objectName = node->parent()->name();
@@ -1601,23 +1590,9 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
// it is very unlikely that we will ever have public API overloading
// signals by const.
QString code = "connect(" + objectName + ", QOverload<";
- for (int i = 0; i < func->parameters().size(); ++i) {
- if (i != 0)
- code += ", ";
- code += func->parameters().at(i).dataType();
- }
-
+ func->parameters().getTypeList(code);
code += ">::of(&" + func->parent()->name() + "::" + func->name() + "),\n [=](";
-
- for (int i = 0; i < func->parameters().size(); ++i) {
- if (i != 0)
- code += ", ";
- const Parameter &p = func->parameters().at(i);
- code += p.dataType();
- if (code[code.size()-1].isLetterOrNumber())
- code += QLatin1Char(' ');
- code += p.name();
- }
+ func->parameters().getTypeAndNameList(code);
code += "){ /* ... */ });";
@@ -2118,30 +2093,30 @@ void Generator::initializeTextOutput()
void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
{
if (node->isFunction() && !node->isMacro()) {
- const FunctionNode *func = static_cast<const FunctionNode *>(node);
- if (func->overloadNumber() == 0) {
+ const FunctionNode *fn = static_cast<const FunctionNode *>(node);
+ if (fn->overloadNumber() == 0) {
QString alternateName;
const FunctionNode *alternateFunc = 0;
- if (func->name().startsWith("set") && func->name().size() >= 4) {
- alternateName = func->name()[3].toLower();
- alternateName += func->name().mid(4);
- alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
+ if (fn->name().startsWith("set") && fn->name().size() >= 4) {
+ alternateName = fn->name()[3].toLower();
+ alternateName += fn->name().mid(4);
+ alternateFunc = fn->parent()->findFunctionChild(alternateName, QString());
if (!alternateFunc) {
- alternateName = "is" + func->name().mid(3);
- alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
+ alternateName = "is" + fn->name().mid(3);
+ alternateFunc = fn->parent()->findFunctionChild(alternateName, QString());
if (!alternateFunc) {
- alternateName = "has" + func->name().mid(3);
- alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
+ alternateName = "has" + fn->name().mid(3);
+ alternateFunc = fn->parent()->findFunctionChild(alternateName, QString());
}
}
}
- else if (!func->name().isEmpty()) {
+ else if (!fn->name().isEmpty()) {
alternateName = "set";
- alternateName += func->name()[0].toUpper();
- alternateName += func->name().mid(1);
- alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
+ alternateName += fn->name()[0].toUpper();
+ alternateName += fn->name().mid(1);
+ alternateFunc = fn->parent()->findFunctionChild(alternateName, QString());
}
if (alternateFunc && alternateFunc->access() != Node::Private) {
diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h
index 1c0126d77..437da7ba0 100644
--- a/src/qdoc/generator.h
+++ b/src/qdoc/generator.h
@@ -91,6 +91,7 @@ public:
static bool preparing() { return (qdocPass_ == Prepare); }
static bool generating() { return (qdocPass_ == Generate); }
static bool singleExec() { return qdocSingleExec_; }
+ static bool dualExec() { return !qdocSingleExec_; }
static bool writeQaPages() { return qdocWriteQaPages_; }
static void setSingleExec() { qdocSingleExec_ = true; }
static void setWriteQaPages() { qdocWriteQaPages_ = true; }
@@ -113,11 +114,13 @@ protected:
virtual void generateAlsoList(const Node *node, CodeMarker *marker);
virtual int generateAtom(const Atom *, const Node *, CodeMarker *) { return 0; }
virtual void generateBody(const Node *node, CodeMarker *marker);
- virtual void generateCppReferencePage(Node *, CodeMarker *) {}
+ virtual void generateCppReferencePage(Aggregate *, CodeMarker *) {}
+ virtual void generateProxyPage(Aggregate *, CodeMarker *) {}
virtual void generateQmlTypePage(QmlTypeNode *, CodeMarker *) {}
virtual void generateQmlBasicTypePage(QmlBasicTypeNode *, CodeMarker *) {}
virtual void generatePageNode(PageNode *, CodeMarker *) {}
virtual void generateCollectionNode(CollectionNode *, CodeMarker *) {}
+ virtual void generateGenericCollectionPage(CollectionNode *, CodeMarker *) {}
virtual void generateInheritedBy(const ClassNode *classe, CodeMarker *marker);
virtual void generateInherits(const ClassNode *classe, CodeMarker *marker);
virtual void generateDocumentation(Node* node);
@@ -233,7 +236,7 @@ private:
static bool useOutputSubdirs_;
static QmlTypeNode* qmlTypeContext_;
- void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker);
+ void generateReimplementsClause(const FunctionNode *fn, CodeMarker *marker);
static bool compareNodes(Node *a, Node *b) { return (a->name() < b->name()); }
static bool comparePaths(QString a, QString b) { return (a < b); }
static void copyTemplateFiles(const Config &config,
diff --git a/src/qdoc/helpprojectwriter.cpp b/src/qdoc/helpprojectwriter.cpp
index 568624842..ec6f46b59 100644
--- a/src/qdoc/helpprojectwriter.cpp
+++ b/src/qdoc/helpprojectwriter.cpp
@@ -402,9 +402,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
// the set of files, we only need to ensure that related nodes
// are inserted.
- if (node->relates()) {
- project.memberStatus[node->relates()].insert(node->status());
- } else if (node->parent())
+ if (node->parent())
project.memberStatus[node->parent()].insert(node->status());
}
break;
@@ -471,8 +469,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
return true;
}
-void HelpProjectWriter::generateSections(HelpProject &project,
- QXmlStreamWriter &writer, const Node *node)
+void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter &writer, const Node *node)
{
/*
Don't include index nodes in the help file.
@@ -487,17 +484,13 @@ void HelpProjectWriter::generateSections(HelpProject &project,
// Ensure that we don't visit nodes more than once.
QSet<const Node*> childSet;
- foreach (const Node *childNode, aggregate->childNodes()) {
- if (childNode->isIndexNode())
+ const NodeList &children = aggregate->childNodes();
+ foreach (const Node *child, children) {
+ if (child->isIndexNode() || child->isPrivate())
continue;
-
- if (childNode->isPrivate())
- continue;
-
- if (childNode->isTextPageNode()) {
- childSet << childNode;
- }
- else if (childNode->isQmlPropertyGroup() || childNode->isJsPropertyGroup()) {
+ if (child->isTextPageNode()) {
+ childSet << child;
+ } else if (child->isQmlPropertyGroup() || child->isJsPropertyGroup()) {
/*
Don't visit QML/JS property group nodes,
but visit their children, which are all
@@ -507,26 +500,18 @@ void HelpProjectWriter::generateSections(HelpProject &project,
because The Qml/Js Property Group is
an actual documented thing.
*/
- const Aggregate* aggregate = static_cast<const Aggregate*>(childNode);
- foreach (const Node* n, aggregate->childNodes()) {
- if (n->isPrivate())
- continue;
- childSet << n;
+ const Aggregate *aggregate = static_cast<const Aggregate *>(child);
+ const NodeList &nodes = aggregate->childNodes();
+ foreach (const Node *n, nodes) {
+ if (!n->isPrivate())
+ childSet << n;
}
- }
- else {
+ } else {
// Store member status of children
- project.memberStatus[node].insert(childNode->status());
- if (childNode->relates()) {
- project.memberStatus[childNode->relates()].insert(childNode->status());
- }
-
- if (childNode->isFunction()) {
- const FunctionNode *funcNode = static_cast<const FunctionNode *>(childNode);
- if (funcNode->isOverload())
- continue;
- }
- childSet << childNode;
+ project.memberStatus[node].insert(child->status());
+ if (child->isFunction() && static_cast<const FunctionNode*>(child)->isOverload())
+ continue;
+ childSet << child;
}
}
foreach (const Node *child, childSet)
diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp
index a70ffabb9..a466fe227 100644
--- a/src/qdoc/htmlgenerator.cpp
+++ b/src/qdoc/htmlgenerator.cpp
@@ -335,8 +335,7 @@ void HtmlGenerator::generateDocs()
qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
projectUrl,
projectDescription,
- this,
- true);
+ this);
}
if (!preparing()) {
@@ -1340,11 +1339,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
header file documented in \a node using the code \a marker
provided.
*/
-void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker)
+void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker)
{
- Q_ASSERT(node->isAggregate());
- Aggregate* aggregate = static_cast<Aggregate*>(node);
-
QString title;
QString rawTitle;
QString fullTitle;
@@ -1549,6 +1545,103 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker)
generateFooter(aggregate);
}
+void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker)
+{
+ Q_ASSERT(aggregate->isProxyNode());
+
+ QString title;
+ QString rawTitle;
+ QString fullTitle;
+ Text subtitleText;
+ SectionVector *summarySections = 0;
+ SectionVector *detailsSections = 0;
+
+ Sections sections(aggregate);
+ rawTitle = aggregate->plainName();
+ fullTitle = aggregate->plainFullName();
+ title = rawTitle + " Proxy Page";
+ summarySections = &sections.stdSummarySections();
+ detailsSections = &sections.stdDetailsSections();
+ generateHeader(title, aggregate, marker);
+ generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
+ generateBrief(aggregate, marker);
+ SectionVector::ConstIterator s = summarySections->constBegin();
+ while (s != summarySections->constEnd()) {
+ if (!s->members().isEmpty()) {
+ // out() << "<hr />\n";
+ QString ref = registerRef(s->title().toLower());
+ out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n";
+ out() << "<h2 id=\"" << ref << "\">" << protectEnc(s->title()) << "</h2>\n";
+ generateSection(s->members(), aggregate, marker);
+ }
+ ++s;
+ }
+
+ QString detailsRef = registerRef("details");
+ out() << "<a name=\"" << detailsRef << "\"></a>" << divNavTop << '\n';
+
+ if (!aggregate->doc().isEmpty()) {
+ generateExtractionMark(aggregate, DetailedDescriptionMark);
+ //out() << "<hr />\n"
+ out() << "<div class=\"descr\">\n" // QTBUG-9504
+ << "<h2 id=\"" << detailsRef << "\">" << "Detailed Description" << "</h2>\n";
+ generateBody(aggregate, marker);
+ out() << "</div>\n"; // QTBUG-9504
+ generateAlsoList(aggregate, marker);
+ generateMaintainerList(aggregate, marker);
+ generateExtractionMark(aggregate, EndMark);
+ }
+
+ s = detailsSections->constBegin();
+ while (s != detailsSections->constEnd()) {
+ if (s->isEmpty()) {
+ ++s;
+ continue;
+ }
+ //out() << "<hr />\n";
+ if (!s->divClass().isEmpty())
+ out() << "<div class=\"" << s->divClass() << "\">\n"; // QTBUG-9504
+ out() << "<h2>" << protectEnc(s->title()) << "</h2>\n";
+
+ NodeVector::ConstIterator m = s->members().constBegin();
+ while (m != s->members().constEnd()) {
+ if (!(*m)->isPrivate()) { // ### check necessary?
+ if (!(*m)->isClass())
+ generateDetailedMember(*m, aggregate, marker);
+ else {
+ out() << "<h3> class ";
+ generateFullName(*m, aggregate);
+ out() << "</h3>";
+ generateBrief(*m, marker, aggregate);
+ }
+
+ QStringList names;
+ names << (*m)->name();
+ if ((*m)->isFunction()) {
+ const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m);
+ if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0)
+ names.clear();
+ } else if ((*m)->isEnumType()) {
+ const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m);
+ if (enume->flagsType())
+ names << enume->flagsType()->name();
+
+ foreach (const QString &enumName,
+ enume->doc().enumItemNames().toSet() -
+ enume->doc().omitEnumItemNames().toSet())
+ names << plainCode(marker->markedUpEnumValue(enumName,
+ enume));
+ }
+ }
+ ++m;
+ }
+ if (!s->divClass().isEmpty())
+ out() << "</div>\n"; // QTBUG-9504
+ ++s;
+ }
+ generateFooter(aggregate);
+}
+
/*!
Generate the HTML page for a QML type. \qcn is the QML type.
\marker is the code markeup object.
@@ -1794,6 +1887,46 @@ void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marke
}
/*!
+ Generate the HTML page for a generic collection. This is usually
+ a collection of C++ elements that are related to an element in
+ a different module.
+ */
+void HtmlGenerator::generateGenericCollectionPage(CollectionNode *cn, CodeMarker *marker)
+{
+ SubTitleSize subTitleSize = LargeSubTitle;
+ QString fullTitle = cn->name();
+ QString ref;
+
+ generateHeader(fullTitle, cn, marker);
+ generateKeywordAnchors(cn);
+ generateTitle(fullTitle, Text() << cn->subtitle(), subTitleSize, cn, marker);
+
+ Text brief;
+ brief << "Each function or type documented here is related to a class or "
+ << "namespace that is documented in a different module. The reference "
+ << "page for that class or namespace will link to the function or type "
+ << "on this page.";
+#if 0
+ << Atom(Atom::LinkNode, CodeMarker::stringForNode(NS))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, " here.")
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+#endif
+ out() << "<p>";
+ generateText(brief, cn, marker);
+ out() << "</p>\n";
+
+ NodeList::ConstIterator m = cn->members().constBegin();
+ while (m != cn->members().constEnd()) {
+ generateDetailedMember(*m, cn, marker);
+ ++m;
+ }
+
+ // generateAnnotatedList(cn, marker, cn->members());
+ generateFooter(cn);
+}
+
+/*!
Returns "html" for this subclass of Generator.
*/
QString HtmlGenerator::fileExtension() const
@@ -2117,12 +2250,11 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker)
const QString instantiatedByText = "Instantiated By";
const QString qtVariableText = "qmake";
- //add the includes to the map
- if (!aggregate->includes().isEmpty()) {
+ //add the include files to the map
+ if (!aggregate->includeFiles().isEmpty()) {
text.clear();
- text << highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(aggregate->includes())),
- aggregate);
+ text << highlightedCode(indent(codeIndent, marker->markedUpIncludes(aggregate->includeFiles())),
+ aggregate);
requisites.insert(headerText, text);
}
@@ -2381,21 +2513,6 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
}
/*!
- This function is not used currently.
- It should be removed. MWS 27-06-2018
- */
-void HtmlGenerator::generateIncludes(const Aggregate *aggregate, CodeMarker *marker)
-{
- if (!aggregate->includes().isEmpty()) {
- out() << "<pre class=\"cpp\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(aggregate->includes())),
- aggregate), codePrefix, codeSuffix)
- << "</pre>";
- }
-}
-
-/*!
Revised for the new doc format.
Generates a table of contents beginning at \a node.
*/
@@ -3356,7 +3473,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N
}
}
-// generateSynopsis(qmn,relative,marker,Section::Details,false);
+// generateSynopsis(*m, relative, marker, Section::Summary, alignNames);
void HtmlGenerator::generateSynopsis(const Node *node,
const Node *relative,
CodeMarker *marker,
@@ -3439,8 +3556,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
html += QLatin1String("</b>");
}
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
- const Node* n = qdb_->findFunctionNode(par1.toString(), relative, genus);
- QString link = linkForNode(n, relative);
+ const FunctionNode *fn = qdb_->findFunctionNode(par1.toString(), relative, genus);
+ QString link = linkForNode(fn, relative);
addLink(link, arg, &html);
par1 = QStringRef();
}
@@ -3652,7 +3769,7 @@ QString HtmlGenerator::protect(const QString &string, const QString &outputEncod
QString HtmlGenerator::fileBase(const Node *node) const
{
QString result = Generator::fileBase(node);
- if (!node->isAggregate() && node->status() == Node::Obsolete)
+ if (!node->isAggregate() && node->isObsolete())
result += QLatin1String("-obsolete");
return result;
}
@@ -3809,7 +3926,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
return node->url();
if (fileBase(node).isEmpty())
return QString();
- if (node->access() == Node::Private)
+ if (node->isPrivate())
return QString();
QString fn = fileName(node);
if (node && node->parent() &&
@@ -3869,7 +3986,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, const Node *relat
}
void HtmlGenerator::generateDetailedMember(const Node *node,
- const Aggregate *relative,
+ const PageNode *relative,
CodeMarker *marker)
{
const EnumNode *etn;
@@ -3952,7 +4069,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
generatePrivateSignalNote(node, marker);
if (fn->isInvokable())
generateInvokableNote(node, marker);
- generateAssociatedPropertyNotes(fn);
+ generateAssociatedPropertyNotes(const_cast<FunctionNode*>(fn));
}
else if (node->isEnumType()) {
const EnumNode *etn = static_cast<const EnumNode *>(node);
@@ -4094,13 +4211,13 @@ void HtmlGenerator::generateQmlSummary(const Section& section,
while (m != section.members().constEnd()) {
out() << "<li class=\"fn\">";
generateQmlItem(*m,relative,marker,true);
- if ((*m)->isQmlPropertyGroup()) {
+ if ((*m)->isQmlPropertyGroup() || (*m)->isJsPropertyGroup()) {
const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*m);
- if (!qpgn->childNodes().isEmpty()) {
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
+ if (qpgn->count() > 0) {
+ NodeList::ConstIterator p = qpgn->constBegin();
out() << "<ul>\n";
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->isQmlProperty()) {
+ while (p != qpgn->constEnd()) {
+ if ((*p)->isQmlProperty() || (*p)->isJsProperty()) {
out() << "<li class=\"fn\">";
generateQmlItem(*p, relative, marker, true);
out() << "</li>\n";
@@ -4145,7 +4262,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
QString nodeRef = refForNode(node);
if (node->isQmlPropertyGroup() || node->isJsPropertyGroup()) {
const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node);
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
+ NodeList::ConstIterator p = qpgn->constBegin();
out() << "<div class=\"qmlproto\">";
out() << "<div class=\"table\"><table class=\"qmlname\">";
@@ -4155,7 +4272,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
out() << "<a name=\"" + nodeRef + "\"></a>";
out() << "<b>" << heading << "</b>";
out() << "</p></th></tr>";
- while (p != qpgn->childNodes().constEnd()) {
+ while (p != qpgn->constEnd()) {
if ((*p)->isQmlProperty() || (*p)->isJsProperty()) {
qpn = static_cast<QmlPropertyNode*>(*p);
nodeRef = refForNode(qpn);
@@ -4181,7 +4298,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
if (!qpn->isReadOnlySet()) {
if (qpn->declarativeCppNode())
- qpn->setReadOnly(!qpn->isWritable());
+ qpn->markReadOnly(!qpn->isWritable());
}
if (qpn->isReadOnly())
out() << "<span class=\"qmlreadonly\">[read-only] </span>";
@@ -4323,7 +4440,7 @@ void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType
if (!func->hasAssociatedProperties()) {
if (func->overloadNumber() == 0)
out() << "[overload1]";
- out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ out() << "$$$" + func->name() + func->parameters().rawSignature().remove(' ');
}
} else if (node->isProperty()) {
out() << "-prop";
@@ -4332,7 +4449,7 @@ void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType
foreach (const Node *propFuncNode, list) {
if (propFuncNode->isFunction()) {
const FunctionNode *func = static_cast<const FunctionNode *>(propFuncNode);
- out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ out() << "$$$" + func->name() + func->parameters().rawSignature().remove(' ');
}
}
} else if (node->isEnumType()) {
@@ -4638,9 +4755,8 @@ void HtmlGenerator::reportOrphans(const Aggregate* parent)
return;
QString message = "has documentation but no \\relates command";
- for (int i=0; i<children.size(); ++i) {
- Node* child = children[i];
- if (!child || child->isInternal() || child->doc().isEmpty() || child->relates())
+ foreach (Node *child, children) {
+ if (!child || child->isInternal() || child->doc().isEmpty() || !child->isRelatedNonmember())
continue;
switch (child->nodeType()) {
case Node::Enum:
@@ -4712,14 +4828,15 @@ QXmlStreamWriter& HtmlGenerator::xmlWriter()
Generates bold Note lines that explain how function \a fn
is associated with each of its associated properties.
*/
-void HtmlGenerator::generateAssociatedPropertyNotes(const FunctionNode* fn)
+void HtmlGenerator::generateAssociatedPropertyNotes(FunctionNode *fn)
{
if (fn->hasAssociatedProperties()) {
out() << "<p><b>Note:</b> ";
- PropNodeList propertyNodes = fn->associatedProperties();
- std::sort(propertyNodes.begin(), propertyNodes.end(), Node::nodeNameLessThan);
- foreach (const PropertyNode* pn, propertyNodes) {
+ NodeList &nodes = fn->associatedProperties();
+ std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan);
+ foreach (const Node *n, nodes) {
QString msg;
+ const PropertyNode *pn = static_cast<const PropertyNode*>(n);
switch (pn->role(fn)) {
case PropertyNode::Getter:
msg = QStringLiteral("Getter function ");
diff --git a/src/qdoc/htmlgenerator.h b/src/qdoc/htmlgenerator.h
index 731a12ac3..4ae50fac8 100644
--- a/src/qdoc/htmlgenerator.h
+++ b/src/qdoc/htmlgenerator.h
@@ -70,11 +70,13 @@ protected:
virtual int generateAtom(const Atom *atom,
const Node *relative,
CodeMarker *marker) override;
- void generateCppReferencePage(Node* node, CodeMarker* marker) override;
+ void generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker) override;
+ void generateProxyPage(Aggregate *aggregate, CodeMarker *marker) override;
void generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker) override;
void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker) override;
void generatePageNode(PageNode* pn, CodeMarker* marker) override;
void generateCollectionNode(CollectionNode* cn, CodeMarker* marker) override;
+ void generateGenericCollectionPage(CollectionNode *cn, CodeMarker *marker) override;
QString fileExtension() const override;
virtual QString refForNode(const Node *node);
virtual QString linkForNode(const Node *node, const Node *relative);
@@ -82,7 +84,7 @@ protected:
void generateManifestFile(const QString &manifest, const QString &element);
void readManifestMetaContent(const Config &config);
void generateKeywordAnchors(const Node* node);
- void generateAssociatedPropertyNotes(const FunctionNode* fn);
+ void generateAssociatedPropertyNotes(FunctionNode *fn);
QString getLink(const Atom *atom, const Node *relative, const Node **node);
QString getAutoLink(const Atom *atom, const Node *relative, const Node **node);
@@ -125,7 +127,6 @@ private:
void generateBrief(const Node *node,
CodeMarker *marker,
const Node *relative = 0, bool addLink=true);
- void generateIncludes(const Aggregate *inner, CodeMarker *marker);
void generateTableOfContents(const Node *node,
CodeMarker *marker,
QVector<Section>* sections = 0);
@@ -179,9 +180,7 @@ private:
Node::Genus genus = Node::DontCare);
void generateFullName(const Node *apparentNode, const Node *relative, const Node *actualNode = 0);
- void generateDetailedMember(const Node *node,
- const Aggregate *relative,
- CodeMarker *marker);
+ void generateDetailedMember(const Node *node, const PageNode *relative, CodeMarker *marker);
void generateLink(const Atom *atom, CodeMarker *marker);
inline bool hasBrief(const Node *node);
diff --git a/src/qdoc/main.cpp b/src/qdoc/main.cpp
index ea9dc6ed7..bb62a9160 100644
--- a/src/qdoc/main.cpp
+++ b/src/qdoc/main.cpp
@@ -392,7 +392,7 @@ static void processQdocconfFile(const QString &fileName)
}
Generator::augmentImageDirs(exampleImageDirs);
- if (!Generator::singleExec() || !Generator::generating()) {
+ if (Generator::dualExec() || Generator::preparing()) {
QStringList headerList;
QStringList sourceList;
@@ -473,19 +473,14 @@ static void processQdocconfFile(const QString &fileName)
++s;
}
Location::logToStdErrAlways("Source files parsed for " + project);
-
- /*
- Now the primary tree has been built from all the header and
- source files. Resolve all the class names, function names,
- targets, URLs, links, and other stuff that needs resolving.
- */
- qCDebug(lcQdoc, "Resolving stuff prior to generating docs");
- qdb->resolveInheritance();
- qdb->resolveIssues();
- }
- else {
- qdb->resolveStuff();
}
+ /*
+ Now the primary tree has been built from all the header and
+ source files. Resolve all the class names, function names,
+ targets, URLs, links, and other stuff that needs resolving.
+ */
+ qCDebug(lcQdoc, "Resolving stuff prior to generating docs");
+ qdb->resolveStuff();
/*
The primary tree is built and all the stuff that needed
@@ -576,17 +571,21 @@ int main(int argc, char **argv)
if (qdocGlobals.singleExec())
qdocFiles = Config::loadMaster(qdocFiles.at(0));
- // Main loop (adapted, when needed, to handle single exec mode):
- if (Generator::singleExec())
- Generator::setQDocPass(Generator::Prepare);
- foreach (const QString &qf, qdocFiles) {
- qdocGlobals.dependModules().clear();
- processQdocconfFile(qf);
- }
if (Generator::singleExec()) {
+ // single qdoc process for prepare and generate phases
+ Generator::setQDocPass(Generator::Prepare);
+ foreach (const QString &qf, qdocFiles) {
+ qdocGlobals.dependModules().clear();
+ processQdocconfFile(qf);
+ }
Generator::setQDocPass(Generator::Generate);
- QDocDatabase* qdb = QDocDatabase::qdocDB();
- qdb->processForest();
+ QDocDatabase::qdocDB()->processForest();
+ foreach (const QString &qf, qdocFiles) {
+ qdocGlobals.dependModules().clear();
+ processQdocconfFile(qf);
+ }
+ } else {
+ // separate qdoc processes for prepare and generate phases
foreach (const QString &qf, qdocFiles) {
qdocGlobals.dependModules().clear();
processQdocconfFile(qf);
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index f80a7bac3..f80aaf699 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -65,6 +65,7 @@ void Node::initialize()
goals_.insert("typedef", Node::Typedef);
goals_.insert("typealias", Node::Typedef);
goals_.insert("function", Node::Function);
+ goals_.insert("proxy", Node::Proxy);
goals_.insert("property", Node::Property);
goals_.insert("variable", Node::Variable);
goals_.insert("group", Node::Group);
@@ -149,9 +150,9 @@ bool Node::nodeNameLessThan(const Node *n1, const Node *n2)
else if (f1->isConst() > f2->isConst())
return false;
- if (f1->signature(false) < f2->signature(false))
+ if (f1->signature(false, false) < f2->signature(false, false))
return true;
- else if (f1->signature(false) > f2->signature(false))
+ else if (f1->signature(false, false) > f2->signature(false, false))
return false;
}
@@ -199,34 +200,11 @@ void Node::clearPropertyGroupCount() { propertyGroupCount_ = 0; }
*/
/*!
- When this Node is destroyed, if it has a parent Node, it
- removes itself from the parent node's child list.
+ The destructor does nothing.
*/
Node::~Node()
{
- if (parent_)
- parent_->removeChild(this);
-
- if (relatesTo_)
- removeRelates();
-}
-
-/*!
- Removes this node from the aggregate's list of related
- nodes, or if this node has created a dummy "relates"
- aggregate, deletes it.
- */
-void Node::removeRelates()
-{
- if (!relatesTo_)
- return;
-
- if (relatesTo_->isDummyNode() && !relatesTo_->parent()) {
- delete relatesTo_;
- relatesTo_ = 0;
- } else {
- relatesTo_->removeRelated(this);
- }
+ // nothing.
}
/*!
@@ -340,8 +318,8 @@ Node::Node(NodeType type, Aggregate *parent, const QString& name)
pageType_((unsigned char) NoPageType),
status_((unsigned char) Active),
indexNodeFlag_(false),
+ relatedNonmember_(false),
parent_(parent),
- relatesTo_(0),
sharedCommentNode_(0),
name_(name)
{
@@ -432,6 +410,7 @@ Node::PageType Node::getPageType(Node::NodeType t)
case Node::JsModule:
case Node::Collection:
return Node::OverviewPage;
+ case Node::Proxy:
default:
return Node::NoPageType;
}
@@ -478,6 +457,7 @@ Node::Genus Node::getGenus(Node::NodeType t)
return Node::DOC;
case Node::Collection:
case Node::SharedComment:
+ case Node::Proxy:
default:
return Node::DontCare;
}
@@ -568,6 +548,8 @@ QString Node::nodeTypeString(unsigned char t)
return QLatin1String("function");
case Property:
return QLatin1String("property");
+ case Proxy:
+ return QLatin1String("proxy");
case Variable:
return QLatin1String("variable");
case Group:
@@ -661,29 +643,6 @@ bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
}
/*!
- Sets the pointer to the node that this node relates to.
- */
-void Node::setRelates(PageNode *pseudoParent)
-{
- if (pseudoParent == parent())
- return;
-
- removeRelates();
- relatesTo_ = pseudoParent;
- pseudoParent->addRelated(this);
-}
-
-/*!
- Sets the (unresolved) entity \a name that this node relates to.
- */
-void Node::setRelates(const QString& name)
-{
- removeRelates();
- // Create a dummy aggregate for writing the name into the index
- relatesTo_ = new DummyNode(0, name);
-}
-
-/*!
This function creates a pair that describes a link.
The pair is composed from \a link and \a desc. The
\a linkType is the map index the pair is filed under.
@@ -848,17 +807,20 @@ bool Node::isInternal() const
return true;
if (parent() && parent()->status() == Internal)
return true;
- if (relates() && relates()->status() == Internal)
- return true;
return false;
}
/*!
Returns a pointer to the root of the Tree this node is in.
*/
-const Node* Node::root() const
+Aggregate *Node::root() const
{
- return (parent() ? parent()->root() : this);
+ if (parent() == nullptr)
+ return (this->isAggregate() ? static_cast<Aggregate*>(const_cast<Node*>(this)) : nullptr);
+ Aggregate *t = parent();
+ while (t->parent() != nullptr)
+ t = t->parent();
+ return t;
}
/*!
@@ -906,17 +868,91 @@ bool Node::hasSharedDoc() const
}
/*!
+ Returns the CPP node's qualified name by prepending the
+ namespaces name + "::" if there isw a namespace.
+ */
+QString Node::qualifyCppName()
+{
+ if (parent_ && parent_->isNamespace() && !parent_->name().isEmpty())
+ return parent_->name() + "::" + name_;
+ return name_;
+}
+
+/*!
+ Return the name of this node qualified with the parent name
+ and "::" if there is a parent name.
+ */
+QString Node::qualifyWithParentName()
+{
+ if (parent_ && !parent_->name().isEmpty())
+ return parent_->name() + "::" + name_;
+ return name_;
+}
+
+
+/*!
+ Returns the QML node's qualified name by stripping off the
+ "QML:" if present and prepending the logical module name.
+ */
+QString Node::qualifyQmlName()
+{
+ QString qualifiedName = name_;
+ if (name_.startsWith(QLatin1String("QML:")))
+ qualifiedName = name_.mid(4);
+ qualifiedName = logicalModuleName() + "::" + name_;
+ return qualifiedName;
+}
+
+/*!
+ Returns the QML node's name after stripping off the
+ "QML:" if present.
+ */
+QString Node::unqualifyQmlName()
+{
+ QString qmlTypeName = name_.toLower();
+ if (qmlTypeName.startsWith(QLatin1String("qml:")))
+ qmlTypeName = qmlTypeName.mid(4);
+ return qmlTypeName;
+}
+
+/*!
\class Aggregate
*/
/*!
- The inner node destructor deletes the children and removes
- this node from its related nodes.
+ Calls delete for each child of this Aggregate that has this
+ Aggregate as its parent. A child node that has some other
+ Aggregate as its parent is deleted by that Aggregate's
+ destructor.
+
+ The destructor no longer deletes the collection of children
+ by calling qDeleteAll() because the child list can contain
+ pointers to children that have some other Aggregate as their
+ parent. This is because of how the \e{\\relates} command is
+ processed. An Aggregate can have a pointer to, for example,
+ a FunctionNode in its child list, but that FunctionNode has
+ a differen Aggregate as its parent because a \e{\\relates}
+ command was used to relate it to that parent. In that case,
+ the other Aggregate's destructor must delete that node.
+
+ \note This function is the \b only place where delete is
+ called to delete any subclass of Node.
+
+ \note This strategy depends on the node tree being destroyed
+ by calling delete on the root node of the tree. This happens
+ in the destructor of class Tree.
*/
Aggregate::~Aggregate()
{
- removeFromRelated();
- deleteChildren();
+ enumChildren_.clear();
+ nonfunctionMap_.clear();
+ functionMap_.clear();
+ for (int i = 0; i < children_.size(); ++i) {
+ if ((children_[i] != nullptr) && (children_[i]->parent() == this))
+ delete children_[i];
+ children_[i] = 0;
+ }
+ children_.clear();
}
/*!
@@ -932,7 +968,7 @@ Aggregate::~Aggregate()
Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findFlags) const
{
if (genus == Node::DontCare) {
- Node *node = childMap_.value(name);
+ Node *node = nonfunctionMap_.value(name);
if (node && !node->isQmlPropertyGroup()) // mws asks: Why not property group?
return node;
if (isQmlType() || isJsType()) {
@@ -946,7 +982,7 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF
}
}
} else {
- NodeList nodes = childMap_.values(name);
+ NodeList nodes = nonfunctionMap_.values(name);
if (!nodes.isEmpty()) {
for (int i = 0; i < nodes.size(); ++i) {
Node* node = nodes.at(i);
@@ -969,37 +1005,54 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF
}
if (genus != Node::DontCare && this->genus() != genus)
return nullptr;
- return primaryFunctionMap_.value(name);
+ return functionMap_.value(name);
}
/*!
Find all the child nodes of this node that are named
\a name and return them in \a nodes.
*/
-void Aggregate::findChildren(const QString& name, NodeList& nodes) const
-{
- nodes = childMap_.values(name);
- Node* n = primaryFunctionMap_.value(name);
- if (n) {
- nodes.append(n);
- NodeList t = secondaryFunctionMap_.value(name);
- if (!t.isEmpty())
- nodes.append(t);
+void Aggregate::findChildren(const QString &name, NodeVector &nodes) const
+{
+ nodes.clear();
+ int nonfunctionCount = nonfunctionMap_.count(name);
+ FunctionMap::const_iterator i = functionMap_.find(name);
+ if (i != functionMap_.end()) {
+ int functionCount = 0;
+ FunctionNode *fn = i.value();
+ while (fn != nullptr) {
+ ++functionCount;
+ fn = fn->nextOverload();
+ }
+ nodes.reserve(nonfunctionCount + functionCount);
+ fn = i.value();
+ while (fn != nullptr) {
+ nodes.append(fn);
+ fn = fn->nextOverload();
+ }
+ } else {
+ nodes.reserve(nonfunctionCount);
}
- if (!nodes.isEmpty() || !(isQmlNode() || isJsNode()))
- return;
- int i = name.indexOf(QChar('.'));
- if (i < 0)
- return;
- QString qmlPropGroup = name.left(i);
- NodeList t = childMap_.values(qmlPropGroup);
- if (t.isEmpty())
- return;
- foreach (Node* n, t) {
- if (n->isQmlPropertyGroup() || n->isJsPropertyGroup()) {
- n->findChildren(name, nodes);
- if (!nodes.isEmpty())
- break;
+ if (nonfunctionCount > 0) {
+ NodeMap::const_iterator i = nonfunctionMap_.find(name);
+ while (i != nonfunctionMap_.end() && i.key() == name) {
+ nodes.append(i.value());
+ ++i;
+ }
+ }
+ if (nodes.isEmpty() && (isQmlNode() || isJsNode())) {
+ int idx = name.indexOf(QChar('.'));
+ if (idx < 0)
+ return;
+ QString qmlPropGroup = name.left(idx);
+ NodeMap::const_iterator i = nonfunctionMap_.find(qmlPropGroup);
+ while (i != nonfunctionMap_.end() && i.key() == qmlPropGroup) {
+ if (i.value()->isQmlPropertyGroup() || i.value()->isJsPropertyGroup()) {
+ static_cast<Aggregate*>(i.value())->findChildren(name, nodes);
+ if (!nodes.isEmpty())
+ return;
+ }
+ ++i;
}
}
}
@@ -1012,136 +1065,74 @@ void Aggregate::findChildren(const QString& name, NodeList& nodes) const
Node* Aggregate::findChildNode(const QString& name, NodeType type)
{
if (type == Function)
- return primaryFunctionMap_.value(name);
- else {
- NodeList nodes = childMap_.values(name);
- for (int i=0; i<nodes.size(); ++i) {
- Node* node = nodes.at(i);
- if (node->nodeType() == type)
- return node;
- }
+ return functionMap_.value(name);
+ NodeList nodes = nonfunctionMap_.values(name);
+ for (int i=0; i<nodes.size(); ++i) {
+ Node *node = nodes.at(i);
+ if (node->nodeType() == type)
+ return node;
}
- return 0;
+ return nullptr;
}
/*!
- Find a function node that is a child of this nose, such
- that the function node has the specified \a name.
+ Find a function node that is a child of this node, such that
+ the function node has the specified \a name and \a parameters.
+ If \a parameters is empty but no matching function is found
+ that has no parameters, return the primary function whether
+ it has parameters or not.
*/
-FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const
+FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters &parameters)
{
- FunctionNode* pfn = static_cast<FunctionNode*>(primaryFunctionMap_.value(name));
- FunctionNode* fn = pfn;
- if (fn) {
- const QVector<Parameter>* funcParams = &(fn->parameters());
- if (params.isEmpty() && funcParams->isEmpty() && !fn->isInternal())
- return fn;
- bool isQPrivateSignal = false; // Not used in the search
- QVector<Parameter> testParams;
- if (!params.isEmpty()) {
- CppCodeParser* cppParser = PureDocParser::pureDocParser();
- cppParser->parseParameters(params, testParams, isQPrivateSignal);
- }
- NodeList funcs = secondaryFunctionMap_.value(name);
- int i = -1;
- while (fn) {
- if (testParams.size() == funcParams->size()) {
- if (testParams.isEmpty() && !fn->isInternal())
- return fn;
- bool different = false;
- for (int j=0; j<testParams.size(); j++) {
- if (testParams.at(j).dataType() != funcParams->at(j).dataType()) {
- different = true;
- break;
- }
+ FunctionMap::iterator i = functionMap_.find(name);
+ if (i == functionMap_.end())
+ return nullptr;
+ FunctionNode *fn = i.value();
+
+ if (parameters.isEmpty() && fn->parameters().isEmpty() && !fn->isInternal())
+ return fn;
+
+ while (fn != nullptr) {
+ if (parameters.count() == fn->parameters().count() && !fn->isInternal()) {
+ if (parameters.isEmpty())
+ return fn;
+ bool matched = true;
+ for (int i = 0; i < parameters.count(); i++) {
+ if (parameters.at(i).type() != fn->parameters().at(i).type()) {
+ matched = false;
+ break;
}
- if (!different && !fn->isInternal())
- return fn;
- }
- if (++i < funcs.size()) {
- fn = static_cast<FunctionNode*>(funcs.at(i));
- funcParams = &(fn->parameters());
- }
- else
- fn = 0;
- }
- /*
- Most \l commands that link to functions don't include
- the parameter declarations in the function signature,
- so if the \l is meant to go to a function that does
- have parameters, the algorithm above won't find it.
- Therefore we must return the pointer to the function
- in the primary function map in the cases where the
- parameters should have been specified in the \l command.
- But if the primary function is marked internal, search
- the secondary list to find one that is not marked internal.
- */
- if (!fn) {
- if (!testParams.empty())
- return 0;
- if (pfn && !pfn->isInternal())
- return pfn;
- foreach (Node* n, funcs) {
- fn = static_cast<FunctionNode*>(n);
- if (!fn->isInternal())
- return fn;
}
+ if (matched)
+ return fn;
}
+ fn = fn->nextOverload();
}
- return fn;
+ return parameters.isEmpty() ? i.value() : nullptr;
}
/*!
Find the function node that is a child of this node, such
- that the function has the same name and signature as the
- \a clone node.
- */
-FunctionNode *Aggregate::findFunctionNode(const FunctionNode *clone) const
-{
- QMap<QString,Node*>::ConstIterator c = primaryFunctionMap_.constFind(clone->name());
- if (c != primaryFunctionMap_.constEnd()) {
- if (isSameSignature(clone, (FunctionNode *) *c)) {
- return (FunctionNode *) *c;
- }
- else if (secondaryFunctionMap_.contains(clone->name())) {
- const NodeList& secs = secondaryFunctionMap_[clone->name()];
- NodeList::ConstIterator s = secs.constBegin();
- while (s != secs.constEnd()) {
- if (isSameSignature(clone, (FunctionNode *) *s))
- return (FunctionNode *) *s;
- ++s;
- }
- }
- }
- return 0;
-}
-
-/*!
- Returns the list of keys from the primary function map.
+ that the function described has the same name and signature
+ as the function described by the \a clone node.
*/
-QStringList Aggregate::primaryKeys()
+FunctionNode *Aggregate::findFunctionChild(const FunctionNode *clone)
{
- QStringList t;
- QMap<QString, Node*>::iterator i = primaryFunctionMap_.begin();
- while (i != primaryFunctionMap_.end()) {
- t.append(i.key());
- ++i;
+ FunctionNode *fn = functionMap_.value(clone->name());
+ while (fn != nullptr) {
+ if (isSameSignature(clone, fn))
+ return fn;
+ fn = fn->nextOverload();
}
- return t;
+ return nullptr;
}
/*!
- Returns the list of keys from the secondary function map.
+ Returns the list of keys from the primary function map.
*/
-QStringList Aggregate::secondaryKeys()
+QStringList Aggregate::primaryKeys()
{
- QStringList t;
- QMap<QString, NodeList>::iterator i = secondaryFunctionMap_.begin();
- while (i != secondaryFunctionMap_.end()) {
- t.append(i.key());
- ++i;
- }
- return t;
+ return functionMap_.keys();
}
/*!
@@ -1149,13 +1140,28 @@ QStringList Aggregate::secondaryKeys()
private access and internal status. qdoc will then ignore
them for documentation purposes.
*/
-void Aggregate::makeUndocumentedChildrenInternal()
+void Aggregate::markUndocumentedChildrenInternal()
{
- foreach (Node *child, childNodes()) {
+ // Property group children have no doc of their own but follow the
+ // the access/status of their parent
+ if (this->isQmlPropertyGroup() || this->isJsPropertyGroup())
+ return;
+
+ foreach (Node *child, children_) {
if (!child->isSharingComment() && !child->hasDoc() && !child->docMustBeGenerated()) {
+ if (child->isFunction()) {
+ if (static_cast<FunctionNode*>(child)->hasAssociatedProperties())
+ continue;
+ } else if (child->isTypedef()) {
+ if (static_cast<TypedefNode*>(child)->hasAssociatedEnum())
+ continue;
+ }
child->setAccess(Node::Private);
child->setStatus(Node::Internal);
}
+ if (child->isAggregate()) {
+ static_cast<Aggregate*>(child)->markUndocumentedChildrenInternal();
+ }
}
}
@@ -1166,97 +1172,50 @@ void Aggregate::makeUndocumentedChildrenInternal()
*/
void Aggregate::normalizeOverloads()
{
- QMap<QString, Node *>::Iterator p1 = primaryFunctionMap_.begin();
- while (p1 != primaryFunctionMap_.end()) {
- FunctionNode *primaryFunc = (FunctionNode *) *p1;
- if (primaryFunc->status() != Active || primaryFunc->access() == Private) {
- if (secondaryFunctionMap_.contains(primaryFunc->name())) {
- /*
- Either the primary function is not active or it is private.
- It therefore can't be the primary function. Search the list
- of overloads to find one that can be the primary function.
- */
- NodeList& overloads = secondaryFunctionMap_[primaryFunc->name()];
- NodeList::ConstIterator s = overloads.constBegin();
- while (s != overloads.constEnd()) {
- FunctionNode *overloadFunc = (FunctionNode *) *s;
- /*
- Any non-obsolete, non-private function (i.e., visible function)
- is preferable to the current primary function. Swap the primary
- and overload functions.
- */
- if (overloadFunc->status() == Active && overloadFunc->access() != Private) {
- primaryFunc->setOverloadNumber(overloadFunc->overloadNumber());
- overloads.replace(overloads.indexOf(overloadFunc), primaryFunc);
- *p1 = overloadFunc;
- overloadFunc->setOverloadFlag(false);
- overloadFunc->setOverloadNumber(0);
- break;
- }
- ++s;
- }
- }
- }
- ++p1;
- }
/*
- Ensure that none of the primary functions is marked with \overload.
- */
- QMap<QString, Node *>::Iterator p = primaryFunctionMap_.begin();
- while (p != primaryFunctionMap_.end()) {
- FunctionNode *primaryFunc = (FunctionNode *) *p;
- if (primaryFunc->isOverload()) {
- if (secondaryFunctionMap_.contains(primaryFunc->name())) {
- /*
- The primary function is marked with \overload. Find an
- overload in the secondary function map that is not marked
- with \overload but that is active and not private. Then
- swap it with the primary function.
- */
- NodeList& overloads = secondaryFunctionMap_[primaryFunc->name()];
- NodeList::ConstIterator s = overloads.constBegin();
- while (s != overloads.constEnd()) {
- FunctionNode *overloadFunc = (FunctionNode *) *s;
- if (!overloadFunc->isOverload()) {
- if (overloadFunc->status() == Active && overloadFunc->access() != Private) {
- primaryFunc->setOverloadNumber(overloadFunc->overloadNumber());
- overloads.replace(overloads.indexOf(overloadFunc), primaryFunc);
- *p = overloadFunc;
- overloadFunc->setOverloadFlag(false);
- overloadFunc->setOverloadNumber(0);
- break;
- }
- }
- ++s;
- }
+ Ensure that none of the primary functions is inactive, private,
+ or marked \e {overload}.
+ */
+ FunctionMap::Iterator i = functionMap_.begin();
+ while (i != functionMap_.end()) {
+ FunctionNode *fn = i.value();
+ if (fn->isOverload()) {
+ FunctionNode *primary = fn->findPrimaryFunction();
+ if (primary) {
+ primary->setNextOverload(fn);
+ i.value() = primary;
+ fn = primary;
+ } else {
+ fn->clearOverloadFlag();
}
}
- ++p;
+ int count = 0;
+ fn->setOverloadNumber(0);
+ fn = fn->nextOverload();
+ while (fn != nullptr) {
+ fn->setOverloadNumber(++count);
+ fn = fn->nextOverload();
+ }
+ ++i; // process next function in function map.
}
/*
Recursive part.
*/
- NodeList::ConstIterator c = childNodes().constBegin();
- while (c != childNodes().constEnd()) {
- if ((*c)->isAggregate())
- ((Aggregate *) *c)->normalizeOverloads();
- ++c;
+ foreach (Node *n, children_) {
+ if (n->isAggregate())
+ static_cast<Aggregate*>(n)->normalizeOverloads();
}
}
/*!
- Deletes all this node's children.
+ Returns a const reference to the list of child nodes of this
+ aggregate that are not function nodes.
*/
-void Aggregate::deleteChildren()
+const NodeList &Aggregate::nonfunctionList()
{
- NodeList childrenCopy = children_;
- // Clear internal collections before deleting child nodes
- children_.clear();
- childMap_.clear();
- enumChildren_.clear();
- primaryFunctionMap_.clear();
- secondaryFunctionMap_.clear();
- qDeleteAll(childrenCopy);
+ if (nonfunctionList_.isEmpty() || (nonfunctionList_.size() != nonfunctionMap_.size()))
+ nonfunctionList_ = nonfunctionMap_.values();
+ return nonfunctionList_;
}
/*! \fn bool Aggregate::isAggregate() const
@@ -1290,34 +1249,19 @@ const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
}
/*!
- Returns a node list containing all the member functions of
- some class such that the functions overload the name \a funcName.
+ Appends \a includeFile file to the list of include files.
*/
-NodeList Aggregate::overloads(const QString &funcName) const
+void Aggregate::addIncludeFile(const QString &includeFile)
{
- NodeList result;
- Node *primary = primaryFunctionMap_.value(funcName);
- if (primary) {
- result << primary;
- result += secondaryFunctionMap_[funcName];
- }
- return result;
+ includeFiles_.append(includeFile);
}
/*!
- Appends an \a include file to the list of include files.
+ Sets the list of include files to \a includeFiles.
*/
-void Aggregate::addInclude(const QString& include)
+void Aggregate::setIncludeFiles(const QStringList &includeFiles)
{
- includes_.append(include);
-}
-
-/*!
- Sets the list of include files to \a includes.
- */
-void Aggregate::setIncludes(const QStringList& includes)
-{
- includes_ = includes;
+ includeFiles_ = includeFiles;
}
/*!
@@ -1325,7 +1269,7 @@ void Aggregate::setIncludes(const QStringList& includes)
*/
bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
{
- if (f1->parameters().size() != f2->parameters().size())
+ if (f1->parameters().count() != f2->parameters().count())
return false;
if (f1->isConst() != f2->isConst())
return false;
@@ -1334,12 +1278,12 @@ bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
if (f1->isRefRef() != f2->isRefRef())
return false;
- QVector<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
- QVector<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
- while (p2 != f2->parameters().constEnd()) {
- if ((*p1).hasType() && (*p2).hasType()) {
- QString t1 = p1->dataType();
- QString t2 = p2->dataType();
+ const Parameters &p1 = f1->parameters();
+ const Parameters &p2 = f2->parameters();
+ for (int i = 0; i < p1.count(); i++) {
+ if (p1.at(i).hasType() && p2.at(i).hasType()) {
+ QString t1 = p1.at(i).type();
+ QString t2 = p2.at(i).type();
if (t1.length() < t2.length())
qSwap(t1, t2);
@@ -1360,44 +1304,60 @@ bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
return false;
}
}
- ++p1;
- ++p2;
}
return true;
}
/*!
- Adds the \a child to this node's child list. It might also
- be necessary to update this node's internal collections and
- the child's parent pointer and output subdirectory.
+ This function is only called by addChild(), when the child is a
+ FunctionNode. If the function map does not contain a function with
+ the name in \a fn, \a fn is inserted into the function map. If the
+ map already contains a function by that name, \a fn is appended to
+ that function's linked list of overloads.
+
+ \note A function's overloads appear in the linked list in the same
+ order they were created. The first overload in the list is the first
+ overload created. This order is maintained in the numbering of
+ overloads. In other words, the first overload in the linked list has
+ overload number 1, and the last overload in the list has overload
+ number n, where n is the number of overloads not including the
+ function in the function map.
+
+ \not Adding a function increments the aggregate's function count,
+ which is the total number of function nodes in the function map,
+ including the overloads. The overloads are not inserted into the map
+ but are in a linked list using the FunctionNode's nextOverload_
+ pointer.
+
+ \note The function's overload number and overload flag are set in
+ normalizeOverloads().
+
+ \sa normalizeOverloads()
*/
-void Aggregate::addChild(Node *child)
+void Aggregate::addFunction(FunctionNode *fn)
{
- children_.append(child);
- if (child->isFunction()) {
- FunctionNode *func = static_cast<FunctionNode*>(child);
- QString name = func->name();
- if (!primaryFunctionMap_.contains(name)) {
- primaryFunctionMap_.insert(name, func);
- func->setOverloadNumber(0);
- }
- else {
- NodeList &overloads = secondaryFunctionMap_[name];
- overloads.append(func);
- func->setOverloadNumber(overloads.size());
- }
- }
- else {
- if (child->isEnumType())
- enumChildren_.append(child);
- childMap_.insertMulti(child->name(), child);
- }
- if (child->parent() == 0) {
- child->setParent(this);
- child->setOutputSubdirectory(this->outputSubdirectory());
- child->setUrl(QString());
- child->setIndexNodeFlag(isIndexNode());
- }
+ FunctionMap::iterator i = functionMap_.find(fn->name());
+ if (i == functionMap_.end())
+ functionMap_.insert(fn->name(), fn);
+ else
+ i.value()->appendOverload(fn);
+ functionCount_++;
+}
+
+/*!
+ When an Aggregate adopts a function that is a child of
+ another Aggregate, the function is inserted into this
+ Aggregate's function map, if the function's name is not
+ already in the function map. If the function's name is
+ already in the function map, do nothing. The overload
+ link is already set correctly.
+ */
+void Aggregate::adoptFunction(FunctionNode *fn)
+{
+ FunctionMap::iterator i = functionMap_.find(fn->name());
+ if (i == functionMap_.end())
+ functionMap_.insert(fn->name(), fn);
+ functionCount_++;
}
/*!
@@ -1408,52 +1368,74 @@ void Aggregate::addChild(Node *child)
*/
void Aggregate::addChildByTitle(Node* child, const QString& title)
{
- childMap_.insertMulti(title, child);
+ nonfunctionMap_.insertMulti(title, child);
}
/*!
- The \a child is removed from this node's child list and
- from this node's internal collections. The child's parent
- pointer is set to 0, but its output subdirectory is not
- changed.
+ Adds the \a child to this node's child list and sets the child's
+ parent pointer to this Aggregate. It then mounts the child with
+ mountChild().
+
+ The \a child is then added to this Aggregate's searchable maps
+ and lists.
+
+ \note This function does not test the child's parent pointer
+ for null before changing it. If the child's parent pointer
+ is not null, then it is being reparented. The child becomes
+ a child of this Aggregate, but it also remains a child of
+ the Aggregate that is it's old parent. But the child will
+ only have one parent, and it will be this Aggregate. The is
+ because of the \c relates command.
+
+ \sa mountChild(), dismountChild()
*/
-void Aggregate::removeChild(Node *child)
+void Aggregate::addChild(Node *child)
{
- children_.removeAll(child);
- enumChildren_.removeAll(child);
+ children_.append(child);
+ child->setParent(this);
+ child->setOutputSubdirectory(this->outputSubdirectory());
+ child->setUrl(QString());
+ child->setIndexNodeFlag(isIndexNode());
if (child->isFunction()) {
- QMap<QString, Node *>::Iterator primary = primaryFunctionMap_.find(child->name());
- NodeList& overloads = secondaryFunctionMap_[child->name()];
- if (primary != primaryFunctionMap_.end() && *primary == child) {
- primaryFunctionMap_.erase(primary);
- if (!overloads.isEmpty()) {
- FunctionNode* fn = static_cast<FunctionNode*>(overloads.takeFirst());
- fn->setOverloadNumber(0);
- primaryFunctionMap_.insert(child->name(), fn);
- }
- }
- else
- overloads.removeAll(child);
+ addFunction(static_cast<FunctionNode*>(child));
}
- QMap<QString, Node *>::Iterator ent = childMap_.find(child->name());
- while (ent != childMap_.end() && ent.key() == child->name()) {
- if (*ent == child) {
- childMap_.erase(ent);
- break;
- }
- ++ent;
+ else {
+ nonfunctionMap_.insertMulti(child->name(), child);
+ if (child->isEnumType())
+ enumChildren_.append(child);
}
- if (child->title().isEmpty())
- return;
- ent = childMap_.find(child->title());
- while (ent != childMap_.end() && ent.key() == child->title()) {
- if (*ent == child) {
- childMap_.erase(ent);
- break;
+}
+
+/*!
+ This Aggregate becomes the adoptive parent of \a child. The
+ \a child knows this Aggregate as its parent, but its former
+ parent continues to have pointers to the child in its child
+ list and in its searchable data structures. But the child is
+ also added to the child list and searchable data structures
+ of this Aggregate.
+
+ The one caveat is that if the child being adopted is a function
+ node, it's next overload pointer is not altered.
+ */
+void Aggregate::adoptChild(Node *child)
+{
+ if (child->parent() != this) {
+ children_.append(child);
+ child->setParent(this);
+ if (child->isFunction()) {
+ adoptFunction(static_cast<FunctionNode*>(child));
+ }
+ else {
+ nonfunctionMap_.insertMulti(child->name(), child);
+ if (child->isEnumType()) {
+ enumChildren_.append(child);
+ } else if (child->isSharedCommentNode()) {
+ SharedCommentNode *scn = static_cast<SharedCommentNode*>(child);
+ for (Node *n : scn->collective())
+ adoptChild(n);
+ }
}
- ++ent;
}
- child->setParent(0);
}
/*!
@@ -1462,8 +1444,8 @@ void Aggregate::removeChild(Node *child)
void Aggregate::setOutputSubdirectory(const QString &t)
{
Node::setOutputSubdirectory(t);
- for (int i = 0; i < childNodes().size(); ++i)
- childNodes().at(i)->setOutputSubdirectory(t);
+ foreach (Node *n, children_)
+ n->setOutputSubdirectory(t);
}
/*!
@@ -1532,7 +1514,7 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n) const
goal1 = Node::JsProperty;
goal2 = Node::JsPropertyGroup;
}
- foreach (Node* child, childNodes()) {
+ foreach (Node *child, children_) {
if (child->nodeType() == goal1) {
if (child->name() == n)
return static_cast<QmlPropertyNode*>(child);
@@ -1558,7 +1540,7 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
goal1 = Node::JsProperty;
goal2 = Node::JsPropertyGroup;
}
- foreach (Node* child, childNodes()) {
+ foreach (Node *child, children_) {
if (child->nodeType() == goal1) {
if (child->name() == n && child->isAttached() == attached)
return static_cast<QmlPropertyNode*>(child);
@@ -1572,6 +1554,28 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
}
/*!
+ The FunctionNode \a fn is assumed to be a member function
+ of this Aggregate. The function's name is looked up in the
+ Aggregate's function map. It should be found because it is
+ assumed that \a fn is in this Aggregate's function map. But
+ in case it is not found, \c false is returned.
+
+ Normally, the name will be found in the function map, and
+ the value of the iterator is used to get the value, which
+ is a pointer to another FunctionNode, which is not itself
+ an overload. If that function has a non-null overload
+ pointer, true is returned. Otherwise false is returned.
+
+ This is a convenience function that you should not need to
+ use.
+ */
+bool Aggregate::hasOverloads(const FunctionNode *fn) const
+{
+ FunctionMap::const_iterator i = functionMap_.find(fn->name());
+ return (i == functionMap_.end() ? false : (i.value()->nextOverload() != nullptr));
+}
+
+/*!
\class NamespaceNode
\brief This class represents a C++ namespace.
@@ -1581,6 +1585,18 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
*/
/*!
+ If this is the global namespace node, remove all orphans
+ from the child list before deleting anything.
+ */
+NamespaceNode::~NamespaceNode()
+{
+ for (int i = 0; i < children_.size(); ++i) {
+ if (children_[i]->parent() != this)
+ children_[i] = nullptr;
+ }
+}
+
+/*!
Returns true if this namespace is to be documented in the
current module. There can be elements declared in this
namespace spread over multiple modules. Those elements are
@@ -1599,7 +1615,7 @@ bool NamespaceNode::isDocumentedHere() const
*/
bool NamespaceNode::hasDocumentedChildren() const
{
- foreach (Node* n, childNodes()) {
+ foreach (Node *n, children_) {
if (n->hasDoc() && !n->isPrivate() && !n->isInternal())
return true;
}
@@ -1613,7 +1629,7 @@ bool NamespaceNode::hasDocumentedChildren() const
*/
void NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace() const
{
- foreach (Node* n, childNodes()) {
+ foreach (Node *n, children_) {
if (n->hasDoc() && !n->isPrivate() && !n->isInternal()) {
QString msg1 = n->name();
if (n->isFunction())
@@ -1638,6 +1654,31 @@ bool NamespaceNode::docMustBeGenerated() const
}
/*!
+ Returns a const reference to the namespace node's list of
+ included children, which contains pointers to all the child
+ nodes of other namespace nodes that have the same name as
+ this namespace node. The list is built after the prepare
+ phase has been run but just before the generate phase. It
+ is buils by QDocDatabase::resolveNamespaces().
+
+ \sa QDocDatabase::resolveNamespaces()
+ */
+const NodeList &NamespaceNode::includedChildren() const
+{
+ return includedChildren_;
+}
+
+/*!
+ This function is only called from QDocDatabase::resolveNamesapces().
+
+ \sa includedChildren(), QDocDatabase::resolveNamespaces()
+ */
+void NamespaceNode::includeChild(Node *child)
+{
+ includedChildren_.append(child);
+}
+
+/*!
\class ClassNode
\brief This class represents a C++ class.
*/
@@ -1826,6 +1867,9 @@ QmlTypeNode* ClassNode::findQmlBaseNode()
\a fn overrides in this class's children or in one of this
class's base classes. Return a pointer to the overridden
function or return 0.
+
+ This should be revised because clang provides the path to the
+ overridden function. mws 15/12/2018
*/
FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
{
@@ -1837,7 +1881,7 @@ FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
bc->node_ = cn;
}
if (cn) {
- FunctionNode* result = cn->findFunctionNode(fn);
+ FunctionNode *result = cn->findFunctionChild(fn);
if (result && !result->isNonvirtual())
return result;
result = cn->findOverriddenFunction(fn);
@@ -1900,44 +1944,9 @@ bool PageNode::setTitle(const QString &title)
Sets the node's \a subtitle. Returns true;
*/
-/*!
- While there are related nodes, remove the first one. If it
- relates to this node (it should), clear that relationship.
- */
-void PageNode::removeFromRelated()
-{
- while (!related_.isEmpty()) {
- Node *p = static_cast<Node *>(related_.takeFirst());
- if (p != 0 && p->relates() == this) p->clearRelated();
- }
-}
-
-/*!
- Removes \a pseudoChild from the list of nodes related to
- this node. If \a pseudoChild is a function node, it is
- also remove from the primary/secondary function maps of
- this node, if this node is a subclass of PageNode
- that has function maps.
+/*! \f void Node::markInternal()
+ Sets the node's access to Private and its status to Internal.
*/
-void PageNode::removeRelated(Node *pseudoChild)
-{
- related_.removeAll(pseudoChild);
- removePseudoChild(pseudoChild);
-}
-
-/*!
- Adds \a pseudoChild to the list of nodes related to this
- node. Also adds \a pseudoChild to the primary/secondary
- function maps, if this PageNode is the base class of
- a subclass that has function maps. In that case, it also
- resolves a correct overload number for a related non-member
- function.
- */
-void PageNode::addRelated(Node *pseudoChild)
-{
- related_.append(pseudoChild);
- addPseudoChild(pseudoChild);
-}
/*!
\class EnumNode
@@ -1977,107 +1986,112 @@ QString EnumNode::itemValue(const QString &name) const
}
/*!
- \class TypedefNode
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-
-/*!
- */
-void TypedefNode::setAssociatedEnum(const EnumNode *enume)
+Node *EnumNode::clone(Aggregate *parent)
{
- associatedEnum_ = enume;
+ EnumNode *en = new EnumNode(*this); // shallow copy
+ en->setParent(nullptr);
+ parent->addChild(en);
+ return en;
}
/*!
- \class TypeAliasNode
- */
-
-/*!
- \class Parameter
- \brief The class Parameter contains one parameter.
-
- A parameter can be a function parameter or a macro
- parameter.
+ \class TypedefNode
*/
/*!
- Constructs this parameter from the \a dataType, the \a name,
- and the \a defaultValue.
*/
-Parameter::Parameter(const QString& dataType, const QString& name, const QString& defaultValue)
- : dataType_(dataType),
- name_(name),
- defaultValue_(defaultValue)
+void TypedefNode::setAssociatedEnum(const EnumNode *enume)
{
- // nothing.
+ associatedEnum_ = enume;
}
/*!
- Standard copy constructor copies \p.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-Parameter::Parameter(const Parameter& p)
- : dataType_(p.dataType_),
- name_(p.name_),
- defaultValue_(p.defaultValue_)
+Node *TypedefNode::clone(Aggregate *parent)
{
- // nothing.
+ TypedefNode *tn = new TypedefNode(*this); // shallow copy
+ tn->setParent(nullptr);
+ parent->addChild(tn);
+ return tn;
}
/*!
- standard assignment operator assigns \p.
+ \class TypeAliasNode
*/
-Parameter& Parameter::operator=(const Parameter& p)
-{
- dataType_ = p.dataType_;
- name_ = p.name_;
- defaultValue_ = p.defaultValue_;
- return *this;
-}
/*!
- Reconstructs the text describing the parameter and
- returns it. If \a value is true, the default value
- will be included, if there is one.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-QString Parameter::reconstruct(bool value) const
+Node *TypeAliasNode::clone(Aggregate *parent)
{
- QString p = dataType_;
- if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
- p += QLatin1Char(' ');
- p += name_;
- if (value && !defaultValue_.isEmpty())
- p += " = " + defaultValue_;
- return p;
+ TypeAliasNode *tan = new TypeAliasNode(*this); // shallow copy
+ tan->setParent(nullptr);
+ parent->addChild(tan);
+ return tan;
}
/*!
\class FunctionNode
+
+ This node is used to represent any kind of function being
+ documented. It can represent a C++ class member function,
+ a C++ global function, a QML method, a javascript method,
+ or a macro, with or without parameters.
+
+ A C++ function can be a signal a slot, a constructor of any
+ kind, a destructor, a copy or move assignment operator, or
+ just a plain old member function or global function.
+
+ A QML or javascript method can be a plain old method, or a
+ signal or signal handler.
+
+ If the function is not an overload, its overload flag is
+ false. If it is an overload, its overload flag is true.
+ If it is not an overload but it has overloads, its next
+ overload pointer will point to an overload function. If it
+ is an overload function, its overload flag is true, and it
+ may or may not have a non-null next overload pointer.
+
+ So all the overloads of a function are in a linked list
+ using the next overload pointer. If a function has no
+ overloads, its overload flag is false and its overload
+ pointer is null.
+
+ The function node also has an overload number. If the
+ node's overload flag is set, this overload number is
+ positive; otherwise, the overload number is 0.
*/
/*!
Construct a function node for a C++ function. It's parent
is \a parent, and it's name is \a name.
- Do not set overloadNumber_ in the initializer list because it
- is set by addChild() in the Node base class.
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
*/
FunctionNode::FunctionNode(Aggregate *parent, const QString& name)
: Node(Function, parent, name),
- metaness_(Plain),
- virtualness_(NonVirtual),
const_(false),
static_(false),
- reimplemented_(false),
+ reimpFlag_(false),
attached_(false),
- privateSignal_(false),
- overload_(false),
- isDeleted_(false),
- isDefaulted_(false),
+ overloadFlag_(false),
isFinal_(false),
isOverride_(false),
- isImplicit_(false),
isRef_(false),
isRefRef_(false),
- isInvokable_(false)
+ isInvokable_(false),
+ metaness_(Plain),
+ virtualness_(NonVirtual),
+ overloadNumber_(0),
+ nextOverload_(nullptr)
{
// nothing
}
@@ -2088,27 +2102,26 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString& name)
it's name is \a name. If \a attached is true, it is an attached
method or signal.
- Do not set overloadNumber_ in the initializer list because it
- is set by addChild() in the Node base class.
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
*/
FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString& name, bool attached)
: Node(Function, parent, name),
- metaness_(kind),
- virtualness_(NonVirtual),
const_(false),
static_(false),
- reimplemented_(false),
+ reimpFlag_(false),
attached_(attached),
- privateSignal_(false),
- overload_(false),
- isDeleted_(false),
- isDefaulted_(false),
+ overloadFlag_(false),
isFinal_(false),
isOverride_(false),
- isImplicit_(false),
isRef_(false),
isRefRef_(false),
- isInvokable_(false)
+ isInvokable_(false),
+ metaness_(kind),
+ virtualness_(NonVirtual),
+ overloadNumber_(0),
+ nextOverload_(nullptr)
{
setGenus(getGenus(metaness_));
if (!isCppNode() && name.startsWith("__"))
@@ -2116,6 +2129,19 @@ FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString& name
}
/*!
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
+ */
+Node *FunctionNode::clone(Aggregate *parent)
+{
+ FunctionNode *fn = new FunctionNode(*this); // shallow copy
+ fn->setParent(nullptr);
+ fn->setNextOverload(nullptr);
+ parent->addChild(fn);
+ return fn;
+}
+
+/*!
Returns this function's virtualness value as a string
for use as an attribute value in index files.
*/
@@ -2298,29 +2324,71 @@ bool FunctionNode::changeMetaness(Metaness from, Metaness to)
return false;
}
-/*! \fn void FunctionNode::setOverloadFlag(bool b)
- Sets this function node's overload flag to \a b.
- It does not set the overload number.
+/*! \fn void FunctionNode::setOverloadNumber(unsigned char n)
+ Sets the function node's overload number to \a n. If \a n
+ is 0, the function node's overload flag is set to false. If
+ \a n is greater than 0, the overload flag is set to true.
*/
+void FunctionNode::setOverloadNumber(signed short n)
+{
+ overloadNumber_ = n;
+ overloadFlag_ = (n > 0) ? true : false;
+}
-/*! \fn void FunctionNode::setOverloadNumber(unsigned char n)
- Sets this function node's overload number to \a n.
- It does not set the overload flag.
+/*!
+ If this function's next overload pointer is null, set it to
+ \a fn. Otherwise continue down the overload list by calling
+ this function recursively for the next overload.
+
+ Although this function appends an overload function to the list of
+ overloads for this function's name, it does not set the function's
+ overload number or it's overload flag. If the function has the
+ \c{\\overload} in its qdoc comment, that will set the overload
+ flag. But qdoc treats the \c{\\overload} command as a hint that the
+ function should be documented as an overload. The hint is almost
+ always correct, but qdoc reserves the right to decide which function
+ should be the primary function and which functions are the overloads.
+ These decisions are made in Aggregate::normalizeOverloads().
*/
+void FunctionNode::appendOverload(FunctionNode *fn)
+{
+ if (nextOverload_ == nullptr)
+ nextOverload_ = fn;
+ else
+ nextOverload_->appendOverload(fn);
+}
/*!
- Sets the function node's reimplementation flag to \a b.
- When \a b is true, it is supposed to mean that this function
- is a reimplementation of a virtual function in a base class,
- but it really just means the \e {\\reimp} command was seen in
- the qdoc comment.
+ This function assumes that this FunctionNode is marked as an
+ overlaod function. It asks if the next overload is marked as
+ an overload. If not, then remove that FunctionNode from the
+ overload list and return it. Otherwise call this function
+ recursively for the next overload.
*/
-void FunctionNode::setReimplemented(bool b)
+FunctionNode *FunctionNode::findPrimaryFunction()
{
- reimplemented_ = b;
+ if (nextOverload_ != nullptr) {
+ if (!nextOverload_->isOverload()) {
+ FunctionNode *t = nextOverload_;
+ nextOverload_ = t->nextOverload();
+ t->setNextOverload(nullptr);
+ return t;
+ }
+ return nextOverload_->findPrimaryFunction();
+ }
+ return nullptr;
}
/*!
+ \fn void FunctionNode::setReimpFlag()
+
+ Sets the function node's reimp flag to \c true, which means
+ the \e {\\reimp} command was used in the qdoc comment. It is
+ supposed to mean that the function reimplements a virtual
+ function in a base class.
+ */
+
+/*!
Returns a string representing the kind of function this
Function node represents, which depends on the Metaness
value.
@@ -2395,52 +2463,6 @@ QString FunctionNode::metanessString() const
}
/*!
- Append \a parameter to the parameter list.
- */
-void FunctionNode::addParameter(const Parameter& parameter)
-{
- parameters_.append(parameter);
-}
-
-/*!
- Split the parameters \a t and store them in this function's
- Parameter vector.
- */
-void FunctionNode::setParameters(const QString &t)
-{
- clearParams();
- if (!t.isEmpty()) {
- QStringList commaSplit = t.split(',');
- foreach (QString s, commaSplit) {
- QStringList blankSplit = s.split(' ');
- QString pName = blankSplit.last();
- blankSplit.removeLast();
- QString pType = blankSplit.join(' ');
- int i = 0;
- while (i < pName.length() && !pName.at(i).isLetter())
- i++;
- if (i > 0) {
- pType += QChar(' ') + pName.left(i);
- pName = pName.mid(i);
- }
- addParameter(Parameter(pType, pName));
- }
- }
-}
-
-void FunctionNode::borrowParameterNames(const FunctionNode *source)
-{
- QVector<Parameter>::Iterator t = parameters_.begin();
- QVector<Parameter>::ConstIterator s = source->parameters_.constBegin();
- while (s != source->parameters_.constEnd() && t != parameters_.end()) {
- if (!(*s).name().isEmpty())
- (*t).setName((*s).name());
- ++s;
- ++t;
- }
-}
-
-/*!
Adds the "associated" property \a p to this function node.
The function might be the setter or getter for a property,
for example.
@@ -2459,7 +2481,7 @@ bool FunctionNode::hasActiveAssociatedProperty() const
{
if (associatedProperties_.isEmpty())
return false;
- foreach (const PropertyNode* p, associatedProperties_) {
+ foreach (const Node *p, associatedProperties_) {
if (!p->isObsolete())
return true;
}
@@ -2471,87 +2493,28 @@ bool FunctionNode::hasActiveAssociatedProperty() const
*/
/*!
- Returns the list of parameter names.
- */
-QStringList FunctionNode::parameterNames() const
-{
- QStringList names;
- QVector<Parameter>::ConstIterator p = parameters().constBegin();
- while (p != parameters().constEnd()) {
- names << (*p).name();
- ++p;
- }
- return names;
-}
-
-/*!
- Returns a raw list of parameters. If \a names is true, the
- names are included. If \a values is true, the default values
- are included, if any are present.
- */
-QString FunctionNode::rawParameters(bool names, bool values) const
-{
- QString raw;
- foreach (const Parameter &parameter, parameters()) {
- raw += parameter.dataType();
- if (names)
- raw += parameter.name();
- if (values)
- raw += parameter.defaultValue();
- }
- return raw;
-}
-
-/*!
- Returns the list of reconstructed parameters. If \a values
- is true, the default values are included, if any are present.
- */
-QStringList FunctionNode::reconstructParameters(bool values) const
-{
- QStringList reconstructedParameters;
- QVector<Parameter>::ConstIterator p = parameters().constBegin();
- while (p != parameters().constEnd()) {
- reconstructedParameters << (*p).reconstruct(values);
- ++p;
- }
- return reconstructedParameters;
-}
-
-/*!
Reconstructs and returns the function's signature. If \a values
is true, the default values of the parameters are included, if
present.
*/
QString FunctionNode::signature(bool values, bool noReturnType) const
{
- QString s;
+ QString result;
if (!noReturnType && !returnType().isEmpty())
- s = returnType() + QLatin1Char(' ');
- s += name();
+ result = returnType() + QLatin1Char(' ');
+ result += name();
if (!isMacroWithoutParams()) {
- s += QLatin1Char('(');
- QStringList reconstructedParameters = reconstructParameters(values);
- int p = reconstructedParameters.size();
- if (p > 0) {
- for (int i=0; i<p; i++) {
- s += reconstructedParameters[i];
- if (i < (p-1))
- s += ", ";
- }
- }
- s += QLatin1Char(')');
+ result += QLatin1Char('(') + parameters_.signature(values) + QLatin1Char(')');
if (isMacro())
- return s;
+ return result;
}
if (isConst())
- s += " const";
+ result += " const";
if (isRef())
- s += " &";
+ result += " &";
else if (isRefRef())
- s += " &&";
- if (isImplicit())
- s += " = default";
- return s;
+ result += " &&";
+ return result;
}
/*!
@@ -2568,6 +2531,18 @@ PropertyNode::FunctionRole PropertyNode::role(const FunctionNode* fn) const
}
/*!
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
+ */
+Node *VariableNode::clone(Aggregate *parent)
+{
+ VariableNode *vn = new VariableNode(*this); // shallow copy
+ vn->setParent(nullptr);
+ parent->addChild(vn);
+ return vn;
+}
+
+/*!
Print some debugging stuff.
*/
void FunctionNode::debug() const
@@ -2594,12 +2569,12 @@ bool FunctionNode::compare(const FunctionNode *fn) const
return false;
if (isAttached() != fn->isAttached())
return false;
- const QVector<Parameter>& p = fn->parameters();
- if (parameters().size() != p.size())
+ const Parameters &p = fn->parameters();
+ if (parameters_.count() != p.count())
return false;
if (!p.isEmpty()) {
- for (int i = 0; i < p.size(); ++i) {
- if (parameters()[i].dataType() != p[i].dataType())
+ for (int i = 0; i < p.count(); ++i) {
+ if (parameters_.at(i).type() != p.at(i).type())
return false;
}
}
@@ -2638,6 +2613,27 @@ bool FunctionNode::isIgnored() const
}
/*!
+ Returns true if this function has overloads. Otherwise false.
+ First, if this function node's overload pointer is not nullptr,
+ return true. Next, if this function node's overload flag is true
+ return true. Finally, if this function's parent Aggregate has a
+ function by the same name as this one in its function map and
+ that function has overloads, return true. Otherwise return false.
+
+ There is a failsafe way to test it under any circumstances.
+ */
+bool FunctionNode::hasOverloads() const
+{
+ if (nextOverload_ != nullptr)
+ return true;
+ if (overloadFlag_)
+ return true;
+ if (parent())
+ return parent()->hasOverloads(this);
+ return false;
+}
+
+/*!
\class PropertyNode
This class describes one instance of using the Q_PROPERTY macro.
@@ -2876,6 +2872,39 @@ QString QmlPropertyGroupNode::idNumber()
}
/*!
+ Marks each of the properties in the property group
+ Private and Internal.
+ */
+void QmlPropertyGroupNode::markInternal()
+{
+ Node::markInternal();
+ foreach (Node *n, children_)
+ n->markInternal();
+}
+
+/*!
+ Marks each of the properties in the property group
+ as the default. Probably wrong.
+ */
+void QmlPropertyGroupNode::markDefault()
+{
+ Node::markDefault();
+ foreach (Node *n, children_)
+ n->markDefault();
+}
+
+/*!
+ Marks each of the properties in the property group
+ with the read only \a flag.
+ */
+void QmlPropertyGroupNode::markReadOnly(bool flag)
+{
+ Node::markReadOnly(flag);
+ foreach (Node *n, children_)
+ n->markReadOnly(flag);
+}
+
+/*!
Constructor for the QML property node.
*/
QmlPropertyNode::QmlPropertyNode(Aggregate* parent,
@@ -3134,47 +3163,355 @@ void Aggregate::printChildren(const QString& title)
}
/*!
- Removes \a pseudoChild from this node's primary/secondary
- function maps.
+ Removes \a fn from this aggregate's function map. That's
+ all it does. If \a fn is in the function map index and it
+ has an overload, the value pointer in the function map
+ index is set to the the overload pointer. If the function
+ has no overload pointer, the function map entry is erased.
+
+ \note When removing a function node from the function map,
+ it is important to set the removed function node's next
+ overload pointer to null because the function node might
+ be added as a child to some other aggregate.
*/
-void Aggregate::removePseudoChild(Node *pseudoChild)
+void Aggregate::removeFunctionNode(FunctionNode *fn)
{
- if (pseudoChild->isFunction()) {
- QMap<QString, Node *>::Iterator p = primaryFunctionMap_.find(pseudoChild->name());
- while (p != primaryFunctionMap_.end()) {
- if (p.value() == pseudoChild) {
- primaryFunctionMap_.erase(p);
- break;
+ FunctionMap::Iterator i = functionMap_.find(fn->name());
+ if (i != functionMap_.end()) {
+ if (i.value() == fn) {
+ if (fn->nextOverload() != nullptr) {
+ i.value() = fn->nextOverload();
+ fn->setNextOverload(nullptr);
+ fn->setOverloadNumber(0);
+ }
+ else {
+ functionMap_.erase(i);
+ }
+ } else {
+ FunctionNode *current = i.value();
+ while (current != nullptr) {
+ if (current->nextOverload() == fn) {
+ current->setNextOverload(fn->nextOverload());
+ fn->setNextOverload(nullptr);
+ fn->setOverloadNumber(0);
+ break;
+ }
+ current = current->nextOverload();
}
- ++p;
}
- NodeList& overloads = secondaryFunctionMap_[pseudoChild->name()];
- overloads.removeAll(pseudoChild);
}
}
+/*
+ When deciding whether to include a function in the function
+ index, if the function is marked private, don't include it.
+ If the function is marked obsolete, don't include it. If the
+ function is marked internal, don't include it. Or if the
+ function is a destructor or any kind of constructor, don't
+ include it. Otherwise include it.
+ */
+static bool keep(FunctionNode *fn)
+{
+ if (fn->isPrivate() ||
+ fn->isObsolete() ||
+ fn->isInternal() ||
+ fn->isSomeCtor() ||
+ fn->isDtor())
+ return false;
+ return true;
+}
+
/*!
- Adds \a pseudoChild to the list of nodes related to this one. Resolve a correct
- overload number for a related non-member function.
+ Insert all functions declared in this aggregate into the
+ \a functionIndex. Call the function recursively for each
+ child that is an aggregate.
+
+ Only include functions that are in the public API and
+ that are not constructors or destructors.
*/
-void Aggregate::addPseudoChild(Node *pseudoChild)
+void Aggregate::findAllFunctions(NodeMapMap &functionIndex)
{
- if (pseudoChild->isFunction()) {
- FunctionNode* fn = static_cast<FunctionNode*>(pseudoChild);
- if (primaryFunctionMap_.contains(pseudoChild->name())) {
- secondaryFunctionMap_[pseudoChild->name()].append(pseudoChild);
- fn->setOverloadNumber(secondaryFunctionMap_[pseudoChild->name()].size());
- fn->setOverloadFlag(true);
+ FunctionMap::const_iterator i;
+ for (i = functionMap_.constBegin(); i != functionMap_.constEnd(); ++i) {
+ FunctionNode *fn = i.value();
+ if (keep(fn))
+ functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
+ fn = fn->nextOverload();
+ while (fn != nullptr) {
+ if (keep(fn))
+ functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
+ fn = fn->nextOverload();
}
- else {
- primaryFunctionMap_.insert(pseudoChild->name(), pseudoChild);
- fn->setOverloadNumber(0);
- fn->setOverloadFlag(false);
+ }
+ foreach (Node *n, children_) {
+ if (n->isAggregate() && !n->isPrivate())
+ static_cast<Aggregate*>(n)->findAllFunctions(functionIndex);
+ }
+}
+
+/*!
+ For each child of this node, if the child is a namespace node,
+ insert the child into the \a namespaces multimap. If the child
+ is an aggregate, call this function recursively for that child.
+
+ When the function called with the root node of a tree, it finds
+ all the namespace nodes in that tree and inserts them into the
+ \a namespaces multimap.
+
+ The root node of a tree is a namespace, but it has no name, so
+ it is not inserted into the map. So, if this function is called
+ for each tree in the qdoc database, it finds all the namespace
+ nodes in the database.
+ */
+void Aggregate::findAllNamespaces(NodeMultiMap &namespaces)
+{
+ foreach (Node *n, children_) {
+ if (n->isAggregate() && !n->isPrivate()) {
+ if (n->isNamespace() && !n->name().isEmpty())
+ namespaces.insert(n->name(), n);
+ static_cast<Aggregate*>(n)->findAllNamespaces(namespaces);
+ }
+ }
+}
+
+/*!
+ Returns true if this aggregate contains at least one child
+ that is marked obsolete. Otherwise returns false.
+ */
+bool Aggregate::hasObsoleteMembers()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate() && n->isObsolete()) {
+ if (n->isFunction() || n->isProperty() || n->isEnumType() ||
+ n->isTypedef() || n->isTypeAlias() || n->isVariable() ||
+ n->isQmlProperty() || n->isJsProperty())
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ Finds all the obsolete C++ classes and QML types in this
+ aggregate and all the C++ classes and QML types with obsolete
+ members, and inserts them into maps used elesewhere for
+ generating documentation.
+ */
+void Aggregate::findAllObsoleteThings()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate()) {
+ QString name = n->name();
+ if (n->isObsolete()) {
+ if (n->isClass())
+ QDocDatabase::obsoleteClasses().insert(n->qualifyCppName(), n);
+ else if (n->isQmlType() || n->isJsType())
+ QDocDatabase::obsoleteQmlTypes().insert(n->qualifyQmlName(), n);
+ } else if (n->isClass()) {
+ Aggregate *a = static_cast<Aggregate *>(n);
+ if (a->hasObsoleteMembers())
+ QDocDatabase::classesWithObsoleteMembers().insert(n->qualifyCppName(), n);
+ }
+ else if (n->isQmlType() || n->isJsType()) {
+ Aggregate *a = static_cast<Aggregate *>(n);
+ if (a->hasObsoleteMembers())
+ QDocDatabase::qmlTypesWithObsoleteMembers().insert(n->qualifyQmlName(), n);
+ }
+ else if (n->isAggregate()) {
+ static_cast<Aggregate*>(n)->findAllObsoleteThings();
+ }
+ }
+ }
+}
+
+/*!
+ Finds all the C++ classes, QML types, JS types, QML and JS
+ basic types, and examples in this aggregate and inserts them
+ into appropriate maps for later use in generating documentation.
+ */
+void Aggregate::findAllClasses()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate() && !n->isInternal() &&
+ n->tree()->camelCaseModuleName() != QString("QDoc")) {
+ if (n->isClass()) {
+ QDocDatabase::cppClasses().insert(n->qualifyCppName().toLower(), n);
+ } else if (n->isQmlType() || n->isQmlBasicType() || n->isJsType() || n->isJsBasicType()) {
+ QString name = n->unqualifyQmlName();
+ QDocDatabase::qmlTypes().insert(name, n);
+ //also add to the QML basic type map
+ if (n->isQmlBasicType() || n->isJsBasicType())
+ QDocDatabase::qmlBasicTypes().insert(name, n);
+ } else if (n->isExample()) {
+ // use the module index title as key for the example map
+ QString title = n->tree()->indexTitle();
+ if (!QDocDatabase::examples().contains(title, n))
+ QDocDatabase::examples().insert(title, n);
+ } else if (n->isAggregate()) {
+ static_cast<Aggregate*>(n)->findAllClasses();
+ }
}
}
}
/*!
+ Find all the attribution pages in this node and insert them
+ into \a attributions.
+ */
+void Aggregate::findAllAttributions(NodeMultiMap &attributions)
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate()) {
+ if (n->pageType() == Node::AttributionPage)
+ attributions.insertMulti(n->tree()->indexTitle(), n);
+ else if (n->isAggregate())
+ static_cast<Aggregate*>(n)->findAllAttributions(attributions);
+ }
+ }
+}
+
+/*!
+ \fn void findAllSince()
+
+ Finds all the nodes in this node where a \e{since} command appeared
+ in the qdoc comment and sorts them into maps according to the kind
+ of node.
+
+ This function is used for generating the "New Classes... in x.y"
+ section on the \e{What's New in Qt x.y} page.
+ */
+void Aggregate::findAllSince()
+{
+ foreach (Node *n, children_) {
+ QString sinceString = n->since();
+ // Insert a new entry into each map for each new since string found.
+ if (!n->isPrivate() && !sinceString.isEmpty()) {
+ NodeMultiMapMap::iterator nsmap = QDocDatabase::newSinceMaps().find(sinceString);
+ if (nsmap == QDocDatabase::newSinceMaps().end())
+ nsmap = QDocDatabase::newSinceMaps().insert(sinceString, NodeMultiMap());
+
+ NodeMapMap::iterator ncmap = QDocDatabase::newClassMaps().find(sinceString);
+ if (ncmap == QDocDatabase::newClassMaps().end())
+ ncmap = QDocDatabase::newClassMaps().insert(sinceString, NodeMap());
+
+ NodeMapMap::iterator nqcmap = QDocDatabase::newQmlTypeMaps().find(sinceString);
+ if (nqcmap == QDocDatabase::newQmlTypeMaps().end())
+ nqcmap = QDocDatabase::newQmlTypeMaps().insert(sinceString, NodeMap());
+
+ if (n->isFunction()) {
+ // Insert functions into the general since map.
+ FunctionNode *fn = static_cast<FunctionNode*>(n);
+ if (!fn->isObsolete() && !fn->isSomeCtor() && !fn->isDtor())
+ nsmap.value().insert(fn->name(), fn);
+ }
+ else if (n->isClass()) {
+ // Insert classes into the since and class maps.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ ncmap.value().insert(name, n);
+ } else if (n->isQmlType() || n->isJsType()) {
+ // Insert QML elements into the since and element maps.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ nqcmap.value().insert(name, n);
+ } else if (n->isQmlProperty() || n->isJsProperty()) {
+ // Insert QML properties into the since map.
+ nsmap.value().insert(n->name(), n);
+ } else {
+ // Insert external documents into the general since map.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ }
+ }
+ // Recursively find child nodes with since commands.
+ if (n->isAggregate())
+ static_cast<Aggregate*>(n)->findAllSince();
+ }
+}
+
+/*!
+ For each QML Type node in this aggregate's children, if the
+ QML type has a QML base type name but its QML base type node
+ pointer is nullptr, use the QML base type name to look up the
+ base type node. If the node is found, set the node's QML base
+ type node pointer to that node.
+ */
+void Aggregate::resolveQmlInheritance()
+{
+ NodeMap previousSearches;
+ // Do we need recursion?
+ foreach (Node *child, children_) {
+ if (!child->isQmlType() && !child->isJsType())
+ continue;
+ QmlTypeNode *type = static_cast<QmlTypeNode *>(child);
+ if (type->qmlBaseNode() != nullptr)
+ continue;
+ if (type->qmlBaseName().isEmpty())
+ continue;
+ QmlTypeNode *base = static_cast<QmlTypeNode *>(previousSearches.value(type->qmlBaseName()));
+ if (base && (base != type)) {
+ type->setQmlBaseNode(base);
+ QmlTypeNode::addInheritedBy(base, type);
+ } else {
+ if (!type->importList().isEmpty()) {
+ const ImportList &imports = type->importList();
+ for (int i=0; i<imports.size(); ++i) {
+ base = QDocDatabase::qdocDB()->findQmlType(imports[i], type->qmlBaseName());
+ if (base && (base != type)) {
+ if (base->logicalModuleVersion()[0] != imports[i].version_[0])
+ base = 0; // Safeguard for QTBUG-53529
+ break;
+ }
+ }
+ }
+ if (base == 0) {
+ base = QDocDatabase::qdocDB()->findQmlType(QString(), type->qmlBaseName());
+ }
+ if (base && (base != type)) {
+ type->setQmlBaseNode(base);
+ QmlTypeNode::addInheritedBy(base, type);
+ previousSearches.insert(type->qmlBaseName(), base);
+ }
+ }
+ }
+}
+
+/*!
+ \class ProxyNode
+ \brief A class for representing an Aggregate that is documented in a different module.
+
+ This class is used to represent an Aggregate (usually a class)
+ that is located and documented in a different module. In the
+ current module, a ProxyNode holds child nodes that are related
+ to the class in the other module.
+
+ For example, class QHash is located and documented in QtCore.
+ There are many global functions named qHash() in QtCore that
+ are all related to class QHash using the \c relates command.
+ There are also a few qHash() function in QtNetwork that are
+ related to QHash. These functions must be documented when the
+ documentation for QtNetwork is generated, but the reference
+ page for QHash must link to that documentation in its related
+ nonmembers list.
+
+ The ProxyNode allows qdoc to construct links to the related
+ functions (or other things?) in QtNetwork from the reference
+ page in QtCore.
+ */
+
+/*!
+ Constructs the ProxyNode, which at this point looks like any
+ other Aggregate, and then finds the Tree this node is in and
+ appends this node to that Tree's proxy list so it will be
+ easy to find later.
+ */
+ProxyNode::ProxyNode(Aggregate *parent, const QString &name)
+ : Aggregate(Node::Proxy, parent, name)
+{
+ tree()->appendProxy(this);
+}
+
+/*!
\class CollectionNode
\brief A class for holding the members of a collection of doc pages.
*/
@@ -3322,34 +3659,39 @@ void CollectionNode::setLogicalModuleInfo(const QStringList& info)
}
/*!
- Sets the overload flag to \b in each node in the collection.
+ Searches the shared comment node's member nodes for function
+ nodes. Each function node's overload flag is set.
*/
-void SharedCommentNode::setOverloadFlag(bool b)
+void SharedCommentNode::setOverloadFlags()
{
- for (Node *n : collective_)
- n->setOverloadFlag(b);
+ for (Node *n : collective_) {
+ if (n->isFunction())
+ static_cast<FunctionNode*>(n)->setOverloadFlag();
+ }
}
/*!
- Sets each node in this node's collective to be related to
- \a pseudoParent.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-void SharedCommentNode::setRelates(PageNode *pseudoParent)
+Node *SharedCommentNode::clone(Aggregate *parent)
{
- Node::setRelates(pseudoParent);
- for (Node *n : collective_)
- n->setRelates(pseudoParent);
+ SharedCommentNode *scn = new SharedCommentNode(*this); // shallow copy
+ scn->setParent(nullptr);
+ parent->addChild(scn);
+ return scn;
}
+
/*!
- Sets the (unresolved) entity \a name that this node relates to
- in each of the nodes in this shared comment node's collective.
+ Sets the related nonmember flag in this node and in each
+ node in the shared comment's collective.
*/
-void SharedCommentNode::setRelates(const QString& name)
+void SharedCommentNode::setRelatedNonmember(bool b)
{
- Node::setRelates(name);
+ Node::setRelatedNonmember(b);
for (Node *n : collective_)
- n->setRelates(name);
+ n->setRelatedNonmember(b);
}
QT_END_NAMESPACE
diff --git a/src/qdoc/node.h b/src/qdoc/node.h
index 76c1eee18..f882ec565 100644
--- a/src/qdoc/node.h
+++ b/src/qdoc/node.h
@@ -34,7 +34,7 @@
#include <qpair.h>
#include <qstringlist.h>
#include <qvector.h>
-#include "codechunk.h"
+#include "parameters.h"
#include "doc.h"
QT_BEGIN_NAMESPACE
@@ -55,13 +55,17 @@ class CollectionNode;
class QmlPropertyNode;
class SharedCommentNode;
+typedef QMap<QString, FunctionNode*> FunctionMap;
typedef QList<Node*> NodeList;
+typedef QList<ClassNode*> ClassList;
typedef QVector<Node*> NodeVector;
-typedef QList<PropertyNode*> PropNodeList;
typedef QMap<QString, Node*> NodeMap;
+typedef QMap<QString, NodeMap> NodeMapMap;
typedef QMultiMap<QString, Node*> NodeMultiMap;
+typedef QMap<QString, NodeMultiMap> NodeMultiMapMap;
typedef QMap<QString, CollectionNode*> CNMap;
typedef QMultiMap<QString, CollectionNode*> CNMultiMap;
+typedef QList<CollectionNode*> CollectionList;
class Node
{
@@ -95,6 +99,7 @@ public:
JsBasicType,
SharedComment,
Collection,
+ Proxy,
LastType
};
@@ -144,6 +149,9 @@ public:
};
virtual ~Node();
+ virtual Node *clone(Aggregate *) { return nullptr; } // currently only FunctionNode
+ virtual Tree *tree() const;
+ Aggregate *root() const;
NodeType nodeType() const { return (NodeType) nodeType_; }
QString nodeTypeString() const;
@@ -159,6 +167,7 @@ public:
void setPageType(const QString& t);
static PageType getPageType(NodeType t);
+ bool isActive() const { return (status_ == (unsigned char) Active); }
bool isClass() const { return nodeType_ == Class; }
bool isCppNode() const { return genus() == CPP; }
bool isEnumType() const { return nodeType_ == Enum; }
@@ -179,19 +188,24 @@ public:
bool isModule() const { return nodeType_ == Module; }
bool isNamespace() const { return nodeType_ == Namespace; }
bool isObsolete() const { return (status_ == (unsigned char) Obsolete); }
+ bool isPreliminary() const { return (status_ == (unsigned char) Preliminary); }
bool isPrivate() const { return (Access) access_ == Private; }
bool isProperty() const { return nodeType_ == Property; }
+ bool isProxyNode() const { return nodeType_ == Proxy; }
bool isPublic() const { return (Access) access_ == Public; }
+ bool isProtected() const { return (Access) access_ == Protected; }
bool isQmlBasicType() const { return nodeType_ == QmlBasicType; }
bool isQmlModule() const { return nodeType_ == QmlModule; }
bool isQmlNode() const { return genus() == QML; }
bool isQmlProperty() const { return nodeType_ == QmlProperty; }
bool isQmlPropertyGroup() const { return nodeType_ == QmlPropertyGroup; }
bool isQmlType() const { return nodeType_ == QmlType; }
+ bool isRelatedNonmember() const { return relatedNonmember_; }
bool isSharedCommentNode() const { return nodeType_ == SharedComment; }
bool isTypeAlias() const { return nodeType_ == Typedef; }
bool isTypedef() const { return nodeType_ == Typedef; }
bool isVariable() const { return nodeType_ == Variable; }
+ bool isGenericCollection() const { return (nodeType_ == Node::Collection); }
virtual bool isAbstract() const { return false; }
virtual bool isAggregate() const { return false; } // means "can have children"
@@ -199,13 +213,12 @@ public:
virtual bool isAttached() const { return false; }
virtual bool isCollectionNode() const { return false; }
virtual bool isDefault() const { return false; }
- virtual bool isImplicit() const { return false; }
virtual bool isInternal() const;
virtual bool isMacro() const { return false; }
virtual bool isPageNode() const { return false; } // means "generates a doc page"
virtual bool isQtQuickNode() const { return false; }
virtual bool isReadOnly() const { return false; }
- virtual bool isReimplemented() const { return false; }
+ virtual bool isMarkedReimp() const { return false; }
virtual bool isStatic() const { return false; }
virtual bool isTextPageNode() const { return false; } // means PageNode but not Aggregate
virtual bool isWrapper() const;
@@ -236,9 +249,8 @@ public:
void setReconstitutedBrief(const QString &t) { reconstitutedBrief_ = t; }
void setParent(Aggregate* n) { parent_ = n; }
void setIndexNodeFlag(bool isIndexNode = true) { indexNodeFlag_ = isIndexNode; }
+ virtual void setRelatedNonmember(bool b) { relatedNonmember_ = b; }
virtual void setOutputFileName(const QString& ) { }
-
-
virtual void addMember(Node* ) { }
virtual bool hasMembers() const { return false; }
virtual bool hasNamespaces() const { return false; }
@@ -248,12 +260,9 @@ public:
virtual void getMemberNamespaces(NodeMap& ) { }
virtual void getMemberClasses(NodeMap& ) const { }
virtual void setDataType(const QString& ) { }
- virtual void setReadOnly(bool ) { }
virtual bool wasSeen() const { return false; }
virtual void appendGroupName(const QString& ) { }
virtual QString element() const { return QString(); }
- virtual Tree* tree() const;
- virtual void findChildren(const QString& , NodeList& nodes) const { nodes.clear(); }
virtual void setNoAutoList(bool ) { }
virtual bool docMustBeGenerated() const { return false; }
@@ -263,9 +272,12 @@ public:
virtual bool setTitle(const QString& ) { return false; }
virtual bool setSubtitle(const QString& ) { return false; }
+ virtual void markInternal() { setAccess(Private); setStatus(Internal); }
+ virtual void markDefault() { }
+ virtual void markReadOnly(bool ) { }
+
bool match(const QList<int>& types) const;
Aggregate* parent() const { return parent_; }
- const Node* root() const;
const QString& name() const { return name_; }
QString physicalModuleName() const;
QString url() const { return url_; }
@@ -276,7 +288,6 @@ public:
virtual void setQtVariable(const QString& ) { }
virtual QString qtVariable() const { return QString(); }
virtual bool hasTag(const QString& ) const { return false; }
- virtual void setOverloadFlag(bool ) { }
const QMap<LinkType, QPair<QString,QString> >& links() const { return linkMap_; }
void setLink(LinkType linkType, const QString &link, const QString &desc);
@@ -298,11 +309,6 @@ public:
QString nodeSubtypeString() const;
virtual void addPageKeywords(const QString& ) { }
- void clearRelated() { relatesTo_ = 0; }
- PageNode* relates() const { return relatesTo_; }
- virtual void setRelates(PageNode* pseudoParent);
- virtual void setRelates(const QString &name);
-
bool isSharingComment() const { return (sharedCommentNode_ != 0); }
bool hasSharedDoc() const;
void setSharedCommentNode(SharedCommentNode* t);
@@ -327,11 +333,14 @@ public:
const QString& outputSubdirectory() const { return outSubDir_; }
virtual void setOutputSubdirectory(const QString& t) { outSubDir_ = t; }
QString fullDocumentName() const;
- static QString cleanId(const QString &str);
+ QString qualifyCppName();
+ QString qualifyQmlName();
+ QString unqualifyQmlName();
+ QString qualifyWithParentName();
+ static QString cleanId(const QString &str);
static FlagValue toFlagValue(bool b);
static bool fromFlagValue(FlagValue fv, bool defaultValue);
-
static QString pageTypeString(unsigned char t);
static QString nodeTypeString(unsigned char t);
static QString nodeSubtypeString(unsigned char t);
@@ -343,20 +352,18 @@ public:
protected:
Node(NodeType type, Aggregate* parent, const QString& name);
- void removeRelates();
private:
-
unsigned char nodeType_;
unsigned char genus_;
unsigned char access_;
unsigned char safeness_;
unsigned char pageType_;
unsigned char status_;
- bool indexNodeFlag_;
+ bool indexNodeFlag_ : 1;
+ bool relatedNonmember_ : 1;
Aggregate* parent_;
- PageNode* relatesTo_;
SharedCommentNode *sharedCommentNode_;
QString name_;
Location declLocation_;
@@ -389,7 +396,6 @@ public:
bool isPageNode() const override { return true; }
bool isTextPageNode() const override { return !isAggregate(); } // PageNode but not Aggregate
- virtual bool isDummyNode() const { return false; }
QString title() const override { return title_; }
QString subtitle() const override { return subtitle_; }
@@ -411,15 +417,8 @@ public:
void setOutputFileName(const QString& f) override { outputFileName_ = f; }
QString outputFileName() const override { return outputFileName_; }
- void removeFromRelated();
- const NodeList & relatedNodes() const { return related_; }
-
protected:
friend class Node;
- void removeRelated(Node* pseudoChild);
- void addRelated(Node* pseudoChild);
- virtual void removePseudoChild(Node *) { }
- virtual void addPseudoChild(Node *) { }
protected:
bool noAutoList_;
@@ -428,14 +427,6 @@ public:
QString outputFileName_;
QStringList groupNames_;
QStringList pageKeywds_;
- NodeList related_;
-};
-
-class DummyNode : public PageNode
-{
-public:
- DummyNode(Aggregate* parent, const QString& name) : PageNode(parent, name) { }
- bool isDummyNode() const override { return true; }
};
class ExternalPageNode : public PageNode
@@ -450,59 +441,81 @@ public:
class Aggregate : public PageNode
{
public:
- virtual ~Aggregate();
-
Node* findChildNode(const QString& name, Node::Genus genus, int findFlags = 0) const;
Node* findChildNode(const QString& name, NodeType type);
- void findChildren(const QString& name, NodeList& nodes) const override;
- FunctionNode* findFunctionNode(const QString& name, const QString& params) const;
- FunctionNode* findFunctionNode(const FunctionNode* clone) const;
+ void findChildren(const QString &name, NodeVector &nodes) const;
+ FunctionNode *findFunctionChild(const QString &name, const Parameters &parameters);
+ FunctionNode *findFunctionChild(const FunctionNode *clone);
void normalizeOverloads();
- void makeUndocumentedChildrenInternal();
- void deleteChildren();
+ void markUndocumentedChildrenInternal();
bool isAggregate() const override { return true; }
const EnumNode* findEnumNodeForValue(const QString &enumValue) const;
int count() const { return children_.size(); }
- const NodeList & childNodes() const { return children_; }
+ const NodeList &childNodes() const { return children_; }
+ const NodeList &nonfunctionList();
+ NodeList::ConstIterator constBegin() const { return children_.constBegin(); }
+ NodeList::ConstIterator constEnd() const { return children_.constEnd(); }
- NodeList overloads(const QString &funcName) const;
- void addInclude(const QString &include);
- void setIncludes(const QStringList &includes);
- const QStringList& includes() const { return includes_; }
+ void addIncludeFile(const QString &includeFile);
+ void setIncludeFiles(const QStringList &includeFiles);
+ const QStringList &includeFiles() const { return includeFiles_; }
QStringList primaryKeys();
- QStringList secondaryKeys();
QmlPropertyNode* hasQmlProperty(const QString& ) const;
QmlPropertyNode* hasQmlProperty(const QString&, bool attached) const;
virtual QmlTypeNode* qmlBaseNode() const { return 0; }
void addChildByTitle(Node* child, const QString& title);
void printChildren(const QString& title);
void addChild(Node* child);
- void removeChild(Node* child);
+ void adoptChild(Node *child);
void setOutputSubdirectory(const QString& t) override;
- const NodeMap& primaryFunctionMap() { return primaryFunctionMap_; }
- const QMap<QString, NodeList>& secondaryFunctionMap() { return secondaryFunctionMap_; }
-protected:
- Aggregate(NodeType type, Aggregate* parent, const QString& name) : PageNode(type, parent, name) { }
+ FunctionMap &functionMap() { return functionMap_; }
+ void findAllFunctions(NodeMapMap &functionIndex);
+ void findAllNamespaces(NodeMultiMap &namespaces);
+ void findAllAttributions(NodeMultiMap &attributions);
+ bool hasObsoleteMembers();
+ void findAllObsoleteThings();
+ void findAllClasses();
+ void findAllSince();
+ void resolveQmlInheritance();
+ bool hasOverloads(const FunctionNode *fn) const;
+ void appendToRelatedByProxy(const NodeList &t) { relatedByProxy_.append(t); }
+ NodeList &relatedByProxy() { return relatedByProxy_; }
- void removePseudoChild(Node *pseudoChild) override;
- void addPseudoChild(Node *pseudoChild) override;
+protected:
+ Aggregate(NodeType type, Aggregate *parent, const QString &name)
+ : PageNode(type, parent, name), functionCount_(0) { }
+ virtual ~Aggregate();
+ void removeFunctionNode(FunctionNode *fn);
private:
friend class Node;
+ void addFunction(FunctionNode *fn);
+ void adoptFunction(FunctionNode *fn);
static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2);
-private:
- QStringList includes_;
+ protected:
NodeList children_;
+ NodeList relatedByProxy_;
+
+private:
+ QStringList includeFiles_;
NodeList enumChildren_;
- NodeMap childMap_;
- NodeMap primaryFunctionMap_;
- QMap<QString, NodeList> secondaryFunctionMap_;
+ NodeMap nonfunctionMap_;
+ NodeList nonfunctionList_;
+ int functionCount_;
+ FunctionMap functionMap_;
+};
+
+class ProxyNode : public Aggregate
+{
+ public:
+ ProxyNode(Aggregate *parent, const QString &name);
+ bool docMustBeGenerated() const override { return true; }
};
class NamespaceNode : public Aggregate
@@ -510,15 +523,15 @@ class NamespaceNode : public Aggregate
public:
NamespaceNode(Aggregate* parent, const QString& name) : Aggregate(Namespace, parent, name),
seen_(false), documented_(false), tree_(0), docNode_(0) { }
- virtual ~NamespaceNode() { }
+ virtual ~NamespaceNode();
Tree* tree() const override { return (parent() ? parent()->tree() : tree_); }
bool wasSeen() const override { return seen_; }
void markSeen() { seen_ = true; }
void markNotSeen() { seen_ = false; }
void setTree(Tree* t) { tree_ = t; }
- const NodeList& orphans() const { return orphans_; }
- void addOrphan(Node* child) { orphans_.append(child); }
+ const NodeList &includedChildren() const;
+ void includeChild(Node *child);
QString whereDocumented() const { return whereDocumented_; }
void setWhereDocumented(const QString &t) { whereDocumented_ = t; }
bool isDocumentedHere() const;
@@ -536,7 +549,7 @@ private:
Tree* tree_;
QString whereDocumented_;
NamespaceNode* docNode_;
- NodeList orphans_;
+ NodeList includedChildren_;
};
struct RelatedClass
@@ -754,6 +767,10 @@ public:
QString idNumber() override;
QString element() const override { return parent()->name(); }
+ void markInternal() override;
+ void markDefault() override;
+ void markReadOnly(bool flag) override;
+
private:
int idNumber_;
};
@@ -772,8 +789,6 @@ public:
void setDataType(const QString& dataType) override { type_ = dataType; }
void setStored(bool stored) { stored_ = toFlagValue(stored); }
void setDesignable(bool designable) { designable_ = toFlagValue(designable); }
- void setReadOnly(bool ro) override { readOnly_ = toFlagValue(ro); }
- void setDefault() { isdefault_ = true; }
const QString &dataType() const { return type_; }
QString qualifiedDataType() const { return type_; }
@@ -798,6 +813,9 @@ public:
}
QString element() const override;
+ void markDefault() override { isdefault_ = true; }
+ void markReadOnly(bool flag) override { readOnly_ = toFlagValue(flag); }
+
private:
PropertyNode* findCorrespondingCppProperty();
@@ -840,6 +858,7 @@ public:
Access itemAccess(const QString& name) const;
const TypedefNode* flagsType() const { return flagsType_; }
QString itemValue(const QString &name) const;
+ Node *clone(Aggregate *parent) override;
private:
QList<EnumItem> items_;
@@ -854,7 +873,9 @@ public:
associatedEnum_(0) { }
virtual ~TypedefNode() { }
+ bool hasAssociatedEnum() const { return associatedEnum_ != nullptr; }
const EnumNode* associatedEnum() const { return associatedEnum_; }
+ Node *clone(Aggregate *parent) override;
private:
void setAssociatedEnum(const EnumNode* t);
@@ -872,6 +893,7 @@ public:
virtual ~TypeAliasNode() { }
QString aliasedType() { return aliasedType_; }
+ Node *clone(Aggregate *parent) override;
private:
QString aliasedType_;
@@ -883,33 +905,6 @@ inline void EnumNode::setFlagsType(TypedefNode* t)
t->setAssociatedEnum(this);
}
-class Parameter
-{
-public:
- Parameter() {}
- Parameter(const QString& dataType,
- const QString& name = QString(),
- const QString& defaultValue = QString());
- Parameter(const Parameter& p);
-
- Parameter& operator=(const Parameter& p);
-
- void setName(const QString& name) { name_ = name; }
-
- bool hasType() const { return dataType_.length() > 0; }
- const QString& dataType() const { return dataType_; }
- const QString& name() const { return name_; }
- const QString& defaultValue() const { return defaultValue_; }
- void setDefaultValue(const QString& defaultValue) { defaultValue_ = defaultValue; }
-
- QString reconstruct(bool value = false) const;
-
-public:
- QString dataType_;
- QString name_;
- QString defaultValue_;
-};
-
class SharedCommentNode : public Node
{
public:
@@ -921,17 +916,14 @@ public:
void append(Node* n) { collective_.append(n); }
const QVector<Node*>& collective() const { return collective_; }
- void setOverloadFlag(bool b) override;
- void setRelates(PageNode* pseudoParent) override;
- void setRelates(const QString &name) override;
+ void setOverloadFlags();
+ void setRelatedNonmember(bool b) override;
+ Node *clone(Aggregate *parent) override;
private:
QVector<Node*> collective_;
};
-//friend class QTypeInfo<Parameter>;
-//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE);
-
class FunctionNode : public Node
{
public:
@@ -962,6 +954,7 @@ public:
FunctionNode(Metaness type, Aggregate* parent, const QString &name, bool attached = false);
virtual ~FunctionNode() { }
+ Node *clone(Aggregate *parent) override;
Metaness metaness() const { return metaness_; }
QString metanessString() const;
bool changeMetaness(Metaness from, Metaness to);
@@ -979,22 +972,15 @@ public:
void setVirtual() { virtualness_ = NormalVirtual; }
void setConst(bool b) { const_ = b; }
void setStatic(bool b) { static_ = b; }
- unsigned char overloadNumber() const { return overloadNumber_; }
- void setOverloadFlag(bool b) override { overload_ = b; }
- void setOverloadNumber(unsigned char n) { overloadNumber_ = n; }
- void setReimplemented(bool b);
- void addParameter(const Parameter& parameter);
- inline void setParameters(const QVector<Parameter>& parameters);
- void setParameters(const QString &t);
- void borrowParameterNames(const FunctionNode* source);
- void setReimplementedFrom(const QString &path) { reimplementedFrom_ = path; }
+ void setReimpFlag() { reimpFlag_ = true; };
+ void setOverridesThis(const QString &path) { overridesThis_ = path; }
const QString& returnType() const { return returnType_; }
QString virtualness() const;
bool isConst() const { return const_; }
bool isStatic() const override { return static_; }
- bool isOverload() const { return overload_; }
- bool isReimplemented() const override { return reimplemented_; }
+ bool isOverload() const { return overloadFlag_; }
+ bool isMarkedReimp() const override { return reimpFlag_; }
bool isSomeCtor() const { return isCtor() || isCCtor() || isMCtor(); }
bool isMacroWithParams() const { return (metaness_ == MacroWithParams); }
bool isMacroWithoutParams() const { return (metaness_ == MacroWithoutParams); }
@@ -1024,22 +1010,22 @@ public:
bool isNonvirtual() const { return (virtualness_ == NonVirtual); }
bool isVirtual() const { return (virtualness_ == NormalVirtual); }
bool isPureVirtual() const { return (virtualness_ == PureVirtual); }
+ bool returnsBool() const { return (returnType_ == QLatin1String("bool")); }
+
+ Parameters &parameters() { return parameters_; }
+ const Parameters &parameters() const { return parameters_; }
+ bool isPrivateSignal() const { return parameters_.isPrivateSignal(); }
+ void setParameters(const QString &signature) { parameters_.set(signature); }
+ QString signature(bool values, bool noReturnType) const override;
- QVector<Parameter> &parameters() { return parameters_; }
- const QVector<Parameter>& parameters() const { return parameters_; }
- void clearParams() { parameters_.clear(); }
- QStringList parameterNames() const;
- QString rawParameters(bool names = false, bool values = false) const;
- const QString& reimplementedFrom() const { return reimplementedFrom_; }
- const PropNodeList& associatedProperties() const { return associatedProperties_; }
+ const QString &overridesThis() const { return overridesThis_; }
+ NodeList &associatedProperties() { return associatedProperties_; }
const QStringList& parentPath() const { return parentPath_; }
bool hasAssociatedProperties() const { return !associatedProperties_.isEmpty(); }
bool hasOneAssociatedProperty() const { return (associatedProperties_.size() == 1); }
- PropertyNode* firstAssociatedProperty() const { return associatedProperties_[0]; }
+ Node *firstAssociatedProperty() const { return associatedProperties_[0]; }
bool hasActiveAssociatedProperty() const;
- QStringList reconstructParameters(bool values = false) const;
- QString signature(bool values, bool noReturnType = false) const override;
QString element() const override { return parent()->name(); }
bool isAttached() const override { return attached_; }
bool isQtQuickNode() const override { return parent()->isQtQuickNode(); }
@@ -1047,26 +1033,15 @@ public:
QString logicalModuleName() const override { return parent()->logicalModuleName(); }
QString logicalModuleVersion() const override { return parent()->logicalModuleVersion(); }
QString logicalModuleIdentifier() const override { return parent()->logicalModuleIdentifier(); }
- bool isPrivateSignal() const { return privateSignal_; }
- void setPrivateSignal() { privateSignal_ = true; }
void debug() const;
- bool isDeleted() const { return isDeleted_; }
- void setIsDeleted(bool b) { isDeleted_ = b; }
-
- bool isDefaulted() const { return isDefaulted_; }
- void setIsDefaulted(bool b) { isDefaulted_ = b; }
-
void setFinal(bool b) { isFinal_ = b; }
bool isFinal() const { return isFinal_; }
void setOverride(bool b) { isOverride_ = b; }
bool isOverride() const { return isOverride_; }
- void setImplicit(bool b) { isImplicit_ = b; }
- bool isImplicit() const override { return isImplicit_; }
-
void setRef(bool b) { isRef_ = b; }
bool isRef() const { return isRef_; }
@@ -1081,6 +1056,15 @@ public:
const QString &tag() const { return tag_; }
bool compare(const FunctionNode *fn) const;
bool isIgnored() const;
+ bool hasOverloads() const;
+ void clearOverloadFlag() { overloadFlag_ = false; }
+ void setOverloadFlag() { overloadFlag_ = true; }
+ void setOverloadNumber(signed short n);
+ void appendOverload(FunctionNode *fn);
+ signed short overloadNumber() const { return overloadNumber_; }
+ FunctionNode *nextOverload() { return nextOverload_; }
+ void setNextOverload(FunctionNode *fn) { nextOverload_ = fn; }
+ FunctionNode *findPrimaryFunction();
private:
void addAssociatedProperty(PropertyNode* property);
@@ -1088,29 +1072,26 @@ private:
friend class Aggregate;
friend class PropertyNode;
- QString returnType_;
- QStringList parentPath_;
- Metaness metaness_;
- Virtualness virtualness_;
bool const_ : 1;
bool static_ : 1;
- bool reimplemented_: 1;
+ bool reimpFlag_: 1;
bool attached_: 1;
- bool privateSignal_: 1;
- bool overload_ : 1;
- bool isDeleted_ : 1;
- bool isDefaulted_ : 1;
+ bool overloadFlag_ : 1;
bool isFinal_ : 1;
bool isOverride_ : 1;
- bool isImplicit_ : 1;
bool isRef_ : 1;
bool isRefRef_ : 1;
bool isInvokable_ : 1;
- unsigned char overloadNumber_;
- QVector<Parameter> parameters_;
- QString reimplementedFrom_;
- PropNodeList associatedProperties_;
- QString tag_;
+ Metaness metaness_;
+ Virtualness virtualness_;
+ signed short overloadNumber_;
+ FunctionNode *nextOverload_;
+ QString returnType_;
+ QStringList parentPath_;
+ QString overridesThis_;
+ QString tag_;
+ NodeList associatedProperties_;
+ Parameters parameters_;
};
class PropertyNode : public Node
@@ -1179,11 +1160,6 @@ private:
const PropertyNode* overrides_;
};
-inline void FunctionNode::setParameters(const QVector<Parameter> &p)
-{
- parameters_ = p;
-}
-
inline void PropertyNode::addFunction(FunctionNode* function, FunctionRole role)
{
functions_[(int)role].append(function);
@@ -1218,6 +1194,7 @@ public:
const QString &rightType() const { return rightType_; }
QString dataType() const { return leftType_ + rightType_; }
bool isStatic() const override { return static_; }
+ Node *clone(Aggregate *parent) override;
private:
QString leftType_;
diff --git a/src/qdoc/parameters.cpp b/src/qdoc/parameters.cpp
new file mode 100644
index 000000000..6e9c2dd9e
--- /dev/null
+++ b/src/qdoc/parameters.cpp
@@ -0,0 +1,567 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "parameters.h"
+#include "tokenizer.h"
+#include "codechunk.h"
+#include "generator.h"
+
+QT_BEGIN_NAMESPACE
+
+QRegExp Parameters::varComment_("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/");
+
+/*!
+ \class Parameter
+ \brief The Parameter class describes one function parameter.
+
+ A parameter can be a function parameter or a macro parameter.
+ It has a name, a data type, and an optional default value.
+ These are all stored as strings so they can be compared with
+ a parameter in a function signature to find a match.
+ */
+
+/*!
+ \fn Parameter::Parameter(const QString &type, const QString &name, const QString &defaultValue)
+
+ Constructs the parameter from the \a type, the optional \a name,
+ and the optional \a defaultValue.
+ */
+
+/*!
+ Reconstructs the text signature for the parameter and returns
+ it. If \a includeValue is true and there is a default value,
+ the default value is appended with '='.
+ */
+QString Parameter::signature(bool includeValue) const
+{
+ QString p = type_;
+ if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
+ p += QLatin1Char(' ');
+ p += name_;
+ if (includeValue && !defaultValue_.isEmpty())
+ p += " = " + defaultValue_;
+ return p;
+}
+
+/*!
+ \class Parameters
+
+ \brief A class for parsing and managing a function parameter list
+
+ The constructor is passed a string that is the text inside the
+ parentheses of a function declaration. The constructor parses
+ the parameter list into a vector of class Parameter.
+
+ The Parameters object is then used in function searches to find
+ the correct function node given the function name and the signature
+ of its parameters.
+ */
+
+Parameters::Parameters()
+ : valid_(true), privateSignal_(false), tok_(0), tokenizer_(0)
+{
+ // nothing.
+}
+
+Parameters::Parameters(const QString &signature)
+ : valid_(true), privateSignal_(false), tok_(0), tokenizer_(0)
+{
+ if (!signature.isEmpty()) {
+ if (!parse(signature)) {
+ parameters_.clear();
+ valid_ = false;
+ }
+ }
+}
+
+/*!
+ Get the next token from the string being parsed and store
+ it in the token variable.
+ */
+void Parameters::readToken()
+{
+ tok_ = tokenizer_->getToken();
+}
+
+/*!
+ Return the current lexeme from the string being parsed.
+ */
+QString Parameters::lexeme()
+{
+ return tokenizer_->lexeme();
+}
+
+/*!
+ Return the previous lexeme read from the string being parsed.
+ */
+QString Parameters::previousLexeme()
+{
+ return tokenizer_->previousLexeme();
+}
+
+/*!
+ If the current token is \a target, read the next token and
+ return \c true. Otherwise, return false without reading the
+ next token.
+ */
+bool Parameters::match(int target)
+{
+ if (tok_ == target) {
+ readToken();
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Match a template clause in angle brackets, append it to the
+ \a type, and return \c true. If there is no template clause,
+ or if an error is detected, return \c false.
+ */
+void Parameters::matchTemplateAngles(CodeChunk &type)
+{
+ if (tok_ == Tok_LeftAngle) {
+ 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;
+ }
+ type.append(lexeme());
+ readToken();
+ } while (leftAngleDepth > 0 && tok_ != Tok_Eoi);
+ }
+}
+
+/*!
+ Uses the current tokenizer to parse the \a name and \a type
+ of the parameter.
+ */
+bool Parameters::matchTypeAndName(CodeChunk &type, QString &name, 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))
+ type.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())
+ type.append(pending);
+ pending.clear();
+ type.append(lexeme());
+ }
+ readToken();
+ virgin = false;
+ }
+ if (!pending.isEmpty()) {
+ type.append(pending);
+ pending.clear();
+ }
+ while (match(Tok_const) || match(Tok_volatile))
+ type.append(previousLexeme());
+
+ if (match(Tok_Tilde))
+ type.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.
+ Is it still needed? mws 11/12/2018
+ */
+ if (lexeme() == "(" &&
+ ((previousLexeme() == "QT_PREPEND_NAMESPACE") || (previousLexeme() == "NS"))) {
+ readToken();
+ readToken();
+ type.append(previousLexeme());
+ readToken();
+ }
+ else
+ type.append(previousLexeme());
+ }
+ else if (match(Tok_void) || match(Tok_int) || match(Tok_char) ||
+ match(Tok_double) || match(Tok_Ellipsis)) {
+ type.append(previousLexeme());
+ }
+ else {
+ return false;
+ }
+ }
+ else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) {
+ type.append(previousLexeme());
+ }
+
+ matchTemplateAngles(type);
+
+ while (match(Tok_const) || match(Tok_volatile))
+ type.append(previousLexeme());
+
+ if (match(Tok_Gulbrandsen))
+ type.append(previousLexeme());
+ else
+ break;
+ }
+
+ while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) ||
+ match(Tok_Caret) || match(Tok_Ellipsis))
+ type.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.
+ */
+ type.append(" "); // force a space after the type
+ type.append(previousLexeme());
+ type.appendHotspot();
+ if (match(Tok_Ident))
+ name = previousLexeme();
+ if (!match(Tok_RightParen))
+ return false;
+ type.append(previousLexeme());
+ if (!match(Tok_LeftParen))
+ return false;
+ type.append(previousLexeme());
+
+ /* parse the parameters. Ignore the parameter name from the type */
+ while (tok_ != Tok_RightParen && tok_ != Tok_Eoi) {
+ QString dummy;
+ if (!matchTypeAndName(type, dummy))
+ return false;
+ if (match(Tok_Comma))
+ type.append(previousLexeme());
+ }
+ if (!match(Tok_RightParen))
+ return false;
+ type.append(previousLexeme());
+ }
+ else {
+ /*
+ The common case: Look for an optional identifier, then for
+ some array brackets.
+ */
+ type.appendHotspot();
+
+ if (match(Tok_Ident)) {
+ name = 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()))
+ name = varComment_.cap(1);
+ }
+ else if (match(Tok_LeftParen)) {
+ name = "(";
+ while (tok_ != Tok_RightParen && tok_ != Tok_Eoi) {
+ name.append(lexeme());
+ readToken();
+ }
+ name.append(")");
+ readToken();
+ if (match(Tok_LeftBracket)) {
+ name.append("[");
+ while (tok_ != Tok_RightBracket && tok_ != Tok_Eoi) {
+ name.append(lexeme());
+ readToken();
+ }
+ name.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
+ name = previousLexeme();
+ }
+
+ if (tok_ == Tok_LeftBracket) {
+ int bracketDepth0 = tokenizer_->bracketDepth();
+ while ((tokenizer_->bracketDepth() >= bracketDepth0 &&
+ tok_ != Tok_Eoi) ||
+ tok_ == Tok_RightBracket) {
+ type.append(lexeme());
+ readToken();
+ }
+ }
+ }
+ return true;
+}
+
+/*!
+ Parse the next function parameter, if there is one, and
+ append it to the internal parameter vector. Return true
+ if a parameter is parsed correctly. Otherwise return false.
+ */
+bool Parameters::matchParameter()
+{
+ if (match(Tok_QPrivateSignal)) {
+ privateSignal_ = true;
+ return true;
+ }
+
+ CodeChunk chunk;
+ QString name;
+ if (!matchTypeAndName(chunk, name))
+ return false;
+ QString type = chunk.toString();
+ QString defaultValue;
+ match(Tok_Comment);
+ if (match(Tok_Equal)) {
+ chunk.clear();
+ int pdepth = tokenizer_->parenDepth();
+ while (tokenizer_->parenDepth() >= pdepth &&
+ (tok_ != Tok_Comma || (tokenizer_->parenDepth() > pdepth)) &&
+ tok_ != Tok_Eoi) {
+ chunk.append(lexeme());
+ readToken();
+ }
+ defaultValue = chunk.toString();
+ }
+ append(type, name, defaultValue);
+ return true;
+}
+
+/*!
+ This function uses a Tokenizer to parse the \a signature,
+ which is a comma-separated list of parameter declarations.
+ If an error is detected, the Parameters object is cleared
+ and \c false is returned. Otherwise \c true is returned.
+ */
+bool Parameters::parse(const QString &signature)
+{
+ Tokenizer *outerTokenizer = tokenizer_;
+ int outerTok = tok_;
+
+ QByteArray latin1 = signature.toLatin1();
+ Tokenizer stringTokenizer(Location(), latin1);
+ stringTokenizer.setParsingFnOrMacro(true);
+ tokenizer_ = &stringTokenizer;
+
+ readToken();
+ do {
+ if (!matchParameter()) {
+ parameters_.clear();
+ valid_ = false;
+ break;
+ }
+ } while (match(Tok_Comma));
+
+ tokenizer_ = outerTokenizer;
+ tok_ = outerTok;
+ return valid_;
+}
+
+/*!
+ Append a Parameter constructed from \a type, \a name, and \a value
+ to the parameter vector.
+ */
+void Parameters::append(const QString &type, const QString &name, const QString &value)
+{
+ parameters_.append(Parameter(type, name, value));
+}
+
+/*!
+ Returns the list of reconstructed parameters. If \a includeValues
+ is true, the default values are included, if any are present.
+ */
+QString Parameters::signature(bool includeValues) const
+{
+ QString result;
+ if (parameters_.size() > 0) {
+ for (int i = 0; i < parameters_.size(); i++) {
+ if (i > 0)
+ result += ", ";
+ result += parameters_.at(i).signature(includeValues);
+ }
+ }
+ return result;
+}
+
+/*!
+ Returns the signature of all the parameters with all the
+ spaces and commas removed. It is unintelligible, but that
+ is what the caller wants.
+
+ If \a names is true, the parameter names are included. If
+ \a values is true, the default values are included.
+ */
+QString Parameters::rawSignature(bool names, bool values) const
+{
+ QString raw;
+ foreach (const Parameter &parameter, parameters_) {
+ raw += parameter.type();
+ if (names)
+ raw += parameter.name();
+ if (values)
+ raw += parameter.defaultValue();
+ }
+ return raw;
+}
+
+/*!
+ Parse the parameter \a signature by splitting the string,
+ and store the individual parameters in the parameter vector.
+
+ This method of parsing the parameter signature probably
+ doesn't work for all cases. Investigate doing using the
+ more robust way in parse().
+ */
+void Parameters::set(const QString &signature)
+{
+ clear();
+ if (!signature.isEmpty()) {
+ QStringList commaSplit = signature.split(',');
+ parameters_.resize(commaSplit.size() + 1);
+ for (int i = 0; i < commaSplit.size(); i++) {
+ QStringList blankSplit = commaSplit[i].split(' ');
+ QString pName = blankSplit.last();
+ blankSplit.removeLast();
+ QString pType;
+ if (blankSplit.size() > 1)
+ pType = blankSplit.join(' ');
+ if (pType.isEmpty() && pName == QLatin1String("..."))
+ qSwap(pType, pName);
+ else {
+ int i = 0;
+ while (i < pName.length() && !pName.at(i).isLetter())
+ i++;
+ if (i > 0) {
+ pType += QChar(' ') + pName.left(i);
+ pName = pName.mid(i);
+ }
+ }
+ parameters_[i].set(pType, pName);
+ }
+ }
+}
+
+/*!
+ Insert all the parameter names into names.
+ */
+void Parameters::getNames(QSet<QString> &names) const
+{
+ foreach (const Parameter &parameter, parameters_) {
+ if (!parameter.name().isEmpty())
+ names.insert(parameter.name());
+ }
+}
+
+/*!
+ Construct a list of the parameter types and append it to
+ \a out. \a out is not cleared first.
+ */
+void Parameters::getTypeList(QString &out) const
+{
+ if (count() > 0) {
+ for (int i = 0; i < count(); ++i) {
+ if (i > 0)
+ out += ", ";
+ out += parameters_.at(i).type();
+ }
+ }
+}
+
+/*!
+ Construct a list of the parameter type/name pairs and
+ append it to \a out. \a out is not cleared first.
+*/
+void Parameters::getTypeAndNameList(QString &out) const
+{
+ if (count() > 0) {
+ for (int i = 0; i < count(); ++i) {
+ if (i != 0)
+ out += ", ";
+ const Parameter &p = parameters_.at(i);
+ out += p.type();
+ if (out[out.size() - 1].isLetterOrNumber())
+ out += QLatin1Char(' ');
+ out += p.name();
+ }
+ }
+}
+
+/*!
+ Returns true if \a parameters contains the same parameter
+ signature as this.
+ */
+bool Parameters::match(const Parameters &parameters) const
+{
+ if (count() != parameters.count())
+ return false;
+ if (count() == 0)
+ return true;
+ for (int i = 0; i < count(); i++) {
+ if (parameters.at(i).type() != parameters_.at(i).type())
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qdoc/parameters.h b/src/qdoc/parameters.h
new file mode 100644
index 000000000..b83c579c2
--- /dev/null
+++ b/src/qdoc/parameters.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARAMETERS_H
+#define PARAMETERS_H
+
+#include <qregexp.h>
+#include <qvector.h>
+#include <qset.h>
+
+QT_BEGIN_NAMESPACE
+
+class Location;
+class Tokenizer;
+class CodeChunk;
+
+class Parameter
+{
+ public:
+ Parameter() {}
+ Parameter(const QString &type,
+ const QString &name = QString(),
+ const QString &defaultValue = QString())
+ : type_(type), name_(name), defaultValue_(defaultValue) { }
+
+ void setName(const QString &name) { name_ = name; }
+ bool hasType() const { return !type_.isEmpty(); }
+ const QString &type() const { return type_; }
+ const QString &name() const { return name_; }
+ const QString &defaultValue() const { return defaultValue_; }
+ void setDefaultValue(const QString &t) { defaultValue_ = t; }
+
+ void set(const QString &type, const QString &name) {
+ type_ = type; name_ = name; defaultValue_.clear();
+ }
+
+ void set(const QString &type, const QString &name, const QString &defaultValue) {
+ type_ = type; name_ = name; defaultValue_ = defaultValue;
+ }
+
+ QString signature(bool includeValue = false) const;
+
+ public:
+ QString type_;
+ QString name_;
+ QString defaultValue_;
+};
+
+typedef QVector<Parameter> ParameterVector;
+
+class Parameters
+{
+ public:
+ Parameters();
+ Parameters(const QString &signature);
+
+ void clear() { parameters_.clear(); privateSignal_ = false; valid_ = true; }
+ const ParameterVector &parameters() const { return parameters_; }
+ bool isPrivateSignal() const { return privateSignal_; }
+ bool isEmpty() const { return parameters_.isEmpty(); }
+ bool isValid() const { return valid_; }
+ int count() const { return parameters_.size(); }
+ void reserve(int count) { parameters_.reserve(count); }
+ const Parameter &at(int i) const { return parameters_.at(i); }
+ const Parameter &last() const { return parameters_.last(); }
+ inline Parameter &operator[](int index) { return parameters_[index]; }
+ void append(const QString &type, const QString &name, const QString &value);
+ void append(const QString &type, const QString &name) { append(type, name, QString()); }
+ void append(const QString &type) { append(type, QString(), QString()); }
+ void pop_back() { parameters_.pop_back(); }
+ void setPrivateSignal() { privateSignal_ = true; }
+ QString signature(bool includeValues = false) const;
+ QString rawSignature(bool names = false, bool values = false) const;
+ void set(const QString &signature);
+ void getNames(QSet<QString> &names) const;
+ void getTypeList(QString &out) const;
+ void getTypeAndNameList(QString &out) const;
+ bool match(const Parameters &parameters) const;
+
+ private:
+ void readToken();
+ QString lexeme();
+ QString previousLexeme();
+ bool match(int target);
+ void matchTemplateAngles(CodeChunk &type);
+ bool matchTypeAndName(CodeChunk &type, QString &name, bool qProp = false);
+ bool matchParameter();
+ bool parse(const QString &signature);
+
+ private:
+ static QRegExp varComment_;
+
+ bool valid_;
+ bool privateSignal_;
+ int tok_;
+ Tokenizer *tokenizer_;
+ ParameterVector parameters_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qdoc/puredocparser.cpp b/src/qdoc/puredocparser.cpp
index cd3479f7f..251c47185 100644
--- a/src/qdoc/puredocparser.cpp
+++ b/src/qdoc/puredocparser.cpp
@@ -26,17 +26,8 @@
**
****************************************************************************/
-/*
- puredocparser.cpp
-*/
-
-#include <qfile.h>
-#include <stdio.h>
#include <errno.h>
-#include "codechunk.h"
-#include "config.h"
#include "tokenizer.h"
-#include <qdebug.h>
#include "qdocdatabase.h"
#include "puredocparser.h"
@@ -69,11 +60,10 @@ void PureDocParser::parseSourceFile(const Location& location, const QString& fil
return;
}
- reset();
Location fileLocation(filePath);
Tokenizer fileTokenizer(fileLocation, in);
- tokenizer = &fileTokenizer;
- readToken();
+ tokenizer_ = &fileTokenizer;
+ tok_ = tokenizer_->getToken();
/*
The set of open namespaces is cleared before parsing
@@ -93,19 +83,19 @@ void PureDocParser::parseSourceFile(const Location& location, const QString& fil
*/
bool PureDocParser::processQdocComments()
{
- const QSet<QString>& metacommands = topicCommands() + otherMetaCommands();
+ const QSet<QString>& commands = topicCommands() + metaCommands();
- while (tok != Tok_Eoi) {
- if (tok == Tok_Doc) {
- QString comment = lexeme(); // returns an entire qdoc comment.
- Location start_loc(location());
- readToken();
+ while (tok_ != Tok_Eoi) {
+ if (tok_ == Tok_Doc) {
+ QString comment = tokenizer_->lexeme(); // returns an entire qdoc comment.
+ Location start_loc(tokenizer_->location());
+ tok_ = tokenizer_->getToken();
- Doc::trimCStyleComment(start_loc,comment);
- Location end_loc(location());
+ Doc::trimCStyleComment(start_loc, comment);
+ Location end_loc(tokenizer_->location());
// Doc constructor parses the comment.
- Doc doc(start_loc, end_loc, comment, metacommands, topicCommands());
+ Doc doc(start_loc, end_loc, comment, commands, topicCommands());
const TopicList& topics = doc.topicsUsed();
if (topics.isEmpty()) {
doc.location().warning(tr("This qdoc comment contains no topic command "
@@ -121,10 +111,10 @@ bool PureDocParser::processQdocComments()
QString topic = topics[0].topic;
processTopicArgs(doc, topic, nodes, docs);
- processOtherMetaCommands(nodes, docs);
+ processMetaCommands(nodes, docs);
}
else {
- readToken();
+ tok_ = tokenizer_->getToken();
}
}
return true;
diff --git a/src/qdoc/puredocparser.h b/src/qdoc/puredocparser.h
index 60f20484c..4e6a16a48 100644
--- a/src/qdoc/puredocparser.h
+++ b/src/qdoc/puredocparser.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
@@ -30,20 +30,17 @@
#define PUREDOCPARSER_H
#include "cppcodeparser.h"
-#include "location.h"
QT_BEGIN_NAMESPACE
-class Config;
-class Node;
-class QString;
+class Location;
class PureDocParser : public CppCodeParser
{
Q_DECLARE_TR_FUNCTIONS(QDoc::PureDocParser)
public:
- PureDocParser() { pureParser_ = this; }
+ PureDocParser() : tokenizer_(nullptr), tok_(0) { pureParser_ = this; }
virtual ~PureDocParser() { pureParser_ = nullptr; }
QStringList sourceFileNameFilter() override;
@@ -54,6 +51,8 @@ public:
private:
bool processQdocComments();
static PureDocParser *pureParser_;
+ Tokenizer *tokenizer_;
+ int tok_;
};
QT_END_NAMESPACE
diff --git a/src/qdoc/qdoc.pro b/src/qdoc/qdoc.pro
index 4334259c4..95fdc5cdf 100644
--- a/src/qdoc/qdoc.pro
+++ b/src/qdoc/qdoc.pro
@@ -48,6 +48,7 @@ HEADERS += atom.h \
loggingcategory.h \
node.h \
openedlist.h \
+ parameters.h \
puredocparser.h \
qdocdatabase.h \
qdoctagfiles.h \
@@ -79,6 +80,7 @@ SOURCES += atom.cpp \
main.cpp \
node.cpp \
openedlist.cpp \
+ parameters.cpp \
puredocparser.cpp \
qdocdatabase.cpp \
qdoctagfiles.cpp \
diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp
index 6a19baf55..bed2f0be1 100644
--- a/src/qdoc/qdocdatabase.cpp
+++ b/src/qdoc/qdocdatabase.cpp
@@ -40,18 +40,41 @@ static NodeMap emptyNodeMap_;
static NodeMultiMap emptyNodeMultiMap_;
bool QDocDatabase::debug = false;
-/*! \class QDocForest
- This class manages a collection of trees. Each tree is an
- instance of class Tree, which is a private class.
+/*!
+ \class QDocForest
+
+ A class representing a forest of Tree objects.
+
+ This private class manages a collection of Tree objects (a
+ forest) for the singleton QDocDatabase object. It is only
+ accessed by that singleton QDocDatabase object, which is a
+ friend. Each tree in the forest is an instance of class
+ Tree, which is a mostly private class. Both QDocForest and
+ QDocDatabase are friends of Tree and have full access.
- The forest is populated as each index file is loaded.
- Each index file adds a tree to the forest. Each tree
- is named with the name of the module it represents.
+ There are two kinds of trees in the forest, differing not
+ in structure but in use. One Tree is the primary tree. It
+ is the tree representing the module being documented. All
+ the other trees in the forest are called index trees. Each
+ one represents the contents of the index file for one of
+ the modules the current module must be able to link to.
+
+ The instances of subclasses of Node in the primary tree
+ will contain documentation in an instance of Doc. The
+ index trees contain no documentation, and each Node in
+ an index tree is marked as an index node.
+
+ Each tree is named with the name of its module.
The search order is created by searchOrder(), if it has
not already been created. The search order and module
names arrays have parallel structure, i.e. modulNames_[i]
is the module name of the Tree at searchOrder_[i].
+
+ The primary tree is always the first tree in the search
+ order. i.e., when the database is searched, the primary
+ tree is always searched first, unless a specific tree is
+ being searched.
*/
/*!
@@ -312,9 +335,9 @@ const Node* QDocForest::findNodeForTarget(QStringList& targetPath,
const Node* n = t->findNodeForTarget(entityPath, target, relative, flags, genus, ref);
if (n)
return n;
- relative = 0;
+ relative = nullptr;
}
- return 0;
+ return nullptr;
}
/*!
@@ -373,58 +396,27 @@ QString QDocForest::getLinkCounts(QStringList& strings, QVector<int>& counts)
}
/*!
- Finds the node for the qualified function path in \a target
- that also has the parameters in \a params and returns it.
- \a target is the path name to the function, without a return
- type and withpout the parameters.
+ Finds the FunctionNode for the qualified function name
+ in \a path, that also has the specified \a parameters.
+ Returns a pointer to the first matching function.
- \a relative is the node in the primary tree where the search
- begins. It is not used in the other trees, if the node is not
- found in the primary tree. \a genus can be used to force the
- search to find a C++ function or a QML function.
-
- The entire forest is searched, but the first match is accepted.
+ \a relative is a node in the primary tree where the search
+ should begin. It is only used when searching the primary
+ tree. \a genus can be used to force the search to find a
+ C++ function or a QML function.
*/
-const FunctionNode* QDocForest::findFunctionNode(const QString& target,
- const QString& params,
+const FunctionNode *QDocForest::findFunctionNode(const QStringList &path,
+ const Parameters &parameters,
const Node* relative,
Node::Genus genus)
{
foreach (Tree* t, searchOrder()) {
- const Node* n = t->findFunctionNode(target, params, relative, genus);
- if (n)
- return static_cast<const FunctionNode *>(n);
- relative = 0;
+ const FunctionNode *fn = t->findFunctionNode(path, parameters, relative, genus);
+ if (fn)
+ return fn;
+ relative = nullptr;
}
- return 0;
-}
-
-/*!
- Finds the node for the qualified function path in \a target
- and returns it. \a target is a complete function signature
- without the return type.
-
- \a relative is the node in the primary tree where the search
- begins. It is not used in the other trees, if the node is not
- found in the primary tree. \a genus can be used to force the
- search to find a C++ function or a QML function.
-
- The entire forest is searched, but the first match is accepted.
- */
-const Node* QDocForest::findFunctionNode(const QString& target,
- const Node* relative,
- Node::Genus genus)
-{
- QString function, params;
- int length = target.length();
- if (target.endsWith(QChar(')'))) {
- int position = target.lastIndexOf(QChar('('));
- params = target.mid(position+1, length-position-2);
- function = target.left(position);
- }
- else
- function = target;
- return findFunctionNode(function, params, relative, genus);
+ return nullptr;
}
/*! \class QDocDatabase
@@ -435,6 +427,17 @@ const Node* QDocForest::findFunctionNode(const QString& target,
QDocDatabase* QDocDatabase::qdocDB_ = NULL;
NodeMap QDocDatabase::typeNodeMap_;
+NodeMultiMap QDocDatabase::obsoleteClasses_;
+NodeMultiMap QDocDatabase::classesWithObsoleteMembers_;
+NodeMultiMap QDocDatabase::obsoleteQmlTypes_;
+NodeMultiMap QDocDatabase::qmlTypesWithObsoleteMembers_;
+NodeMultiMap QDocDatabase::cppClasses_;
+NodeMultiMap QDocDatabase::qmlBasicTypes_;
+NodeMultiMap QDocDatabase::qmlTypes_;
+NodeMultiMap QDocDatabase::examples_;
+NodeMapMap QDocDatabase::newClassMaps_;
+NodeMapMap QDocDatabase::newQmlTypeMaps_;
+NodeMultiMapMap QDocDatabase::newSinceMaps_;
/*!
Constructs the singleton qdoc database object. The singleton
@@ -895,7 +898,7 @@ void QDocDatabase::processForest(void (QDocDatabase::*func) (Aggregate*))
/*!
Constructs the collection of legalese texts, if it has not
- already been constructed and returns a reference to it.
+ already been constructed, and returns a reference to it.
*/
TextToNodeMap& QDocDatabase::getLegaleseTexts()
{
@@ -1018,98 +1021,14 @@ NodeMultiMap& QDocDatabase::getCppClasses()
}
/*!
- Finds all the C++ class nodes and QML type nodes and
- sorts them into maps.
- */
-void QDocDatabase::findAllClasses(Aggregate* node)
-{
- NodeList::const_iterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if ((*c)->access() != Node::Private && (!(*c)->isInternal() || showInternal_) &&
- (*c)->tree()->camelCaseModuleName() != QString("QDoc")) {
- if ((*c)->isClass()) {
- QString className = (*c)->name();
- if ((*c)->parent() &&
- (*c)->parent()->nodeType() == Node::Namespace &&
- !(*c)->parent()->name().isEmpty())
- className = (*c)->parent()->name()+"::"+className;
-
- cppClasses_.insert(className.toLower(), *c);
- }
- else if ((*c)->isQmlType() || (*c)->isQmlBasicType() ||
- (*c)->isJsType() || (*c)->isJsBasicType()) {
- QString qmlTypeName = (*c)->name().toLower();
- if (qmlTypeName.startsWith(QLatin1String("QML:"), Qt::CaseInsensitive))
- qmlTypes_.insert(qmlTypeName.mid(4),*c);
- else
- qmlTypes_.insert(qmlTypeName,*c);
-
- //also add to the QML basic type map
- if ((*c)->isQmlBasicType() || (*c)->isJsBasicType())
- qmlBasicTypes_.insert(qmlTypeName,*c);
- }
- else if ((*c)->isExample()) {
- // use the module index title as key for the example map
- QString title = (*c)->tree()->indexTitle();
- if (!examples_.contains(title, *c))
- examples_.insert(title, *c);
- }
- else if ((*c)->isAggregate()) {
- findAllClasses(static_cast<Aggregate*>(*c));
- }
- }
- ++c;
- }
-}
-
-/*!
Construct the function index data structure and return it.
This data structure is used to output the function index page.
*/
NodeMapMap& QDocDatabase::getFunctionIndex()
{
- processForest(&QDocDatabase::findAllFunctions);
- return funcIndex_;
-}
-
-/*!
- Finds all the function nodes
- */
-void QDocDatabase::findAllFunctions(Aggregate* node)
-{
- NodeList::ConstIterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if ((*c)->access() != Node::Private) {
- if ((*c)->isAggregate()) {
- findAllFunctions(static_cast<Aggregate*>(*c));
- }
- else if ((*c)->nodeType() == Node::Function) {
- const FunctionNode* func = static_cast<const FunctionNode*>(*c);
- if ((func->status() > Node::Obsolete) && !func->isInternal() &&
- !func->isSomeCtor() && !func->isDtor()) {
- funcIndex_[(*c)->name()].insert((*c)->parent()->fullDocumentName(), *c);
- }
- }
- }
- ++c;
- }
-}
-
-/*!
- Finds all the attribution pages and collects them per module
- */
-void QDocDatabase::findAllAttributions(Aggregate* node)
-{
- NodeList::ConstIterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if ((*c)->access() != Node::Private) {
- if ((*c)->pageType() == Node::AttributionPage)
- attributions_.insertMulti((*c)->tree()->indexTitle(), *c);
- else if ((*c)->isAggregate())
- findAllAttributions(static_cast<Aggregate*>(*c));
- }
- ++c;
- }
+ if (functionIndex_.isEmpty())
+ processForest(&QDocDatabase::findAllFunctions);
+ return functionIndex_;
}
/*!
@@ -1118,9 +1037,9 @@ void QDocDatabase::findAllAttributions(Aggregate* node)
*/
void QDocDatabase::findAllLegaleseTexts(Aggregate* node)
{
- NodeList::ConstIterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if ((*c)->access() != Node::Private) {
+ NodeList::ConstIterator c = node->constBegin();
+ while (c != node->constEnd()) {
+ if (!(*c)->isPrivate()) {
if (!(*c)->doc().legaleseText().isEmpty())
legaleseTexts_.insertMulti((*c)->doc().legaleseText(), *c);
if ((*c)->isAggregate())
@@ -1131,189 +1050,23 @@ void QDocDatabase::findAllLegaleseTexts(Aggregate* node)
}
/*!
- Finds all the namespace nodes in the tree beginning at
- \a node and puts them in a map to be used later as an
- index.
+ \fn void QDocDatabase::findAllObsoleteThings(Aggregate *node)
- Ensure each namespace node has a name before inserting
- it into the map, because the root namespace node has no
- name, and we are not interested in it.
- */
-void QDocDatabase::findAllNamespaces(Aggregate* node)
-{
- foreach (Node* n, node->childNodes()) {
- if (n->isNamespace() && !n->name().isEmpty())
- nmm_.insert(n->name(), n);
- if (n->isNamespace() || (n->isAggregate() && n->access() != Node::Private))
- findAllNamespaces(static_cast<Aggregate *>(n));
- }
-}
-
-/*!
Finds all nodes with status = Obsolete and sorts them into
maps. They can be C++ classes, QML types, or they can be
functions, enum types, typedefs, methods, etc.
*/
-void QDocDatabase::findAllObsoleteThings(Aggregate* node)
-{
- NodeList::const_iterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if (!(*c)->isPrivate()) {
- QString name = (*c)->name();
- if ((*c)->isObsolete()) {
- if ((*c)->isClass()) {
- Node* parent = (*c)->parent();
- if (parent && parent->isNamespace() && !parent->name().isEmpty())
- name = parent->name() + "::" + name;
- obsoleteClasses_.insert(name, *c);
- }
- else if ((*c)->isQmlType() || (*c)->isJsType()) {
- if (name.startsWith(QLatin1String("QML:")))
- name = name.mid(4);
- name = (*c)->logicalModuleName() + "::" + name;
- obsoleteQmlTypes_.insert(name,*c);
- }
- }
- else if ((*c)->isClass()) { //not obsolete
- Aggregate* n = static_cast<Aggregate*>(*c);
- bool inserted = false;
- NodeList::const_iterator p = n->childNodes().constBegin();
- while (p != n->childNodes().constEnd()) {
- if (!(*p)->isPrivate() && (*p)->isObsolete()) {
- switch ((*p)->nodeType()) {
- case Node::Enum:
- case Node::Typedef:
- case Node::Function:
- case Node::Property:
- case Node::Variable: {
- Node* parent = (*c)->parent();
- if (parent && parent->isNamespace() && !parent->name().isEmpty())
- name = (*c)->parent()->name() + "::" + name;
- classesWithObsoleteMembers_.insert(name, *c);
- inserted = true;
- break;
- }
- default:
- break;
- }
- }
- if (inserted)
- break;
- ++p;
- }
- }
- else if ((*c)->isQmlType() || (*c)->isJsType()) {
- Aggregate* n = static_cast<Aggregate*>(*c);
- bool inserted = false;
- NodeList::const_iterator p = n->childNodes().constBegin();
- while (p != n->childNodes().constEnd()) {
- if (!(*p)->isPrivate() && (*p)->isObsolete()) {
- switch ((*p)->nodeType()) {
- case Node::JsProperty:
- case Node::QmlProperty:
- case Node::Function:
- if ((*c)->parent()) {
- Node* parent = (*c)->parent();
- if ((parent->isQmlPropertyGroup() || parent->isJsPropertyGroup()) && parent->parent())
- parent = parent->parent();
- if (parent && (parent->isQmlType() || parent->isJsType()) && !parent->name().isEmpty())
- name = parent->name() + "::" + name;
- }
- qmlTypesWithObsoleteMembers_.insert(name,*c);
- inserted = true;
- break;
- default:
- break;
- }
- }
- if (inserted)
- break;
- ++p;
- }
- }
- else if ((*c)->isAggregate()) {
- findAllObsoleteThings(static_cast<Aggregate*>(*c));
- }
- }
- ++c;
- }
-}
/*!
- Finds all the nodes where a \e{since} command appeared in the
- qdoc comment and sorts them into maps according to the kind of
- node.
+ \fn void QDocDatabase::findAllSince(Aggregate *node)
+
+ Finds all the nodes in \a node where a \e{since} command appeared
+ in the qdoc comment and sorts them into maps according to the kind
+ of node.
This function is used for generating the "New Classes... in x.y"
section on the \e{What's New in Qt x.y} page.
*/
-void QDocDatabase::findAllSince(Aggregate* node)
-{
- NodeList::const_iterator child = node->childNodes().constBegin();
- while (child != node->childNodes().constEnd()) {
- QString sinceString = (*child)->since();
- // Insert a new entry into each map for each new since string found.
- if (((*child)->access() != Node::Private) && !sinceString.isEmpty()) {
- NodeMultiMapMap::iterator nsmap = newSinceMaps_.find(sinceString);
- if (nsmap == newSinceMaps_.end())
- nsmap = newSinceMaps_.insert(sinceString,NodeMultiMap());
-
- NodeMapMap::iterator ncmap = newClassMaps_.find(sinceString);
- if (ncmap == newClassMaps_.end())
- ncmap = newClassMaps_.insert(sinceString,NodeMap());
-
- NodeMapMap::iterator nqcmap = newQmlTypeMaps_.find(sinceString);
- if (nqcmap == newQmlTypeMaps_.end())
- nqcmap = newQmlTypeMaps_.insert(sinceString,NodeMap());
-
- if ((*child)->nodeType() == Node::Function) {
- // Insert functions into the general since map.
- FunctionNode *func = static_cast<FunctionNode *>(*child);
- if ((func->status() > Node::Obsolete) && !func->isSomeCtor() && !func->isDtor()) {
- nsmap.value().insert(func->name(),(*child));
- }
- }
- else {
- if ((*child)->nodeType() == Node::Class) {
- // Insert classes into the since and class maps.
- QString className = (*child)->name();
- if ((*child)->parent() && !(*child)->parent()->name().isEmpty()) {
- className = (*child)->parent()->name()+"::"+className;
- }
- nsmap.value().insert(className,(*child));
- ncmap.value().insert(className,(*child));
- }
- else if ((*child)->isQmlType() || (*child)->isJsType()) {
- // Insert QML elements into the since and element maps.
- QString className = (*child)->name();
- if ((*child)->parent() && !(*child)->parent()->name().isEmpty()) {
- className = (*child)->parent()->name()+"::"+className;
- }
- nsmap.value().insert(className,(*child));
- nqcmap.value().insert(className,(*child));
- }
- else if ((*child)->isQmlProperty() || (*child)->isJsProperty()) {
- // Insert QML properties into the since map.
- QString propertyName = (*child)->name();
- nsmap.value().insert(propertyName,(*child));
- }
- else {
- // Insert external documents into the general since map.
- QString name = (*child)->name();
- if ((*child)->parent() && !(*child)->parent()->name().isEmpty()) {
- name = (*child)->parent()->name()+"::"+name;
- }
- nsmap.value().insert(name,(*child));
- }
- }
- }
- // Recursively find child nodes with since commands.
- if ((*child)->isAggregate())
- findAllSince(static_cast<Aggregate *>(*child));
-
- ++child;
- }
-}
/*!
Find the \a key in the map of new class maps, and return a
@@ -1361,61 +1114,73 @@ const NodeMap& QDocDatabase::getSinceMap(const QString& key)
}
/*!
- Performs several housekeeping algorithms that create
- certain data structures and resolve lots of links, prior
- to generating documentation.
- */
-void QDocDatabase::resolveIssues() {
- primaryTreeRoot()->normalizeOverloads();
- fixInheritance();
- resolveProperties();
- primaryTreeRoot()->makeUndocumentedChildrenInternal();
- resolveQmlInheritance(primaryTreeRoot());
- primaryTree()->resolveTargets(primaryTreeRoot());
- primaryTree()->resolveCppToQmlLinks();
- if (!Generator::singleExec()) {
- QDocIndexFiles::qdocIndexFiles()->resolveRelates();
- QDocIndexFiles::destroyQDocIndexFiles();
+ Performs several housekeeping tasks prior to generating the
+ documentation. These tasks create required data structures
+ and resolve links.
+ */
+void QDocDatabase::resolveStuff() {
+ if (Generator::dualExec() || Generator::preparing()) {
+ primaryTree()->resolveInheritance(primaryTreeRoot());
+ primaryTreeRoot()->normalizeOverloads();
+ primaryTree()->fixInheritance(primaryTreeRoot());
+ primaryTree()->resolveProperties();
+ primaryTreeRoot()->markUndocumentedChildrenInternal();
+ primaryTreeRoot()->resolveQmlInheritance();
+ primaryTree()->resolveTargets(primaryTreeRoot());
+ primaryTree()->resolveCppToQmlLinks();
+ primaryTree()->resolveUsingClauses();
}
- if (Generator::generating())
+ if (Generator::singleExec() && Generator::generating()) {
+ primaryTree()->resolveInheritance(primaryTreeRoot());
+ primaryTreeRoot()->resolveQmlInheritance();
+ //primaryTree()->resolveTargets(primaryTreeRoot());
+ primaryTree()->resolveCppToQmlLinks();
+ primaryTree()->resolveUsingClauses();
+ }
+ if (Generator::generating()) {
resolveNamespaces();
+ resolveProxies();
+ }
+ if (Generator::dualExec())
+ QDocIndexFiles::destroyQDocIndexFiles();
}
-void QDocDatabase::resolveStuff()
+/*!
+ Returns a reference to the namespace map. Constructs the
+ namespace map if it hasn't been constructed yet.
+ */
+NodeMultiMap &QDocDatabase::getNamespaces()
{
- primaryTree()->resolveInheritance();
- resolveQmlInheritance(primaryTreeRoot());
- //primaryTree()->resolveTargets(primaryTreeRoot());
- primaryTree()->resolveCppToQmlLinks();
- primaryTree()->resolveUsingClauses();
resolveNamespaces();
+ return namespaceIndex_;
}
/*!
- Multiple namespace nodes for a particular namespace can be
- created in multiple places. This function first finds all
- namespace nodes and inserts them into a multimap. Then it
- combines all the namespace nodes with the same name into a
- single node and inserts that combined namespace node into
- a namespace index.
+ Multiple namespace nodes for namespace X can exist in the
+ qdoc database in different trees. This function first finds
+ all namespace nodes in all the trees and inserts them into
+ a multimap. Then it combines all the namespace nodes that
+ have the same name into a single namespace node of that
+ name and inserts that combined namespace node into an index.
*/
void QDocDatabase::resolveNamespaces()
{
if (!namespaceIndex_.isEmpty())
return;
+ NodeMultiMap namespaceMultimap;
Tree* t = forest_.firstTree();
while (t) {
- findAllNamespaces(t->root());
+ t->root()->findAllNamespaces(namespaceMultimap);
t = forest_.nextTree();
}
- QList<QString> keys = nmm_.uniqueKeys();
+ QList<QString> keys = namespaceMultimap.uniqueKeys();
foreach (const QString &s, keys) {
NamespaceNode* ns = 0;
NamespaceNode* somewhere = 0;
- QList<Node*> nodes = nmm_.values(s);
- int count = nmm_.remove(s);
+ NodeList namespaces = namespaceMultimap.values(s);
+ int count = namespaceMultimap.remove(s);
if (count > 0) {
- foreach (Node* n, nodes) {
+ foreach (Node *n, namespaces) {
ns = static_cast<NamespaceNode*>(n);
if (ns->isDocumentedHere())
break;
@@ -1424,49 +1189,122 @@ void QDocDatabase::resolveNamespaces()
ns = 0;
}
if (ns) {
- foreach (Node* n, nodes) {
+ foreach (Node *n, namespaces) {
NamespaceNode* NS = static_cast<NamespaceNode*>(n);
if (NS->wasDocumented() && NS != ns) {
- ns->doc().location().warning(tr("Namespace %1 documented more than once").arg(NS->name()));
+ ns->doc().location().warning(tr("Namespace %1 documented more than once")
+ .arg(NS->name()));
NS->doc().location().warning(tr("...also seen here"));
}
}
} else if (somewhere == 0) {
- foreach (Node* n, nodes) {
+ foreach (Node *n, namespaces) {
NamespaceNode* NS = static_cast<NamespaceNode*>(n);
NS->reportDocumentedChildrenInUndocumentedNamespace();
}
}
if (somewhere) {
- foreach (Node* n, nodes) {
+ foreach (Node *n, namespaces) {
NamespaceNode* NS = static_cast<NamespaceNode*>(n);
if (NS != somewhere)
NS->setDocNode(somewhere);
}
}
}
+ /*
+ If there are multiple namespace nodes with the same
+ name and one of them will be the reference page for
+ the namespace, include all the nodes in the public
+ API of the namespace in the single namespace node
+ that will generate the namespace reference page for
+ the namespace.
+ */
if (ns && count > 1) {
- foreach (Node* n, nodes) {
+ foreach (Node *n, namespaces) {
NamespaceNode* NS = static_cast<NamespaceNode*>(n);
- if ((NS != ns) && !NS->childNodes().isEmpty()) {
- const NodeList& children = NS->childNodes();
- int i = children.size() - 1;
- while (i >= 0) {
- Node* child = children.at(i--);
- if (child && child->isPublic() && !child->isInternal())
- ns->addOrphan(child);
+ if (NS != ns) {
+ NodeList::ConstIterator c = NS->constBegin();
+ while (c != NS->constEnd()) {
+ Node *N = *c;
+ if (N && N->isPublic() && !N->isInternal())
+ ns->includeChild(N);
+ ++c;
}
}
}
}
if (ns == 0)
- ns = static_cast<NamespaceNode*>(nodes.at(0));
+ ns = static_cast<NamespaceNode*>(namespaces.at(0));
namespaceIndex_.insert(ns->name(), ns);
}
}
/*!
+ Each instance of class Tree that represents an index file
+ must be traversed to find all instances of class ProxyNode.
+ For each ProxyNode found, look up the ProxyNode's name in
+ the primary Tree. If it is found, it means that the proxy
+ node contains elements (normally just functions) that are
+ documented in the module represented by the Tree containing
+ the proxy node but that are related to the node we found in
+ the primary tree.
+ */
+void QDocDatabase::resolveProxies()
+{
+ // The first tree is the primary tree.
+ // Skip the primary tree.
+ Tree *t = forest_.firstTree();
+ t = forest_.nextTree();
+ while (t) {
+ NodeList &proxies = t->proxies();
+ if (!proxies.isEmpty()) {
+ foreach (Node *n, proxies) {
+ ProxyNode *pn = static_cast<ProxyNode*>(n);
+ if (pn->count() > 0) {
+ Aggregate *aggregate = primaryTree()->findAggregate(pn->name());
+ if (aggregate != nullptr)
+ aggregate->appendToRelatedByProxy(pn->childNodes());
+ }
+ }
+ }
+ t = forest_.nextTree();
+ }
+}
+
+
+/*!
+ Finds the function node for the qualified function path in
+ \a target and returns a pointer to it. The \a target is a
+ function signature with or without parameters but without
+ the return type.
+
+ \a relative is the node in the primary tree where the search
+ begins. It is not used in the other trees, if the node is not
+ found in the primary tree. \a genus can be used to force the
+ search to find a C++ function or a QML function.
+
+ The entire forest is searched, but the first match is accepted.
+ */
+const FunctionNode *QDocDatabase::findFunctionNode(const QString &target,
+ const Node *relative,
+ Node::Genus genus)
+{
+ QString signature;
+ QString function = target;
+ int length = target.length();
+ if (function.endsWith("()"))
+ function.chop(2);
+ if (function.endsWith(QChar(')'))) {
+ int position = function.lastIndexOf(QChar('('));
+ signature = function.mid(position + 1, length - position - 2);
+ function = function.left(position);
+ }
+ QStringList path = function.split("::");
+ return forest_.findFunctionNode(path, Parameters(signature), relative, genus);
+}
+
+/*!
This function is called for autolinking to a \a type,
which could be a function return type or a parameter
type. The tree node that represents the \a type is
@@ -1515,58 +1353,6 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
}
/*!
- For each QML Type node in the tree beginning at \a root,
- if it has a QML base type name but its QML base type node
- pointer is 0, use the QML base type name to look up the
- base type node. If the node is found in the tree, set the
- node's QML base type node pointer.
- */
-void QDocDatabase::resolveQmlInheritance(Aggregate* root)
-{
- NodeMap previousSearches;
- // Do we need recursion?
- foreach (Node* child, root->childNodes()) {
- if (child->isQmlType() || child->isJsType()) {
- 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)) {
- 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->logicalModuleVersion()[0] != imports[i].version_[0])
- bqcn = 0; // Safeguard for QTBUG-53529
- break;
- }
- }
- }
- if (bqcn == 0) {
- bqcn = findQmlType(QString(), qcn->qmlBaseName());
- }
- if (bqcn && (bqcn != qcn)) {
- qcn->setQmlBaseNode(bqcn);
- QmlTypeNode::addInheritedBy(bqcn, qcn);
- previousSearches.insert(qcn->qmlBaseName(), bqcn);
- }
-#if 0
- else {
- qDebug() << "Temporary error message (ignore): UNABLE to resolve QML base type:"
- << qcn->qmlBaseName() << "for QML type:" << qcn->name();
- }
-#endif
- }
- }
- }
- }
-}
-
-/*!
Generates a tag file and writes it to \a name.
*/
void QDocDatabase::generateTagFile(const QString& name, Generator* g)
@@ -1595,49 +1381,18 @@ void QDocDatabase::readIndexes(const QStringList& t)
/*!
Generates a qdoc index file and write it to \a fileName. The
- index file is generated with the parameters \a url, \a title,
- \a g, and \a generateInternalNodes.
- */
-void QDocDatabase::generateIndex(const QString& fileName,
- const QString& url,
- const QString& title,
- Generator* g,
- bool generateInternalNodes)
+ index file is generated with the parameters \a url and \a title,
+ using the generator \a g.
+ */
+void QDocDatabase::generateIndex(const QString &fileName, const QString &url, const QString &title, Generator *g)
{
QString t = fileName.mid(fileName.lastIndexOf(QChar('/'))+1);
primaryTree()->setIndexFileName(t);
- QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, g, generateInternalNodes);
+ QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, g);
QDocIndexFiles::destroyQDocIndexFiles();
}
/*!
- If there are open namespaces, search for the function node
- having the same function name as the \a clone node in each
- open namespace. The \a parentPath is a portion of the path
- name provided with the function name at the point of
- reference. \a parentPath is usually a class name. Return
- the pointer to the function node if one is found in an
- open namespace. Otherwise return 0.
-
- This open namespace concept is of dubious value and might
- be removed.
- */
-FunctionNode* QDocDatabase::findNodeInOpenNamespace(const QStringList& parentPath,
- const FunctionNode* clone)
-{
- FunctionNode* fn = 0;
- if (!openNamespaces_.isEmpty()) {
- foreach (const QString& t, openNamespaces_) {
- QStringList path = t.split("::") + parentPath;
- fn = findFunctionNode(path, clone);
- if (fn)
- break;
- }
- }
- return fn;
-}
-
-/*!
Find a node of the specified \a type that is reached with
the specified \a path qualified with the name of one of the
open namespaces (might not be any open ones). If the node
@@ -1787,12 +1542,18 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
if (first.endsWith(".html"))
node = domain->findNodeByNameAndType(QStringList(first), Node::Page);
else if (first.endsWith(QChar(')'))) {
- QString function, params;
+ QString signature;
+ QString function = first;
int length = first.length();
- int position = first.lastIndexOf(QChar('('));
- params = first.mid(position+1, length-position-2);
- function = first.left(position);
- node = domain->findFunctionNode(function, params, 0, genus);
+ if (function.endsWith("()"))
+ function.chop(2);
+ if (function.endsWith(QChar(')'))) {
+ int position = function.lastIndexOf(QChar('('));
+ signature = function.mid(position + 1, length - position - 2);
+ function = function.left(position);
+ }
+ QStringList path = function.split("::");
+ node = domain->findFunctionNode(path, Parameters(signature), nullptr, genus);
}
if (!node) {
int flags = SearchBaseClasses | SearchEnumValues;
@@ -1809,9 +1570,8 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
else {
if (first.endsWith(".html"))
node = findNodeByNameAndType(QStringList(first), Node::Page);
- else if (first.endsWith(QChar(')'))) {
+ else if (first.endsWith(QChar(')')))
node = findFunctionNode(first, relative, genus);
- }
if (!node)
return findNodeForTarget(targetPath, relative, genus, ref);
}
diff --git a/src/qdoc/qdocdatabase.h b/src/qdoc/qdocdatabase.h
index deb554abe..8d9899042 100644
--- a/src/qdoc/qdocdatabase.h
+++ b/src/qdoc/qdocdatabase.h
@@ -38,11 +38,7 @@
QT_BEGIN_NAMESPACE
-typedef QMap<QString, NodeMap> NodeMapMap;
-typedef QMap<QString, NodeMultiMap> NodeMultiMapMap;
-typedef QMultiMap<QString, Node*> QDocMultiMap;
typedef QMap<Text, const Node*> TextToNodeMap;
-typedef QList<CollectionNode*> CollectionList;
class Atom;
class Generator;
@@ -57,7 +53,7 @@ enum FindFlag {
class QDocForest
{
- public:
+ private:
friend class QDocDatabase;
QDocForest(QDocDatabase* qdb)
: qdb_(qdb), primaryTree_(0), currentIndex_(0) { }
@@ -126,20 +122,8 @@ class QDocForest
return 0;
}
- PageNode* findRelatesNode(const QStringList& path) {
- foreach (Tree* t, searchOrder()) {
- PageNode* n = t->findRelatesNode(path);
- if (n)
- return n;
- }
- return 0;
- }
-
- const Node* findFunctionNode(const QString& target,
- const Node* relative,
- Node::Genus genus);
- const FunctionNode* findFunctionNode(const QString& target,
- const QString& params,
+ const FunctionNode *findFunctionNode(const QStringList &path,
+ const Parameters &parameters,
const Node* relative,
Node::Genus genus);
const Node* findNodeForTarget(QStringList& targetPath,
@@ -208,8 +192,6 @@ class QDocForest
}
void printLinkCounts(const QString& project);
QString getLinkCounts(QStringList& strings, QVector<int>& counts);
-
- private:
void newPrimaryTree(const QString& module);
void setPrimaryTree(const QString& t);
NamespaceNode* newIndexTree(const QString& module);
@@ -266,14 +248,25 @@ class QDocDatabase
QmlTypeNode* findQmlType(const ImportRec& import, const QString& name);
Aggregate* findQmlBasicType(const QString& qmid, const QString& name);
+ static NodeMultiMap &obsoleteClasses() { return obsoleteClasses_; }
+ static NodeMultiMap &obsoleteQmlTypes() { return obsoleteQmlTypes_; }
+ static NodeMultiMap &classesWithObsoleteMembers() { return classesWithObsoleteMembers_; }
+ static NodeMultiMap &qmlTypesWithObsoleteMembers() { return qmlTypesWithObsoleteMembers_; }
+ static NodeMultiMap &cppClasses() { return cppClasses_; }
+ static NodeMultiMap &qmlBasicTypes() { return qmlBasicTypes_; }
+ static NodeMultiMap &qmlTypes() { return qmlTypes_; }
+ static NodeMultiMap &examples() { return examples_; }
+ static NodeMapMap &newClassMaps() { return newClassMaps_; }
+ static NodeMapMap &newQmlTypeMaps() { return newQmlTypeMaps_; }
+ static NodeMultiMapMap &newSinceMaps() { return newSinceMaps_; }
+
private:
- void findAllClasses(Aggregate *node);
- void findAllFunctions(Aggregate *node);
- void findAllAttributions(Aggregate *node);
+ void findAllClasses(Aggregate *node) { node->findAllClasses(); }
+ void findAllFunctions(Aggregate *node) { node->findAllFunctions(functionIndex_); }
+ void findAllAttributions(Aggregate *node) { node->findAllAttributions(attributions_); }
void findAllLegaleseTexts(Aggregate *node);
- void findAllNamespaces(Aggregate *node);
- void findAllObsoleteThings(Aggregate* node);
- void findAllSince(Aggregate *node);
+ void findAllObsoleteThings(Aggregate *node) { node->findAllObsoleteThings(); }
+ void findAllSince(Aggregate *node) { node->findAllSince(); }
public:
/*******************************************************************
@@ -284,7 +277,7 @@ class QDocDatabase
NodeMultiMap& getClassesWithObsoleteMembers();
NodeMultiMap& getObsoleteQmlTypes();
NodeMultiMap& getQmlTypesWithObsoleteMembers();
- NodeMultiMap& getNamespaces() { resolveNamespaces(); return namespaceIndex_; }
+ NodeMultiMap& getNamespaces();
NodeMultiMap& getQmlBasicTypes();
NodeMultiMap& getQmlTypes();
NodeMultiMap& getExamples();
@@ -298,13 +291,7 @@ class QDocDatabase
/*******************************************************************
Many of these will be either eliminated or replaced.
********************************************************************/
- void resolveInheritance() { primaryTree()->resolveInheritance(); }
- void resolveQmlInheritance(Aggregate* root);
- void resolveIssues();
void resolveStuff();
- void fixInheritance() { primaryTree()->fixInheritance(); }
- void resolveProperties() { primaryTree()->resolveProperties(); }
-
void insertTarget(const QString& name,
const QString& title,
TargetRec::TargetType type,
@@ -316,19 +303,13 @@ class QDocDatabase
/*******************************************************************
The functions declared below are called for the current tree only.
********************************************************************/
- FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) {
- return primaryTree()->findFunctionNode(parentPath, clone);
- }
- FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
+ Aggregate *findRelatesNode(const QStringList &path) { return primaryTree()->findRelatesNode(path); }
Node* findNodeInOpenNamespace(QStringList& path, Node::NodeType type);
- const Node* checkForCollision(const QString& name) {
- return primaryTree()->checkForCollision(name);
- }
/*******************************************************************/
- /*******************************************************************
- The functions declared below handle the parameters in '[' ']'.
- ********************************************************************/
+ /*****************************************************************************
+ This function can handle parameters enclosed in '[' ']' (domanin and genus).
+ ******************************************************************************/
const Node* findNodeForAtom(const Atom* atom, const Node* relative, QString& ref);
/*******************************************************************/
@@ -337,16 +318,7 @@ class QDocDatabase
********************************************************************/
ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
Node* findNodeForInclude(const QStringList& path) { return forest_.findNodeForInclude(path); }
- PageNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
- const Node* findFunctionNode(const QString& target, const Node* relative, Node::Genus genus) {
- return forest_.findFunctionNode(target, relative, genus);
- }
- const FunctionNode* findFunctionNode(const QString& target,
- const QString& params,
- const Node* relative,
- Node::Genus genus) {
- return forest_.findFunctionNode(target, params, relative, genus);
- }
+ const FunctionNode *findFunctionNode(const QString &target, const Node *relative, Node::Genus genus);
const Node* findTypeNode(const QString& type, const Node* relative, Node::Genus genus);
const Node* findNodeForTarget(const QString& target, const Node* relative);
const PageNode* findPageNodeByTitle(const QString& title) {
@@ -358,8 +330,8 @@ class QDocDatabase
const CollectionNode* getCollectionNode(const QString& name, Node::NodeType type) {
return forest_.getCollectionNode(name, type);
}
- Node *findFunctionNodeForTag(QString tag) { return primaryTree()->findFunctionNodeForTag(tag); }
- Node* findMacroNode(const QString &t) { return primaryTree()->findMacroNode(t); }
+ FunctionNode *findFunctionNodeForTag(QString tag) { return primaryTree()->findFunctionNodeForTag(tag); }
+ FunctionNode *findMacroNode(const QString &t) { return primaryTree()->findMacroNode(t); }
private:
const Node* findNodeForTarget(QStringList& targetPath,
@@ -368,6 +340,12 @@ class QDocDatabase
QString& ref) {
return forest_.findNodeForTarget(targetPath, relative, genus, ref);
}
+ const FunctionNode *findFunctionNode(const QStringList &path,
+ const Parameters &parameters,
+ const Node *relative,
+ Node::Genus genus) {
+ return forest_.findFunctionNode(path, parameters, relative, genus);
+ }
/*******************************************************************/
public:
@@ -382,11 +360,7 @@ class QDocDatabase
void generateTagFile(const QString& name, Generator* g);
void readIndexes(const QStringList& indexFiles);
- void generateIndex(const QString& fileName,
- const QString& url,
- const QString& title,
- Generator* g,
- bool generateInternalNodes = false);
+ void generateIndex(const QString &fileName, const QString &url, const QString &title, Generator *g);
void clearOpenNamespaces() { openNamespaces_.clear(); }
void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); }
@@ -424,10 +398,10 @@ class QDocDatabase
QStringList getTargetListKeys() { return primaryTree()->getTargetListKeys(); }
QStringList keys() { return forest_.keys(); }
void resolveNamespaces();
+ void resolveProxies();
private:
- friend class QDocIndexFiles;
- friend class QDocTagFiles;
+ friend class Tree;
const Node* findNode(const QStringList& path,
const Node* relative,
@@ -451,26 +425,26 @@ class QDocDatabase
private:
static QDocDatabase* qdocDB_;
static NodeMap typeNodeMap_;
+ static NodeMultiMap obsoleteClasses_;
+ static NodeMultiMap classesWithObsoleteMembers_;
+ static NodeMultiMap obsoleteQmlTypes_;
+ static NodeMultiMap qmlTypesWithObsoleteMembers_;
+ static NodeMultiMap cppClasses_;
+ static NodeMultiMap qmlBasicTypes_;
+ static NodeMultiMap qmlTypes_;
+ static NodeMultiMap examples_;
+ static NodeMapMap newClassMaps_;
+ static NodeMapMap newQmlTypeMaps_;
+ static NodeMultiMapMap newSinceMaps_;
+
bool showInternal_;
bool singleExec_;
QString version_;
QDocForest forest_;
- NodeMultiMap cppClasses_;
- NodeMultiMap obsoleteClasses_;
- NodeMultiMap classesWithObsoleteMembers_;
- NodeMultiMap obsoleteQmlTypes_;
- NodeMultiMap qmlTypesWithObsoleteMembers_;
NodeMultiMap namespaceIndex_;
- NodeMultiMap nmm_;
- NodeMultiMap qmlBasicTypes_;
- NodeMultiMap qmlTypes_;
- NodeMultiMap examples_;
NodeMultiMap attributions_;
- NodeMapMap newClassMaps_;
- NodeMapMap newQmlTypeMaps_;
- NodeMultiMapMap newSinceMaps_;
- NodeMapMap funcIndex_;
+ NodeMapMap functionIndex_;
TextToNodeMap legaleseTexts_;
QSet<QString> openNamespaces_;
};
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index cdba1b548..2b957a439 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -105,7 +105,6 @@ void QDocIndexFiles::destroyQDocIndexFiles()
*/
void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
{
- relatedList_.clear();
foreach (const QString& indexFile, indexFiles) {
QString msg = "Loading index file: " + indexFile;
Location::logToStdErr(msg);
@@ -209,8 +208,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
ns->setDocumented();
}
- }
- else if (elementName == QLatin1String("class")) {
+ } else if (elementName == QLatin1String("class")) {
node = new ClassNode(parent, name);
if (attributes.hasAttribute(QLatin1String("bases"))) {
QString bases = attributes.value(QLatin1String("bases")).toString();
@@ -225,8 +223,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
if (attributes.value(QLatin1String("abstract")) == QLatin1String("true"))
abstract = true;
node->setAbstract(abstract);
- }
- else if (elementName == QLatin1String("header")) {
+ } else if (elementName == QLatin1String("header")) {
node = new HeaderNode(parent, name);
if (attributes.hasAttribute(QLatin1String("location")))
@@ -236,8 +233,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
location = Location(indexUrl + QLatin1Char('/') + name);
else if (!indexUrl.isNull())
location = Location(name);
- }
- else if (elementName == QLatin1String("qmlclass")) {
+ } else if (elementName == QLatin1String("qmlclass")) {
QmlTypeNode* qcn = new QmlTypeNode(parent, name);
qcn->setTitle(attributes.value(QLatin1String("title")).toString());
QString logicalModuleName = attributes.value(QLatin1String("qml-module-name")).toString();
@@ -258,8 +254,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qcn;
- }
- else if (elementName == QLatin1String("jstype")) {
+ } else if (elementName == QLatin1String("jstype")) {
QmlTypeNode* qcn = new QmlTypeNode(parent, name);
qcn->setGenus(Node::JS);
qcn->setTitle(attributes.value(QLatin1String("title")).toString());
@@ -281,8 +276,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qcn;
- }
- else if (elementName == QLatin1String("qmlbasictype")) {
+ } else if (elementName == QLatin1String("qmlbasictype")) {
QmlBasicTypeNode* qbtn = new QmlBasicTypeNode(parent, name);
qbtn->setTitle(attributes.value(QLatin1String("title")).toString());
if (attributes.hasAttribute(QLatin1String("location")))
@@ -292,8 +286,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qbtn;
- }
- else if (elementName == QLatin1String("jsbasictype")) {
+ } else if (elementName == QLatin1String("jsbasictype")) {
QmlBasicTypeNode* qbtn = new QmlBasicTypeNode(parent, name);
qbtn->setGenus(Node::JS);
qbtn->setTitle(attributes.value(QLatin1String("title")).toString());
@@ -304,8 +297,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qbtn;
- }
- else if (elementName == QLatin1String("qmlpropertygroup")) {
+ } else if (elementName == QLatin1String("qmlpropertygroup")) {
QmlTypeNode* qcn = static_cast<QmlTypeNode*>(parent);
QmlPropertyGroupNode* qpgn = new QmlPropertyGroupNode(qcn, name);
if (attributes.hasAttribute(QLatin1String("location")))
@@ -315,8 +307,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qpgn;
- }
- else if (elementName == QLatin1String("jspropertygroup")) {
+ } else if (elementName == QLatin1String("jspropertygroup")) {
QmlTypeNode* qcn = static_cast<QmlTypeNode*>(parent);
QmlPropertyGroupNode* qpgn = new QmlPropertyGroupNode(qcn, name);
qpgn->setGenus(Node::JS);
@@ -327,8 +318,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(name);
node = qpgn;
- }
- else if (elementName == QLatin1String("qmlproperty")) {
+ } else if (elementName == QLatin1String("qmlproperty")) {
QString type = attributes.value(QLatin1String("type")).toString();
bool attached = false;
if (attributes.value(QLatin1String("attached")) == QLatin1String("true"))
@@ -337,10 +327,9 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
if (attributes.value(QLatin1String("writable")) == QLatin1String("false"))
readonly = true;
QmlPropertyNode* qpn = new QmlPropertyNode(parent, name, type, attached);
- qpn->setReadOnly(readonly);
+ qpn->markReadOnly(readonly);
node = qpn;
- }
- else if (elementName == QLatin1String("jsproperty")) {
+ } else if (elementName == QLatin1String("jsproperty")) {
QString type = attributes.value(QLatin1String("type")).toString();
bool attached = false;
if (attributes.value(QLatin1String("attached")) == QLatin1String("true"))
@@ -350,26 +339,23 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
readonly = true;
QmlPropertyNode* qpn = new QmlPropertyNode(parent, name, type, attached);
qpn->setGenus(Node::JS);
- qpn->setReadOnly(readonly);
+ qpn->markReadOnly(readonly);
node = qpn;
- }
- else if (elementName == QLatin1String("group")) {
+ } else if (elementName == QLatin1String("group")) {
CollectionNode* cn = qdb_->addGroup(name);
cn->setTitle(attributes.value(QLatin1String("title")).toString());
cn->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
cn->markSeen();
node = cn;
- }
- else if (elementName == QLatin1String("module")) {
+ } else if (elementName == QLatin1String("module")) {
CollectionNode* cn = qdb_->addModule(name);
cn->setTitle(attributes.value(QLatin1String("title")).toString());
cn->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
cn->markSeen();
node = cn;
- }
- else if (elementName == QLatin1String("qmlmodule")) {
+ } else if (elementName == QLatin1String("qmlmodule")) {
QString t = attributes.value(QLatin1String("qml-module-name")).toString();
CollectionNode* cn = qdb_->addQmlModule(t);
QStringList info;
@@ -380,8 +366,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
cn->markSeen();
node = cn;
- }
- else if (elementName == QLatin1String("jsmodule")) {
+ } else if (elementName == QLatin1String("jsmodule")) {
QString t = attributes.value(QLatin1String("js-module-name")).toString();
CollectionNode* cn = qdb_->addJsModule(t);
QStringList info;
@@ -392,36 +377,29 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
cn->markSeen();
node = cn;
- }
- else if (elementName == QLatin1String("page")) {
+ } else if (elementName == QLatin1String("page")) {
QDocAttr subtype = QDocAttrNone;
Node::PageType ptype = Node::NoPageType;
QString attr = attributes.value(QLatin1String("subtype")).toString();
if (attr == QLatin1String("attribution")) {
subtype = QDocAttrDocument;
ptype = Node::AttributionPage;
- }
- else if (attr == QLatin1String("example")) {
+ } else if (attr == QLatin1String("example")) {
subtype = QDocAttrExample;
ptype = Node::ExamplePage;
- }
- else if (attr == QLatin1String("file")) {
+ } else if (attr == QLatin1String("file")) {
subtype = QDocAttrFile;
ptype = Node::NoPageType;
- }
- else if (attr == QLatin1String("image")) {
+ } else if (attr == QLatin1String("image")) {
subtype = QDocAttrImage;
ptype = Node::NoPageType;
- }
- else if (attr == QLatin1String("page")) {
+ } else if (attr == QLatin1String("page")) {
subtype = QDocAttrDocument;
ptype = Node::ArticlePage;
- }
- else if (attr == QLatin1String("externalpage")) {
+ } else if (attr == QLatin1String("externalpage")) {
subtype = QDocAttrExternalPage;
ptype = Node::ArticlePage;
- }
- else
+ } else
goto done;
if (current && current->isExample()) {
@@ -454,8 +432,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
node = pn;
- }
- else if (elementName == QLatin1String("enum")) {
+ } else if (elementName == QLatin1String("enum")) {
EnumNode* enumNode = new EnumNode(parent, name);
if (!indexUrl.isEmpty())
@@ -480,8 +457,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
node = enumNode;
hasReadChildren = true;
- }
- else if (elementName == QLatin1String("typedef")) {
+ } else if (elementName == QLatin1String("typedef")) {
node = new TypedefNode(parent, name);
if (!indexUrl.isEmpty())
@@ -489,8 +465,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
else if (!indexUrl.isNull())
location = Location(parent->name().toLower() + ".html");
- }
- else if (elementName == QLatin1String("property")) {
+ } else if (elementName == QLatin1String("property")) {
node = new PropertyNode(parent, name);
if (!indexUrl.isEmpty())
@@ -508,12 +483,10 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
attached = true;
FunctionNode* fn = new FunctionNode(metaness, parent, name, attached);
if (fn->isCppNode()) {
- fn->setReturnType(attributes.value(QLatin1String("return")).toString());
+ fn->setReturnType(attributes.value(QLatin1String("type")).toString());
fn->setVirtualness(attributes.value(QLatin1String("virtual")).toString());
fn->setConst(attributes.value(QLatin1String("const")) == QLatin1String("true"));
fn->setStatic(attributes.value(QLatin1String("static")) == QLatin1String("true"));
- fn->setIsDeleted(attributes.value(QLatin1String("delete")) == QLatin1String("true"));
- fn->setIsDefaulted(attributes.value(QLatin1String("default")) == QLatin1String("true"));
fn->setFinal(attributes.value(QLatin1String("final")) == QLatin1String("true"));
fn->setOverride(attributes.value(QLatin1String("override")) == QLatin1String("true"));
int refness = attributes.value(QLatin1String("refness")).toUInt();
@@ -521,32 +494,31 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
fn->setRef(true);
else if (refness == 2)
fn->setRefRef(true);
- if (attributes.value(QLatin1String("overload")) == QLatin1String("true")) {
- fn->setOverloadFlag(true);
+ /*
+ Theoretically, this should ensure that each function
+ node receives the same overload number and overload
+ flag it was written with, and it should be unnecessary
+ to call normalizeOverloads() for index nodes.
+ */
+ if (attributes.value(QLatin1String("overload")) == QLatin1String("true"))
fn->setOverloadNumber(attributes.value(QLatin1String("overload-number")).toUInt());
- }
- else {
- fn->setOverloadFlag(false);
+ else
fn->setOverloadNumber(0);
- }
- if (attributes.hasAttribute(QLatin1String("relates"))) {
- QString relatesName = attributes.value(QLatin1String("relates")).toString();
- if (relatesName != parent->name())
- relatedList_.append(QPair<FunctionNode*, QString>(fn, relatesName));
- }
/*
Note: The "signature" attribute was written to the
- index file, but it is not read back in. Is that ok?
+ index file, but it is not read back in. That is ok
+ because we reconstruct the parameter list and the
+ return type, from which the signature was built in
+ the first place and from which it can be rebuilt.
*/
while (reader.readNextStartElement()) {
QXmlStreamAttributes childAttributes = reader.attributes();
if (reader.name() == QLatin1String("parameter")) {
// Do not use the default value for the parameter; it is not
// required, and has been known to cause problems.
- Parameter parameter(childAttributes.value(QLatin1String("type")).toString(),
- childAttributes.value(QLatin1String("name")).toString(),
- QString()); // childAttributes.value(QLatin1String("default"))
- fn->addParameter(parameter);
+ QString type = childAttributes.value(QLatin1String("type")).toString();
+ QString name = childAttributes.value(QLatin1String("name")).toString();
+ fn->parameters().append(type, name);
} else if (reader.name() == QLatin1String("keyword")) {
insertTarget(TargetRec::Keyword, childAttributes, fn);
} else if (reader.name() == QLatin1String("target")) {
@@ -563,28 +535,30 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
location = Location(parent->name().toLower() + ".html");
hasReadChildren = true;
- }
- else if (elementName == QLatin1String("variable")) {
+ } else if (elementName == QLatin1String("variable")) {
node = new VariableNode(parent, name);
if (!indexUrl.isEmpty())
location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
else if (!indexUrl.isNull())
location = Location(parent->name().toLower() + ".html");
- }
- else if (elementName == QLatin1String("keyword")) {
+ } else if (elementName == QLatin1String("keyword")) {
insertTarget(TargetRec::Keyword, attributes, current);
goto done;
- }
- else if (elementName == QLatin1String("target")) {
+ } else if (elementName == QLatin1String("target")) {
insertTarget(TargetRec::Target, attributes, current);
goto done;
- }
- else if (elementName == QLatin1String("contents")) {
+ } else if (elementName == QLatin1String("contents")) {
insertTarget(TargetRec::Contents, attributes, current);
goto done;
- }
- else
+ } else if (elementName == QLatin1String("proxy")) {
+ node = new ProxyNode(parent, name);
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(name.toLower() + ".html");
+ } else {
goto done;
+ }
{
QString access = attributes.value(QLatin1String("access")).toString();
@@ -596,12 +570,10 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
node->setAccess(Node::Private);
else
node->setAccess(Node::Public);
+ if (attributes.hasAttribute(QLatin1String("related")))
+ node->setRelatedNonmember(attributes.value(QLatin1String("related")) == QLatin1String("true"));
- if ((elementName != QLatin1String("page")) &&
- (elementName != QLatin1String("qmlclass")) &&
- (elementName != QLatin1String("qmlbasictype")) &&
- (elementName != QLatin1String("jstype")) &&
- (elementName != QLatin1String("jsbasictype"))) {
+ if (attributes.hasAttribute(QLatin1String("threadsafety"))) {
QString threadSafety = attributes.value(QLatin1String("threadsafety")).toString();
if (threadSafety == QLatin1String("non-reentrant"))
node->setThreadSafeness(Node::NonReentrant);
@@ -662,7 +634,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
}
Doc doc(location, location, QString(), emptySet, emptySet); // placeholder
node->setDoc(doc);
- node->setIndexNodeFlag();
+ node->setIndexNodeFlag(); // Important: This node came from an index file.
node->setOutputSubdirectory(project_.toLower());
QString briefAttr = attributes.value(QLatin1String("brief")).toString();
if (!briefAttr.isEmpty()) {
@@ -743,34 +715,54 @@ void QDocIndexFiles::resolveIndex()
basesList_.clear();
}
-/*
- Goes though the list of nodes that are related to other aggregates
- that were read from all index files, and tries to find the aggregate
- nodes from the database. Calls the node's setRelates() for each
- aggregate that is found in the local module (primary tree).
-
- This function is meant to be called before starting the doc generation,
- after all the index files are read.
- */
-void QDocIndexFiles::resolveRelates()
+static const QString getAccessString(Node::Access t)
{
- if (relatedList_.isEmpty())
- return;
- // Restrict searching only to the local (primary) tree
- QVector<Tree*> searchOrder = qdb_->searchOrder();
- qdb_->setLocalSearch();
+ switch (t) {
+ case Node::Public:
+ return QLatin1String("public");
+ case Node::Protected:
+ return QLatin1String("protected");
+ case Node::Private:
+ return QLatin1String("private");
+ default:
+ break;
+ }
+ return QLatin1String("public");
+}
- QPair<FunctionNode*,QString> relatedPair;
- foreach (relatedPair, relatedList_) {
- QStringList path = relatedPair.second.split("::");
- Node* n = qdb_->findRelatesNode(path);
- if (n)
- relatedPair.first->setRelates(static_cast<PageNode*>(n));
+static const QString getStatusString(Node::Status t)
+{
+ switch (t) {
+ case Node::Obsolete:
+ case Node::Deprecated:
+ return QLatin1String("obsolete");
+ case Node::Preliminary:
+ return QLatin1String("preliminary");
+ case Node::Active:
+ return QLatin1String("active");
+ case Node::Internal:
+ return QLatin1String("internal");
+ default:
+ break;
}
- // Restore original search order
- qdb_->setSearchOrder(searchOrder);
- relatedList_.clear();
+ return QLatin1String("active");
+}
+
+static const QString getThreadSafenessString(Node::ThreadSafeness t)
+{
+ switch (t) {
+ case Node::NonReentrant:
+ return QLatin1String("non-reentrant");
+ case Node::Reentrant:
+ return QLatin1String("reentrant");
+ case Node::ThreadSafe:
+ return QLatin1String("thread safe");
+ case Node::UnspecifiedSafeness:
+ default:
+ break;
+ }
+ return QLatin1String("unspecified");
}
/*!
@@ -778,12 +770,9 @@ void QDocIndexFiles::resolveRelates()
specified, returning true if an element was written, and returning
false if an element is not written.
- \node Currently \a generateInternalNodes is always \c true. If it is
- passed as \c false, then nodes marked internal or private are skipped.
+ \note Function nodes are processed in generateFunctionSection()
*/
-bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
- Node* node,
- bool generateInternalNodes)
+bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node)
{
if (!gen_)
gen_ = Generator::currentGenerator();
@@ -794,8 +783,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
*/
if (node->isIndexNode())
return false;
- if (!generateInternalNodes && (node->isInternal() || node->isPrivate()))
- return false;
QString nodeName;
QString logicalModuleName;
@@ -873,9 +860,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::Property:
nodeName = "property";
break;
- case Node::Function:
- nodeName = "function";
- break;
case Node::Variable:
nodeName = "variable";
break;
@@ -891,27 +875,10 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::JsPropertyGroup:
nodeName = "jspropertygroup";
break;
- default:
- return false;
- }
-
- QString access;
- switch (node->access()) {
- case Node::Public:
- access = "public";
- break;
- case Node::Protected:
- access = "protected";
- break;
- case Node::Private:
- /*
- Should we test generateInternalNodes here and return
- false immediately if it is set? As it is now, we are
- always writing all internal and private nodes to the
- index file.
- */
- access = "private";
+ case Node::Proxy:
+ nodeName = "proxy";
break;
+ case Node::Function: // Now processed in generateFunctionSection()
default:
return false;
}
@@ -923,46 +890,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeStartElement(nodeName);
- QXmlStreamAttributes attributes;
-
if (!node->isTextPageNode() && !node->isCollectionNode() && !node->isHeader()) {
- QString threadSafety;
- switch (node->threadSafeness()) {
- case Node::NonReentrant:
- threadSafety = "non-reentrant";
- break;
- case Node::Reentrant:
- threadSafety = "reentrant";
- break;
- case Node::ThreadSafe:
- threadSafety = "thread safe";
- break;
- case Node::UnspecifiedSafeness:
- default:
- threadSafety = "unspecified";
- break;
- }
- writer.writeAttribute("threadsafety", threadSafety);
- }
-
- QString status;
- switch (node->status()) {
- case Node::Obsolete:
- case Node::Deprecated:
- status = "obsolete";
- break;
- case Node::Preliminary:
- status = "preliminary";
- break;
- case Node::Active:
- status = "active";
- break;
- case Node::Internal:
- status = "internal";
- break;
- default:
- status = "main";
- break;
+ if (node->threadSafeness() != Node::UnspecifiedSafeness)
+ writer.writeAttribute("threadsafety", getThreadSafenessString(node->threadSafeness()));
}
writer.writeAttribute("name", objName);
@@ -1000,9 +930,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
if (!href.isEmpty())
writer.writeAttribute("href", href);
- writer.writeAttribute("status", status);
+ writer.writeAttribute("status", getStatusString(node->status()));
if (!node->isTextPageNode() && !node->isCollectionNode() && !node->isHeader()) {
- writer.writeAttribute("access", access);
+ writer.writeAttribute("access", getAccessString(node->access()));
if (node->isAbstract())
writer.writeAttribute("abstract", "true");
}
@@ -1014,9 +944,11 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("lineno", QString("%1").arg(declLocation.lineNo()));
}
- if (!node->since().isEmpty()) {
+ if (node->isRelatedNonmember())
+ writer.writeAttribute("related", "true");
+
+ if (!node->since().isEmpty())
writer.writeAttribute("since", node->since());
- }
QString brief = node->doc().trimmedBriefText(node->name()).toString();
switch (node->nodeType()) {
@@ -1202,68 +1134,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("brief", brief);
}
break;
- case Node::Function:
- {
- const FunctionNode* fn = static_cast<const FunctionNode*>(node);
- writer.writeAttribute("meta", fn->metanessString());
- if (fn->isCppNode()) {
- writer.writeAttribute("virtual", fn->virtualness());
- writer.writeAttribute("const", fn->isConst() ? "true":"false");
- writer.writeAttribute("static", fn->isStatic() ? "true":"false");
- writer.writeAttribute("overload", fn->isOverload() ? "true":"false");
- writer.writeAttribute("delete", fn->isDeleted() ? "true" : "false");
- writer.writeAttribute("default", fn->isDefaulted() ? "true" : "false");
- writer.writeAttribute("final", fn->isFinal() ? "true" : "false");
- writer.writeAttribute("override", fn->isOverride() ? "true" : "false");
- if (fn->isRef())
- writer.writeAttribute("refness", QString::number(1));
- else if (fn->isRefRef())
- writer.writeAttribute("refness", QString::number(2));
- if (fn->isOverload())
- writer.writeAttribute("overload-number", QString::number(fn->overloadNumber()));
- if (fn->relates())
- writer.writeAttribute("relates", fn->relates()->name());
- if (fn->hasAssociatedProperties()) {
- QStringList associatedProperties;
- foreach (PropertyNode* pn, fn->associatedProperties()) {
- associatedProperties << pn->name();
- }
- associatedProperties.sort();
- writer.writeAttribute("associated-property", associatedProperties.join(QLatin1Char(',')));
- }
- writer.writeAttribute("type", fn->returnType());
- if (!brief.isEmpty())
- writer.writeAttribute("brief", brief);
- /*
- Note: The "signature" attribute is written to the
- index file, but it is not read back in by qdoc. However,
- we need it for the webxml generator.
- */
- QString signature = fn->signature(false);
- // 'const' is already part of FunctionNode::signature()
- if (fn->isFinal())
- signature += " final";
- if (fn->isOverride())
- signature += " override";
- if (fn->isPureVirtual())
- signature += " = 0";
- else if (fn->isDeleted())
- signature += " = delete";
- else if (fn->isDefaulted())
- signature += " = default";
- writer.writeAttribute("signature", signature);
-
- for (int i = 0; i < fn->parameters().size(); ++i) {
- Parameter parameter = fn->parameters()[i];
- writer.writeStartElement("parameter");
- writer.writeAttribute("type", parameter.dataType());
- writer.writeAttribute("name", parameter.name());
- writer.writeAttribute("default", parameter.defaultValue());
- writer.writeEndElement(); // parameter
- }
- }
- }
- break;
case Node::JsProperty:
case Node::QmlProperty:
{
@@ -1351,6 +1221,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("enum",typedefNode->associatedEnum()->fullDocumentName());
}
break;
+ case Node::Function: // Now processed in generateFunctionSection()
default:
break;
}
@@ -1448,32 +1319,154 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
}
/*!
+ This function writes a <function> element for \a fn to the
+ index file using \a writer.
+ */
+void QDocIndexFiles::generateFunctionSection(QXmlStreamWriter &writer, FunctionNode *fn)
+{
+ QString objName = fn->name();
+ writer.writeStartElement("function");
+ writer.writeAttribute("name", objName);
+
+ QString fullName = fn->fullDocumentName();
+ if (fullName != objName)
+ writer.writeAttribute("fullname", fullName);
+ QString href = gen_->fullDocumentLocation(fn);
+ if (!href.isEmpty())
+ writer.writeAttribute("href", href);
+ if (fn->threadSafeness() != Node::UnspecifiedSafeness)
+ writer.writeAttribute("threadsafety", getThreadSafenessString(fn->threadSafeness()));
+ writer.writeAttribute("status", getStatusString(fn->status()));
+ writer.writeAttribute("access", getAccessString(fn->access()));
+
+ const Location &declLocation = fn->declLocation();
+ if (!declLocation.fileName().isEmpty())
+ writer.writeAttribute("location", declLocation.fileName());
+ if (!declLocation.filePath().isEmpty()) {
+ writer.writeAttribute("filepath", declLocation.filePath());
+ writer.writeAttribute("lineno", QString("%1").arg(declLocation.lineNo()));
+ }
+
+ if (fn->isRelatedNonmember())
+ writer.writeAttribute("related", "true");
+ if (!fn->since().isEmpty())
+ writer.writeAttribute("since", fn->since());
+
+ QString brief = fn->doc().trimmedBriefText(fn->name()).toString();
+ writer.writeAttribute("meta", fn->metanessString());
+ if (fn->isCppNode()) {
+ writer.writeAttribute("virtual", fn->virtualness());
+ writer.writeAttribute("const", fn->isConst() ? "true" : "false");
+ writer.writeAttribute("static", fn->isStatic() ? "true" : "false");
+ writer.writeAttribute("final", fn->isFinal() ? "true" : "false");
+ writer.writeAttribute("override", fn->isOverride() ? "true" : "false");
+ /*
+ This ensures that for functions that have overloads,
+ the first function written is the one that is not an
+ overload, and the overloads follow it immediately in
+ the index file numbered from 1 to n.
+ */
+ if (fn->isOverload() && (fn->overloadNumber() > 0)) {
+ writer.writeAttribute("overload", "true");
+ writer.writeAttribute("overload-number", QString::number(fn->overloadNumber()));
+ }
+ if (fn->isRef())
+ writer.writeAttribute("refness", QString::number(1));
+ else if (fn->isRefRef())
+ writer.writeAttribute("refness", QString::number(2));
+ if (fn->hasAssociatedProperties()) {
+ QStringList associatedProperties;
+ foreach (Node *n, fn->associatedProperties()) {
+ associatedProperties << n->name();
+ }
+ associatedProperties.sort();
+ writer.writeAttribute("associated-property", associatedProperties.join(QLatin1Char(',')));
+ }
+ writer.writeAttribute("type", fn->returnType());
+ if (!brief.isEmpty())
+ writer.writeAttribute("brief", brief);
+ /*
+ Note: The "signature" attribute is written to the
+ index file, but it is not read back in by qdoc. However,
+ we need it for the webxml generator.
+ */
+ QString signature = fn->signature(false, false);
+ // 'const' is already part of FunctionNode::signature()
+ if (fn->isFinal())
+ signature += " final";
+ if (fn->isOverride())
+ signature += " override";
+ if (fn->isPureVirtual())
+ signature += " = 0";
+ writer.writeAttribute("signature", signature);
+
+ for (int i = 0; i < fn->parameters().count(); ++i) {
+ const Parameter &parameter = fn->parameters().at(i);
+ writer.writeStartElement("parameter");
+ writer.writeAttribute("type", parameter.type());
+ writer.writeAttribute("name", parameter.name());
+ writer.writeAttribute("default", parameter.defaultValue());
+ writer.writeEndElement(); // parameter
+ }
+ }
+ writer.writeEndElement();
+}
+
+/*!
+ This function outputs a <function> element to the index file
+ for each FunctionNode in \a aggregate using the \a writer.
+ The \a aggregate has a function map that contains all the
+ function nodes indexed by function name. But the map is not
+ used as a multimap, so if the \a aggregate contains multiple
+ functions with the same name, only one of those functions is
+ in the function map index. The others are linked to that
+ function using the next overload pointer.
+
+ So this function generates a <function> element for a function
+ followed by a function element for each of its overloads. If a
+ <function> element represents an overload, it has an \c overload
+ attribute set to \c true and an \c {overload-number} attribute
+ set to the function's overload number. If the <function>
+ element does not represent an overload, the <function> element
+ has neither of these attributes.
+ */
+void QDocIndexFiles::generateFunctionSections(QXmlStreamWriter &writer, Aggregate *aggregate)
+{
+ FunctionMap &functionMap = aggregate->functionMap();
+ if (!functionMap.isEmpty()) {
+ FunctionMap::iterator i = functionMap.begin();
+ while (i != functionMap.end()) {
+ FunctionNode *fn = i.value();
+ while (fn != nullptr) {
+ generateFunctionSection(writer, fn);
+ fn = fn->nextOverload();
+ }
+ i++;
+ }
+ }
+}
+
+/*!
Generate index sections for the child nodes of the given \a node
- using the \a writer specified. If \a generateInternalNodes is true,
- nodes marked as internal will be included in the index; otherwise,
- they will be omitted.
+ using the \a writer specified.
*/
-void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
- Node* node,
- bool generateInternalNodes)
+void QDocIndexFiles::generateIndexSections(QXmlStreamWriter &writer, Node *node)
{
/*
Note that groups, modules, and QML modules are written
after all the other nodes.
*/
- if (node->isGroup() || node->isModule() || node->isQmlModule() || node->isJsModule())
+ if (node->isCollectionNode() ||
+ node->isGroup() || node->isModule() || node->isQmlModule() || node->isJsModule())
return;
- if (generateIndexSection(writer, node, generateInternalNodes)) {
+ if (generateIndexSection(writer, node)) {
if (node->isAggregate()) {
- const Aggregate* aggregate = static_cast<const Aggregate*>(node);
-
- NodeList cnodes = aggregate->childNodes();
- std::sort(cnodes.begin(), cnodes.end(), Node::nodeNameLessThan);
-
- foreach (Node* child, cnodes) {
- generateIndexSections(writer, child, generateInternalNodes);
- }
+ Aggregate *aggregate = static_cast<Aggregate *>(node);
+ // First write the function children, then write the nonfunction children.
+ generateFunctionSections(writer, aggregate);
+ foreach (Node *n, aggregate->nonfunctionList())
+ generateIndexSections(writer, n);
}
if (node == root_) {
@@ -1489,7 +1482,7 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
if (!groups.isEmpty()) {
CNMap::ConstIterator g = groups.constBegin();
while (g != groups.constEnd()) {
- if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ if (generateIndexSection(writer, g.value()))
writer.writeEndElement();
++g;
}
@@ -1499,7 +1492,7 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
if (!modules.isEmpty()) {
CNMap::ConstIterator g = modules.constBegin();
while (g != modules.constEnd()) {
- if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ if (generateIndexSection(writer, g.value()))
writer.writeEndElement();
++g;
}
@@ -1509,7 +1502,7 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
if (!qmlModules.isEmpty()) {
CNMap::ConstIterator g = qmlModules.constBegin();
while (g != qmlModules.constEnd()) {
- if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ if (generateIndexSection(writer, g.value()))
writer.writeEndElement();
++g;
}
@@ -1519,7 +1512,7 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
if (!jsModules.isEmpty()) {
CNMap::ConstIterator g = jsModules.constBegin();
while (g != jsModules.constEnd()) {
- if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ if (generateIndexSection(writer, g.value()))
writer.writeEndElement();
++g;
}
@@ -1531,13 +1524,16 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
}
/*!
- Outputs an index file.
+ Writes aqdoc module index in XML to a file named \afilerName.
+ \a url becaomes the \c url attribute of the <INDEX> element.
+ \a title becomes the \c title attribute of the <INDEX> element.
+ \a g is used to get the Config object that contains the variables
+ from the module's .qdocconf file.
*/
void QDocIndexFiles::generateIndex(const QString& fileName,
const QString& url,
const QString& title,
- Generator* g,
- bool generateInternalNodes)
+ Generator *g)
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
@@ -1562,7 +1558,7 @@ void QDocIndexFiles::generateIndex(const QString& fileName,
if (!root_->tree()->indexTitle().isEmpty())
writer.writeAttribute("indexTitle", root_->tree()->indexTitle());
- generateIndexSections(writer, root_, generateInternalNodes);
+ generateIndexSections(writer, root_);
writer.writeEndElement(); // INDEX
writer.writeEndElement(); // QDOCINDEX
diff --git a/src/qdoc/qdocindexfiles.h b/src/qdoc/qdocindexfiles.h
index 39135de18..5f0752c1d 100644
--- a/src/qdoc/qdocindexfiles.h
+++ b/src/qdoc/qdocindexfiles.h
@@ -55,19 +55,16 @@ class QDocIndexFiles
~QDocIndexFiles();
void readIndexes(const QStringList& indexFiles);
- void generateIndex(const QString& fileName,
- const QString& url,
- const QString& title,
- Generator* g,
- bool generateInternalNodes = false);
-
void readIndexFile(const QString& path);
void readIndexSection(QXmlStreamReader &reader, Node* current, const QString& indexUrl);
void insertTarget(TargetRec::TargetType type, const QXmlStreamAttributes &attributes, Node *node);
void resolveIndex();
- void resolveRelates();
- bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
- void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
+
+ void generateIndex(const QString &fileName, const QString &url, const QString &title, Generator *g);
+ void generateFunctionSection(QXmlStreamWriter &writer, FunctionNode *fn);
+ void generateFunctionSections(QXmlStreamWriter &writer, Aggregate *aggrtegate);
+ bool generateIndexSection(QXmlStreamWriter &writer, Node *node);
+ void generateIndexSections(QXmlStreamWriter &writer, Node *node);
private:
static QDocIndexFiles* qdocIndexFiles_;
@@ -75,7 +72,6 @@ class QDocIndexFiles
Generator* gen_;
QString project_;
QVector<QPair<ClassNode*,QString> > basesList_;
- QVector<QPair<FunctionNode*,QString> > relatedList_;
};
QT_END_NAMESPACE
diff --git a/src/qdoc/qdoctagfiles.cpp b/src/qdoc/qdoctagfiles.cpp
index 94e3f4375..4cc1735d3 100644
--- a/src/qdoc/qdoctagfiles.cpp
+++ b/src/qdoc/qdoctagfiles.cpp
@@ -90,14 +90,13 @@ void QDocTagFiles::destroyQDocTagFiles()
}
/*!
- Generate the tag file section with the given \a writer for the \a node
- specified, returning true if an element was written; otherwise returns
- false.
+ Generate the tag file section with the given \a writer for the \a parent
+ node.
*/
-void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Aggregate* inner)
+void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter &writer, const Aggregate *parent)
{
- foreach (const Node* node, inner->childNodes()) {
- if (!node->url().isEmpty())
+ foreach (const Node *node, const_cast<Aggregate *>(parent)->nonfunctionList()) {
+ if (!node->url().isEmpty() || node->isPrivate())
continue;
QString kind;
@@ -107,29 +106,17 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Aggr
break;
case Node::Class:
case Node::QmlType:
+ case Node::JsType:
kind = "class";
break;
- case Node::Enum:
- case Node::Typedef:
- case Node::Property:
- case Node::Function:
- case Node::Variable:
default:
continue;
}
+ const Aggregate *aggregate = static_cast<const Aggregate*>(node);
- QString access;
- switch (node->access()) {
- case Node::Public:
- access = "public";
- break;
- case Node::Protected:
+ QString access = "public";
+ if (node->isProtected())
access = "protected";
- break;
- case Node::Private:
- default:
- continue;
- }
QString objName = node->name();
@@ -155,33 +142,32 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Aggr
}
// Recurse to write all members.
- generateTagFileMembers(writer, static_cast<const Aggregate*>(node));
+ generateTagFileMembers(writer, aggregate);
writer.writeEndElement();
// Recurse to write all compounds.
- generateTagFileCompounds(writer, static_cast<const Aggregate*>(node));
- }
- else {
+ generateTagFileCompounds(writer, aggregate);
+ } else {
writer.writeTextElement("name", node->fullDocumentName());
writer.writeTextElement("filename", gen_->fullDocumentLocation(node, false));
// Recurse to write all members.
- generateTagFileMembers(writer, static_cast<const Aggregate*>(node));
+ generateTagFileMembers(writer, aggregate);
writer.writeEndElement();
// Recurse to write all compounds.
- generateTagFileCompounds(writer, static_cast<const Aggregate*>(node));
+ generateTagFileCompounds(writer, aggregate);
}
}
}
/*!
- Writes all the members of the \a inner node with the \a writer.
+ Writes all the members of the \a parent node with the \a writer.
The node represents a C++ class, namespace, etc.
*/
-void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggregate* inner)
+void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter &writer, const Aggregate *parent)
{
- foreach (const Node* node, inner->childNodes()) {
+ foreach (const Node *node, parent->childNodes()) {
if (!node->url().isEmpty())
continue;
@@ -269,7 +255,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg
QStringList pieces = gen_->fullDocumentLocation(node, false).split(QLatin1Char('#'));
writer.writeTextElement("anchorfile", pieces[0]);
writer.writeTextElement("anchor", pieces[1]);
- QString signature = functionNode->signature(false);
+ QString signature = functionNode->signature(false, false);
signature = signature.mid(signature.indexOf(QChar('('))).trimmed();
if (functionNode->isConst())
signature += " const";
@@ -279,10 +265,6 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg
signature += " override";
if (functionNode->isPureVirtual())
signature += " = 0";
- else if (functionNode->isDeleted())
- signature += " = delete";
- else if (functionNode->isDefaulted())
- signature += " = default";
writer.writeTextElement("arglist", signature);
}
writer.writeEndElement(); // member
diff --git a/src/qdoc/qmlcodeparser.cpp b/src/qdoc/qmlcodeparser.cpp
index 86db59a3f..58939c9c3 100644
--- a/src/qdoc/qmlcodeparser.cpp
+++ b/src/qdoc/qmlcodeparser.cpp
@@ -134,17 +134,13 @@ void QmlCodeParser::parseSourceFile(const Location& location, const QString& fil
extractPragmas(newCode);
lexer->setCode(newCode, 1);
- const QSet<QString>& topicCommandsAllowed = topicCommands();
- const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands();
- const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed;
-
if (parser->parse()) {
QQmlJS::AST::UiProgram *ast = parser->ast();
QmlDocVisitor visitor(filePath,
newCode,
&engine,
- metacommandsAllowed,
- topicCommandsAllowed);
+ topicCommands() + commonMetaCommands(),
+ topicCommands());
QQmlJS::AST::Node::accept(ast, &visitor);
}
foreach (const QQmlJS::DiagnosticMessage &msg, parser->diagnosticMessages()) {
@@ -189,35 +185,6 @@ const QSet<QString>& QmlCodeParser::topicCommands()
return topicCommands_;
}
-static QSet<QString> otherMetaCommands_;
-/*!
- Returns the set of strings representing the common metacommands
- plus some other metacommands.
- */
-const QSet<QString>& QmlCodeParser::otherMetaCommands()
-{
- if (otherMetaCommands_.isEmpty()) {
- otherMetaCommands_ = commonMetaCommands();
- otherMetaCommands_ << COMMAND_STARTPAGE
- << COMMAND_QMLINHERITS
- << COMMAND_QMLDEFAULT
- << COMMAND_QMLREADONLY
- << COMMAND_DEPRECATED
- << COMMAND_INGROUP
- << COMMAND_INTERNAL
- << COMMAND_OBSOLETE
- << COMMAND_PRELIMINARY
- << COMMAND_SINCE
- << COMMAND_ABSTRACT
- << COMMAND_QMLABSTRACT
- << COMMAND_INQMLMODULE
- << COMMAND_INJSMODULE
- << COMMAND_WRAPPER
- << COMMAND_NOAUTOLIST;
- }
- return otherMetaCommands_;
-}
-
#ifndef QT_NO_DECLARATIVE
/*!
Copy and paste from src/declarative/qml/qdeclarativescriptparser.cpp.
diff --git a/src/qdoc/qmlcodeparser.h b/src/qdoc/qmlcodeparser.h
index 3788175f3..5188867e4 100644
--- a/src/qdoc/qmlcodeparser.h
+++ b/src/qdoc/qmlcodeparser.h
@@ -69,7 +69,6 @@ public:
protected:
const QSet<QString>& topicCommands();
- const QSet<QString>& otherMetaCommands();
private:
#ifndef QT_NO_DECLARATIVE
diff --git a/src/qdoc/qmlvisitor.cpp b/src/qdoc/qmlvisitor.cpp
index 7cf2afe7e..1b22d9d38 100644
--- a/src/qdoc/qmlvisitor.cpp
+++ b/src/qdoc/qmlvisitor.cpp
@@ -32,6 +32,7 @@
#include "codeparser.h"
#include "qdocdatabase.h"
#include "tokenizer.h"
+#include "codechunk.h"
#include <qfileinfo.h>
#include <qstringlist.h>
@@ -117,7 +118,7 @@ class QmlSignatureParser
QString previousLexeme() { return tokenizer_->previousLexeme(); }
bool match(int target);
- bool matchDataType(CodeChunk* dataType, QString* var);
+ bool matchTypeAndName(CodeChunk *type, QString *var);
bool matchParameter();
bool matchFunctionDecl();
@@ -182,11 +183,11 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod
n = new QmlPropertyNode(parent, qpa.name_, qpa.type_, isAttached);
n->setLocation(doc.location());
n->setDoc(doc);
- n->setReadOnly(nodePassedIn->isReadOnly());
+ n->markReadOnly(nodePassedIn->isReadOnly());
if (nodePassedIn->isDefault())
- n->setDefault();
+ n->markDefault();
if (isAttached)
- n->setReadOnly(0);
+ n->markReadOnly(0);
if ((topic == COMMAND_JSPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY))
n->changeType(Node::QmlProperty, Node::JsProperty);
nodes.append(n);
@@ -244,10 +245,10 @@ bool QmlSignatureParser::match(int target)
}
/*!
- Parse a QML data type into \a dataType and an optional
+ Parse a QML data type into \a type and an optional
variable name into \a var.
*/
-bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
+bool QmlSignatureParser::matchTypeAndName(CodeChunk *type, QString *var)
{
/*
This code is really hard to follow... sorry. The loop is there to match
@@ -262,32 +263,32 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
match(Tok_short) ||
match(Tok_long) ||
match(Tok_int64)) {
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
virgin = false;
}
}
if (virgin) {
if (match(Tok_Ident)) {
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
}
else if (match(Tok_void) ||
match(Tok_int) ||
match(Tok_char) ||
match(Tok_double) ||
match(Tok_Ellipsis))
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
else
return false;
}
else if (match(Tok_int) ||
match(Tok_char) ||
match(Tok_double)) {
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
}
if (match(Tok_Gulbrandsen))
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
else
break;
}
@@ -296,13 +297,13 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
match(Tok_Aster) ||
match(Tok_const) ||
match(Tok_Caret))
- dataType->append(previousLexeme());
+ type->append(previousLexeme());
/*
The usual case: Look for an optional identifier, then for
some array brackets.
*/
- dataType->appendHotspot();
+ type->appendHotspot();
if ((var != 0) && match(Tok_Ident))
*var = previousLexeme();
@@ -311,7 +312,7 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
int bracketDepth0 = tokenizer_->bracketDepth();
while ((tokenizer_->bracketDepth() >= bracketDepth0 && tok_ != Tok_Eoi) ||
tok_ == Tok_RightBracket) {
- dataType->append(lexeme());
+ type->append(lexeme());
readToken();
}
}
@@ -321,13 +322,13 @@ bool QmlSignatureParser::matchDataType(CodeChunk* dataType, QString* var)
bool QmlSignatureParser::matchParameter()
{
QString name;
- CodeChunk dataType;
+ CodeChunk type;
CodeChunk defaultValue;
- bool result = matchDataType(&dataType, &name);
+ bool result = matchTypeAndName(&type, &name);
if (name.isEmpty()) {
- name = dataType.toString();
- dataType.clear();
+ name = type.toString();
+ type.clear();
}
if (!result)
@@ -342,7 +343,7 @@ bool QmlSignatureParser::matchParameter()
readToken();
}
}
- func_->addParameter(Parameter(dataType.toString(), name, defaultValue.toString()));
+ func_->parameters().append(type.toString(), name, defaultValue.toString());
return true;
}
@@ -353,7 +354,7 @@ bool QmlSignatureParser::matchFunctionDecl()
int firstBlank = signature_.indexOf(QChar(' '));
int leftParen = signature_.indexOf(QChar('('));
if ((firstBlank > 0) && (leftParen - firstBlank) > 1) {
- if (!matchDataType(&returnType, 0))
+ if (!matchTypeAndName(&returnType, 0))
return false;
}
@@ -368,14 +369,17 @@ bool QmlSignatureParser::matchFunctionDecl()
if (tok_ != Tok_LeftParen)
return false;
-
+ /*
+ Parsing the parameters should be moved into class Parameters,
+ but it can wait. mws 14/12/2018
+ */
readToken();
func_->setLocation(location_);
func_->setReturnType(returnType.toString());
if (tok_ != Tok_RightParen) {
- func_->clearParams();
+ func_->parameters().clear();
do {
if (!matchParameter())
return false;
@@ -472,16 +476,10 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
}
}
else if (command == COMMAND_QMLDEFAULT) {
- if (node->isQmlProperty() || node->isJsProperty()) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setDefault();
- }
+ node->markDefault();
}
else if (command == COMMAND_QMLREADONLY) {
- if (node->isQmlProperty() || node->isJsProperty()) {
- QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
- qpn->setReadOnly(1);
- }
+ node->markReadOnly(1);
}
else if ((command == COMMAND_INGROUP) && !args.isEmpty()) {
ArgList::ConstIterator argsIter = args.constBegin();
@@ -662,13 +660,12 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
metaness = FunctionNode::JsSignal;
QString name = member->name.toString();
FunctionNode *newSignal = new FunctionNode(metaness, current, name);
- QVector<Parameter> parameters;
+ Parameters &parameters = newSignal->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()));
+ parameters.append(type, QString(), it->name.toString());
}
- newSignal->setParameters(parameters);
applyDocumentation(member->firstSourceLocation(), newSignal);
}
}
@@ -685,9 +682,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
QmlPropertyNode* qmlPropNode = qmlType->hasQmlProperty(name);
if (qmlPropNode == 0)
qmlPropNode = new QmlPropertyNode(qmlType, name, type, false);
- qmlPropNode->setReadOnly(member->isReadonlyMember);
+ qmlPropNode->markReadOnly(member->isReadonlyMember);
if (member->isDefaultMember)
- qmlPropNode->setDefault();
+ qmlPropNode->markDefault();
applyDocumentation(member->firstSourceLocation(), qmlPropNode);
}
}
@@ -719,38 +716,24 @@ bool QmlDocVisitor::visit(QQmlJS::AST::IdentifierPropertyName *)
*/
bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
{
- if (nestingLevel > 1) {
- return true;
- }
- 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* newMethod = new FunctionNode(metaness, current, name);
- int overloads = 0;
- NodeList::ConstIterator i = current->childNodes().constBegin();
- while (i != current->childNodes().constEnd()) {
- if ((*i)->name() == name)
- overloads++;
- i++;
- }
- if (overloads > 1)
- newMethod->setOverloadFlag(true);
- QVector<Parameter> parameters;
- QQmlJS::AST::FormalParameterList* formals = fd->formals;
- if (formals) {
- QQmlJS::AST::FormalParameterList* fpl = formals;
- do {
- parameters.append(Parameter(QString(), QString(), fpl->element->bindingIdentifier.toString()));
- fpl = fpl->next;
- } while (fpl && fpl != formals);
- newMethod->setParameters(parameters);
- }
- applyDocumentation(fd->firstSourceLocation(), newMethod);
+ if (nestingLevel <= 1) {
+ FunctionNode::Metaness metaness = FunctionNode::QmlMethod;
+ if (current->isJsType())
+ metaness = FunctionNode::JsMethod;
+ else if (!current->isQmlType())
+ return true;
+ QString name = fd->name.toString();
+ FunctionNode *method = new FunctionNode(metaness, current, name);
+ Parameters &parameters = method->parameters();
+ QQmlJS::AST::FormalParameterList *formals = fd->formals;
+ if (formals) {
+ QQmlJS::AST::FormalParameterList *fp = formals;
+ do {
+ parameters.append(QString(), QString(), fp->element->bindingIdentifier.toString());
+ fp = fp->next;
+ } while (fp && fp != formals);
}
+ applyDocumentation(fd->firstSourceLocation(), method);
}
return true;
}
diff --git a/src/qdoc/sections.cpp b/src/qdoc/sections.cpp
index e83dcadb9..69683d358 100644
--- a/src/qdoc/sections.cpp
+++ b/src/qdoc/sections.cpp
@@ -172,7 +172,7 @@ void Section::insert(Node *node)
{
bool irrelevant = false;
bool inherited = false;
- if (!node->relates()) {
+ if (!node->isRelatedNonmember()) {
Aggregate* p = node->parent();
if (p->isQmlPropertyGroup())
p = p->parent();
@@ -231,9 +231,9 @@ void Section::insert(Node *node)
*/
bool Section::insertReimplementedMember(Node* node)
{
- if (!node->isPrivate() && (node->relates() == 0)) {
+ if (!node->isPrivate() && !node->isRelatedNonmember()) {
const FunctionNode* fn = static_cast<const FunctionNode*>(node);
- if (!fn->reimplementedFrom().isEmpty() && (status_ == Active)) {
+ if (!fn->overridesThis().isEmpty() && (status_ == Active)) {
if (fn->parent() == aggregate_) {
QString key = sortName(fn);
if (!reimplementedMemberMap_.contains(key)) {
@@ -265,16 +265,13 @@ ClassMap *Section::newClassMap(const Aggregate* aggregate)
void Section::add(ClassMap *classMap, Node *n)
{
if (n->isQmlPropertyGroup() || n->isJsPropertyGroup()) {
- const QmlPropertyGroupNode* pg = static_cast<const QmlPropertyGroupNode*>(n);
- NodeList::ConstIterator p = pg->childNodes().constBegin();
- while (p != pg->childNodes().constEnd()) {
- if ((*p)->isQmlProperty() || (*p)->isJsProperty()) {
- QString key = (*p)->name();
- key = sortName(*p, &key);
- memberMap_.insert(key,*p);
- classMap->second.insert(key,*p);
- }
- ++p;
+ Aggregate *aggregate = static_cast<Aggregate*>(n);
+ const NodeList &properties = aggregate->nonfunctionList();
+ foreach (Node *p, properties) {
+ QString key = p->name();
+ key = sortName(p, &key);
+ memberMap_.insert(key, p);
+ classMap->second.insert(key, p);
}
}
else {
@@ -341,6 +338,7 @@ Sections::Sections(Aggregate *aggregate) : aggregate_(aggregate)
break;
case Node::Namespace:
case Node::HeaderFile:
+ case Node::Proxy:
default:
initAggregate(stdSummarySections_, aggregate_);
initAggregate(stdDetailsSections_, aggregate_);
@@ -660,20 +658,30 @@ void Sections::stdRefPageSwitch(SectionVector &v, Node *n)
/*!
Build the section vectors for a standard reference page,
when the aggregate node is not a C++ class or a QML type.
+
+ If this is for a namespace page then if the namespace node
+ itself does not have documentation, only its children that
+ have documentation should be documented. In other words,
+ there are cases where a namespace is declared but does not
+ have documentation, but some of the elements declared in
+ that namespace do have documentation.
+
+ This special processing of namespaces that do not have a
+ documentation comment is meant to allow documenting its
+ members that do have documentation while avoiding posting
+ error messages for its members that are not documented.
*/
void Sections::buildStdRefPageSections()
{
const NamespaceNode* ns = 0;
- bool documentAll = true;
- NodeList nodeList = aggregate_->childNodes();
- nodeList += aggregate_->relatedNodes();
+ bool documentAll = true; // document all the children
if (aggregate_->isNamespace()) {
ns = static_cast<const NamespaceNode*>(aggregate_);
if (!ns->hasDoc())
- documentAll = false;
+ documentAll = false; // only document children that have documentation
}
- NodeList::ConstIterator c = nodeList.constBegin();
- while (c != nodeList.constEnd()) {
+ NodeList::ConstIterator c = aggregate_->constBegin();
+ while (c != aggregate_->constEnd()) {
Node *n = *c;
if (documentAll || n->hasDoc()) {
stdRefPageSwitch(stdSummarySections(), n);
@@ -681,9 +689,22 @@ void Sections::buildStdRefPageSections()
}
++c;
}
- if (ns && !ns->orphans().isEmpty()) {
- NodeList::ConstIterator c = ns->orphans().constBegin();
- while (c != ns->orphans().constEnd()) {
+ if (!aggregate_->relatedByProxy().isEmpty()) {
+ c = aggregate_->relatedByProxy().constBegin();
+ while (c != aggregate_->relatedByProxy().constEnd()) {
+ Node *n = *c;
+ stdRefPageSwitch(stdSummarySections(), n);
+ ++c;
+ }
+ }
+ /*
+ If we are building the sections for the reference page
+ for a namespace node, include all the namespace node's
+ included children in the sections.
+ */
+ if (ns && !ns->includedChildren().isEmpty()) {
+ NodeList::ConstIterator c = ns->includedChildren().constBegin();
+ while (c != ns->includedChildren().constEnd()) {
Node *n = *c;
if (documentAll || n->hasDoc())
stdRefPageSwitch(stdSummarySections(), n);
@@ -704,6 +725,13 @@ void Sections::distributeNodeInSummaryVector(SectionVector &sv, Node *n)
{
if (n->isFunction()) {
FunctionNode *fn = static_cast<FunctionNode*>(n);
+ if (fn->isRelatedNonmember()) {
+ if (fn->isMacro())
+ sv[Macros].insert(n);
+ else
+ sv[RelatedNonmembers].insert(n);
+ return;
+ }
if (fn->hasAssociatedProperties() && !fn->hasActiveAssociatedProperty())
return;
else if (fn->isIgnored())
@@ -740,6 +768,10 @@ void Sections::distributeNodeInSummaryVector(SectionVector &sv, Node *n)
}
return;
}
+ if (n->isRelatedNonmember()) {
+ sv[RelatedNonmembers].insert(n);
+ return;
+ }
if (n->isVariable()) {
if (n->isStatic()) {
if (n->isPublic())
@@ -784,6 +816,13 @@ void Sections::distributeNodeInDetailsVector(SectionVector &dv, Node *n)
return;
if (n->isFunction()) {
FunctionNode *fn = static_cast<FunctionNode*>(n);
+ if (fn->isRelatedNonmember()) {
+ if (fn->isMacro())
+ dv[DetailsMacros].insert(n);
+ else
+ dv[DetailsRelatedNonmembers].insert(n);
+ return;
+ }
if (fn->isIgnored())
return;
if (!fn->isSharingComment()) {
@@ -792,6 +831,10 @@ void Sections::distributeNodeInDetailsVector(SectionVector &dv, Node *n)
}
return;
}
+ if (n->isRelatedNonmember()) {
+ dv[DetailsRelatedNonmembers].insert(n);
+ return;
+ }
if (n->isEnumType() || n->isTypedef()) {
if (n->name() != QLatin1String("QtGadgetHelper"))
dv[DetailsMemberTypes].insert(n);
@@ -883,32 +926,13 @@ void Sections::buildStdCppClassRefPageSections()
SectionVector &sv = stdCppClassSummarySections();
SectionVector &dv = stdCppClassDetailsSections();
Section &allMembers = allMembersSection();
- NodeList::ConstIterator r = aggregate_->relatedNodes().constBegin();
- while (r != aggregate_->relatedNodes().constEnd()) {
- Node* n = *r;
- if (n->isFunction()) {
- FunctionNode *func = static_cast<FunctionNode *>(n);
- if (func->isMacro()) {
- sv[Macros].insert(n);
- dv[DetailsMacros].insert(n);
- } else {
- sv[RelatedNonmembers].insert(n);
- dv[DetailsRelatedNonmembers].insert(n);
- }
- } else {
- sv[RelatedNonmembers].insert(n);
- dv[DetailsRelatedNonmembers].insert(n);
- }
- ++r;
- }
-
bool documentAll = true;
if (aggregate_->parent() && !aggregate_->name().isEmpty() && !aggregate_->hasDoc())
documentAll = false;
- NodeList::ConstIterator c = aggregate_->childNodes().constBegin();
- while (c != aggregate_->childNodes().constEnd()) {
+ NodeList::ConstIterator c = aggregate_->constBegin();
+ while (c != aggregate_->constEnd()) {
Node* n = *c;
- if (!n->isPrivate() && !n->isProperty())
+ if (!n->isPrivate() && !n->isProperty() && !n->isRelatedNonmember())
allMembers.insert(n);
if (!documentAll && !n->hasDoc()) {
++c;
@@ -918,14 +942,22 @@ void Sections::buildStdCppClassRefPageSections()
distributeNodeInDetailsVector(dv, n);
++c;
}
+ if (!aggregate_->relatedByProxy().isEmpty()) {
+ c = aggregate_->relatedByProxy().constBegin();
+ while (c != aggregate_->relatedByProxy().constEnd()) {
+ Node *n = *c;
+ distributeNodeInSummaryVector(sv, n);
+ ++c;
+ }
+ }
QStack<ClassNode*> stack;
ClassNode* cn = static_cast<ClassNode*>(aggregate_);
pushBaseClasses(stack, cn);
while (!stack.isEmpty()) {
ClassNode *cn = stack.pop();
- c = cn->childNodes().constBegin();
- while (c != cn->childNodes().constEnd()) {
+ c = cn->constBegin();
+ while (c != cn->constEnd()) {
Node* n = *c;
if (!n->isPrivate() && !n->isProperty())
allMembers.insert(n);
@@ -959,8 +991,8 @@ void Sections::buildStdQmlTypeRefPageSections()
while (true) {
if (!qtn->isAbstract() || !classMap)
classMap = allMembers.newClassMap(qtn);
- NodeList::ConstIterator c = qtn->childNodes().constBegin();
- while (c != qtn->childNodes().constEnd()) {
+ NodeList::ConstIterator c = qtn->constBegin();
+ while (c != qtn->constEnd()) {
Node *n = *c;
if (n->isInternal()) {
++c;
@@ -988,8 +1020,8 @@ void Sections::buildStdQmlTypeRefPageSections()
while (qtn != 0) {
if (!qtn->isAbstract() || !classMap)
classMap = allMembers.newClassMap(qtn);
- NodeList::ConstIterator c = qtn->childNodes().constBegin();
- while (c != qtn->childNodes().constEnd()) {
+ NodeList::ConstIterator c = qtn->constBegin();
+ while (c != qtn->constEnd()) {
Node *n = *c;
if (n->isInternal()) {
++c;
diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp
index d9fe1b0e4..0561b36b4 100644
--- a/src/qdoc/tree.cpp
+++ b/src/qdoc/tree.cpp
@@ -134,6 +134,35 @@ Node* Tree::findNodeForInclude(const QStringList& path) const
return n;
}
+static QList<int> aggregateTypes_;
+static const QList<int>& aggregateTypes()
+{
+ if (aggregateTypes_.isEmpty()) {
+ aggregateTypes_.reserve(5);
+ aggregateTypes_.append(Node::Class);
+ aggregateTypes_.append(Node::Namespace);
+ aggregateTypes_.append(Node::HeaderFile);
+ aggregateTypes_.append(Node::QmlType);
+ aggregateTypes_.append(Node::QmlBasicType);
+ }
+ return aggregateTypes_;
+}
+
+/*!
+ This function searches this tree for an Aggregate node with
+ the specified \a name. It returns the pointer to that node
+ or nullptr.
+
+ We might need to split the name on '::' but we assume the
+ name is a single word at the moment.
+ */
+Aggregate *Tree::findAggregate(const QString &name)
+{
+ QStringList path;
+ path << name;
+ return static_cast<Aggregate*>(findNodeRecursive(path, 0, const_cast<NamespaceNode*>(root()), aggregateTypes()));
+}
+
/*!
Find the C++ class node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
@@ -159,30 +188,6 @@ NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
}
/*!
- This function first ignores the \a clone node and searches
- for the parent node with \a parentPath. If that search is
- successful, it searches for a child node of the parent that
- matches the \a clone node. If it finds a node that is just
- like the \a clone, it returns a pointer to the found node.
-
- Apparently the search order is important here. Don't change
- it unless you know what you are doing, or you will introduce
- qdoc warnings.
- */
-FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const FunctionNode* clone)
-{
- const Node* parent = findNamespaceNode(parentPath);
- if (parent == 0)
- parent = findClassNode(parentPath, 0);
- if (parent == 0)
- parent = findNode(parentPath, 0, 0, Node::DontCare);
- if (parent == 0 || !parent->isAggregate())
- return 0;
- return ((const Aggregate*)parent)->findFunctionNode(clone);
-}
-
-
-/*!
Find the Qml type node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a Qml type node named <\a path is
@@ -206,103 +211,17 @@ QmlTypeNode* Tree::findQmlTypeNode(const QStringList& path)
return static_cast<QmlTypeNode*>(findNodeRecursive(path, 0, root(), Node::QmlType));
}
-/*!
- This function begins searching the tree at \a relative for
- the \l {FunctionNode} {function node} identified by \a path.
- The \a findFlags are used to restrict the search. If a node
- that matches the \a path is found, it is returned. Otherwise,
- 0 is returned. If \a relative is 0, the root of the tree is
- used as the starting point.
- */
-const FunctionNode* Tree::findFunctionNode(const QStringList& path,
- const QString& params,
- const Node* relative,
- int findFlags,
- Node::Genus genus) const
-{
- if (path.size() == 3 && !path[0].isEmpty() &&
- ((genus == Node::QML) || (genus == Node::DontCare))) {
- QmlTypeNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
- if (!qcn) {
- QStringList p(path[1]);
- Node* n = findNodeByNameAndType(p, Node::QmlType);
- if (n && (n->isQmlType() || n->isJsType()))
- qcn = static_cast<QmlTypeNode*>(n);
- }
- if (qcn)
- return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2], params));
- }
-
- if (!relative)
- relative = root();
- else if (genus != Node::DontCare) {
- if (genus != relative->genus())
- relative = root();
- }
-
- do {
- const Node* node = relative;
- int i;
-
- for (i = 0; i < path.size(); ++i) {
- if (node == 0 || !node->isAggregate())
- break;
-
- const Node* next;
- if (i == path.size() - 1)
- next = ((const Aggregate*) node)->findFunctionNode(path.at(i), params);
- else
- next = ((const Aggregate*) node)->findChildNode(path.at(i), genus);
-
- if (!next && node->isClass() && (findFlags & SearchBaseClasses)) {
- NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
- foreach (const Node* baseClass, baseClasses) {
- if (i == path.size() - 1)
- next = static_cast<const Aggregate*>(baseClass)->findFunctionNode(path.at(i), params);
- else
- next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus);
-
- if (next)
- break;
- }
- }
-
- node = next;
- }
- if (node && i == path.size() && node->isFunction()) {
- // CppCodeParser::processOtherMetaCommand ensures that reimplemented
- // functions are private.
- const FunctionNode* func = static_cast<const FunctionNode*>(node);
- while (func->access() == Node::Private) {
- if (func->reimplementedFrom().isEmpty())
- return func;
- QString path = func->reimplementedFrom();
- const FunctionNode* from = qdb_->findFunctionNode(path, params, relative, genus);
- if (from == 0)
- break;
- if (from->access() != Node::Private)
- return from;
- else
- func = from;
- }
- return func;
- }
- relative = relative->parent();
- } while (relative);
-
- return 0;
-}
-
-static QList<int> t;
+static QList<int> relatesTypes_;
static const QList<int>& relatesTypes()
{
- if (t.isEmpty()) {
- t.reserve(3);
- t.append(Node::Class);
- t.append(Node::Namespace);
- t.append(Node::HeaderFile);
+ if (relatesTypes_.isEmpty()) {
+ relatesTypes_.reserve(4);
+ relatesTypes_.append(Node::Class);
+ relatesTypes_.append(Node::Namespace);
+ relatesTypes_.append(Node::HeaderFile);
+ relatesTypes_.append(Node::Proxy);
}
- return t;
+ return relatesTypes_;
}
/*!
@@ -317,10 +236,10 @@ static const QList<int>& relatesTypes()
If a matching node is found, a pointer to it is returned.
Otherwise 0 is returned.
*/
-PageNode* Tree::findRelatesNode(const QStringList& path)
+Aggregate *Tree::findRelatesNode(const QStringList &path)
{
Node* n = findNodeRecursive(path, 0, root(), relatesTypes());
- return ((n && n->isPageNode()) ? static_cast<PageNode*>(n) : 0);
+ return ((n && n->isAggregate()) ? static_cast<Aggregate*>(n) : 0);
}
/*!
@@ -345,18 +264,14 @@ void Tree::addPropertyFunction(PropertyNode* property,
*/
void Tree::resolveInheritance(Aggregate* n)
{
- if (!n)
- n = root();
-
for (int pass = 0; pass < 2; pass++) {
- NodeList::ConstIterator c = n->childNodes().constBegin();
- while (c != n->childNodes().constEnd()) {
+ NodeList::ConstIterator c = n->constBegin();
+ while (c != n->constEnd()) {
if ((*c)->isClass()) {
- resolveInheritanceHelper(pass, (ClassNode*)*c);
- resolveInheritance((ClassNode*)*c);
+ resolveInheritanceHelper(pass, static_cast<ClassNode*>(*c));
+ resolveInheritance(static_cast<ClassNode*>(*c));
} else if ((*c)->isNamespace()) {
- NamespaceNode* ns = static_cast<NamespaceNode*>(*c);
- resolveInheritance(ns);
+ resolveInheritance(static_cast<NamespaceNode*>(*c));
}
++c;
}
@@ -413,8 +328,8 @@ void Tree::resolveInheritanceHelper(int pass, ClassNode* cn)
}
}
else {
- NodeList::ConstIterator c = cn->childNodes().constBegin();
- while (c != cn->childNodes().constEnd()) {
+ NodeList::ConstIterator c = cn->constBegin();
+ while (c != cn->constEnd()) {
if ((*c)->isProperty())
cn->fixPropertyUsingBaseClasses(static_cast<PropertyNode*>(*c));
++c;
@@ -437,8 +352,8 @@ void Tree::resolveProperties()
QString resetterName = (*propEntry)[PropertyNode::Resetter];
QString notifierName = (*propEntry)[PropertyNode::Notifier];
- NodeList::ConstIterator c = parent->childNodes().constBegin();
- while (c != parent->childNodes().constEnd()) {
+ NodeList::ConstIterator c = parent->constBegin();
+ while (c != parent->constEnd()) {
if ((*c)->isFunction()) {
FunctionNode* function = static_cast<FunctionNode*>(*c);
if (function->access() == property->access() &&
@@ -483,7 +398,8 @@ void Tree::resolveProperties()
void Tree::resolveCppToQmlLinks()
{
- foreach (Node* child, root_.childNodes()) {
+ const NodeList &children = root_.childNodes();
+ foreach (Node *child, children) {
if (child->isQmlType() || child->isJsType()) {
QmlTypeNode* qcn = static_cast<QmlTypeNode*>(child);
ClassNode* cn = const_cast<ClassNode*>(qcn->classNode());
@@ -499,7 +415,8 @@ void Tree::resolveCppToQmlLinks()
*/
void Tree::resolveUsingClauses()
{
- foreach (Node* child, root_.childNodes()) {
+ const NodeList &children = root_.childNodes();
+ foreach (Node *child, children) {
if (child->isClass()) {
ClassNode* cn = static_cast<ClassNode*>(child);
QList<UsingClause>& usingClauses = cn->usingClauses();
@@ -523,23 +440,21 @@ void Tree::fixInheritance(NamespaceNode* rootNode)
if (!rootNode)
rootNode = root();
- NodeList::ConstIterator c = rootNode->childNodes().constBegin();
- while (c != rootNode->childNodes().constEnd()) {
+ NodeList::ConstIterator c = rootNode->constBegin();
+ while (c != rootNode->constEnd()) {
if ((*c)->isClass())
static_cast<ClassNode*>(*c)->fixBaseClasses();
- else if ((*c)->isNamespace()) {
- NamespaceNode* ns = static_cast<NamespaceNode*>(*c);
- fixInheritance(ns);
- }
+ else if ((*c)->isNamespace())
+ fixInheritance(static_cast<NamespaceNode*>(*c));
++c;
}
}
/*!
*/
-NodeList Tree::allBaseClasses(const ClassNode* classNode) const
+ClassList Tree::allBaseClasses(const ClassNode *classNode) const
{
- NodeList result;
+ ClassList result;
foreach (const RelatedClass& r, classNode->baseClasses()) {
if (r.node_) {
result += r.node_;
@@ -594,8 +509,7 @@ Node* Tree::findNodeRecursive(const QStringList& path,
Aggregate* current = static_cast<Aggregate*>(node);
const NodeList& children = current->childNodes();
const QString& name = path.at(pathIndex);
- for (int i=0; i<children.size(); ++i) {
- Node* n = children.at(i);
+ foreach (Node *n, children) {
if (!n)
continue;
if (n->isQmlPropertyGroup()) {
@@ -648,9 +562,8 @@ Node* Tree::findNodeRecursive(const QStringList& path,
return 0;
Aggregate* current = static_cast<Aggregate*>(start);
- const NodeList& children = current->childNodes();
- for (int i=0; i<children.size(); ++i) {
- Node* n = children.at(i);
+ const NodeList &children = current->childNodes();
+ foreach (Node *n, children) {
if (n && n->name() == path.at(pathIndex)) {
if (pathIndex+1 >= path.size()) {
if (n->match(types))
@@ -792,64 +705,60 @@ const Node* Tree::matchPathAndTarget(const QStringList& path,
if (!target.isEmpty()) {
ref = getRef(target, node);
if (ref.isEmpty())
- return 0;
+ return nullptr;
}
if (node->isFunction() && node->name() == node->parent()->name())
node = node->parent();
return node;
}
- const Node* t = 0;
QString name = path.at(idx);
- QList<Node*> nodes;
- node->findChildren(name, nodes);
-
- foreach (const Node* n, nodes) {
- if (genus != Node::DontCare) {
- if (n->genus() != genus)
+ if (node->isAggregate()) {
+ NodeVector nodes;
+ static_cast<const Aggregate*>(node)->findChildren(name, nodes);
+ foreach (const Node *n, nodes) {
+ if (genus != Node::DontCare && n->genus() != genus)
continue;
+ const Node *t = matchPathAndTarget(path, idx + 1, target, n, flags, genus, ref);
+ if (t && !t->isPrivate())
+ return t;
}
- t = matchPathAndTarget(path, idx+1, target, n, flags, genus, ref);
- if (t && !t->isPrivate())
- return t;
}
if (target.isEmpty()) {
if ((idx) == (path.size()-1) && node->isAggregate() && (flags & SearchEnumValues)) {
- t = static_cast<const Aggregate*>(node)->findEnumNodeForValue(path.at(idx));
+ const Node *t = static_cast<const Aggregate*>(node)->findEnumNodeForValue(path.at(idx));
if (t)
return t;
}
}
if (((genus == Node::CPP) || (genus == Node::DontCare)) &&
node->isClass() && (flags & SearchBaseClasses)) {
- NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
- foreach (const Node* bc, baseClasses) {
- t = matchPathAndTarget(path, idx, target, bc, flags, genus, ref);
+ ClassList bases = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const ClassNode *base, bases) {
+ const Node *t = matchPathAndTarget(path, idx, target, base, flags, genus, ref);
if (t && ! t->isPrivate())
return t;
if (target.isEmpty()) {
if ((idx) == (path.size()-1) && (flags & SearchEnumValues)) {
- t = static_cast<const Aggregate*>(bc)->findEnumNodeForValue(path.at(idx));
+ t = base->findEnumNodeForValue(path.at(idx));
if (t)
return t;
}
}
}
}
- return 0;
+ return nullptr;
}
/*!
Searches the tree for a node that matches the \a path. The
search begins at \a start but can move up the parent chain
- recursively if no match is found.
-
- This findNode() callse the other findNode(), which is not
- called anywhere else.
+ recursively if no match is found. The \a flags are used to
+ restrict the search.
*/
const Node* Tree::findNode(const QStringList& path,
const Node* start,
- int findFlags,
+ int flags,
Node::Genus genus) const
{
const Node* current = start;
@@ -881,27 +790,26 @@ const Node* Tree::findNode(const QStringList& path,
}
for (i = start_idx; i < path.size(); ++i) {
- if (node == 0 || !node->isAggregate())
+ if (node == nullptr || !node->isAggregate())
break;
// Clear the TypesOnly flag until the last path segment, as e.g. namespaces are not types.
// We also ignore module nodes as they are not aggregates and thus have no children.
- int tmpFlags = (i < path.size() - 1) ? (findFlags & ~TypesOnly) | IgnoreModules : findFlags;
+ int tmpFlags = (i < path.size() - 1) ? (flags & ~TypesOnly) | IgnoreModules : flags;
const Node* next = static_cast<const Aggregate*>(node)->findChildNode(path.at(i), genus, tmpFlags);
- if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) {
+ if (!next && (flags & SearchEnumValues) && i == path.size()-1) {
next = static_cast<const Aggregate*>(node)->findEnumNodeForValue(path.at(i));
}
if (!next && ((genus == Node::CPP) || (genus == Node::DontCare)) &&
- node->isClass() && (findFlags & SearchBaseClasses)) {
- NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
- foreach (const Node* baseClass, baseClasses) {
- next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus, tmpFlags);
- if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
- next = static_cast<const Aggregate*>(baseClass)->findEnumNodeForValue(path.at(i));
- if (next) {
+ node->isClass() && (flags & SearchBaseClasses)) {
+ ClassList bases = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const ClassNode *base, bases) {
+ next = base->findChildNode(path.at(i), genus, tmpFlags);
+ if (!next && (flags & SearchEnumValues) && i == path.size() - 1)
+ next = base->findEnumNodeForValue(path.at(i));
+ if (next)
break;
- }
}
}
node = next;
@@ -911,7 +819,7 @@ const Node* Tree::findNode(const QStringList& path,
current = current->parent();
} while (current);
- return 0;
+ return nullptr;
}
/*!
@@ -1407,33 +1315,96 @@ void Tree::insertQmlType(const QString& key, QmlTypeNode* n)
}
/*!
- Split \a target on "::" and find the function node with that
- path.
+ Finds the function node with the specifried name \a path that
+ also has the specified \a parameters and returns a pointer to
+ the the first matching function node if one is found.
- This function used to return 0 if a matching node was found,
- but the node represented a macro without parameters. That test
- was removed by mws 26/01/2018.
+ This function begins searching the tree at \a relative for
+ the \l {FunctionNode} {function node} identified by \a path
+ that has the specified \a parameters. The \a flags are
+ used to restrict the search. If a matching node is found, a
+ pointer to it is returned. Otherwise, nullis returned. If
+ \a relative is ull, the search begins at the tree root.
*/
-const Node* Tree::findFunctionNode(const QString& target,
- const QString& params,
- const Node* relative,
- Node::Genus genus) const
+const FunctionNode *Tree::findFunctionNode(const QStringList &path,
+ const Parameters &parameters,
+ const Node *relative,
+ Node::Genus genus) const
{
- QString t = target;
- if (t.endsWith("()")) {
- t.chop(2);
+ if (path.size() == 3 && !path[0].isEmpty() &&
+ ((genus == Node::QML) || (genus == Node::DontCare))) {
+ QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
+ if (!qcn) {
+ QStringList p(path[1]);
+ Node *n = findNodeByNameAndType(p, Node::QmlType);
+ if (n && (n->isQmlType() || n->isJsType()))
+ qcn = static_cast<QmlTypeNode*>(n);
+ }
+ if (qcn)
+ return static_cast<const FunctionNode*>(qcn->findFunctionChild(path[2], parameters));
}
- QStringList path = t.split("::");
- return findFunctionNode(path, params, relative, SearchBaseClasses, genus);
-}
-/*!
- Search for a node that is identified by \a name.
- Return a pointer to a matching node, or 0.
-*/
-const Node* Tree::checkForCollision(const QString& name)
-{
- return findNode(QStringList(name), 0, 0, Node::DontCare);
+ if (relative == nullptr)
+ relative = root();
+ else if (genus != Node::DontCare) {
+ if (genus != relative->genus())
+ relative = root();
+ }
+
+ do {
+ Node *node = const_cast<Node *>(relative);
+ int i;
+
+ for (i = 0; i < path.size(); ++i) {
+ if (node == nullptr || !node->isAggregate())
+ break;
+
+ Aggregate *aggregate = static_cast<Aggregate*>(node);
+ Node *next = nullptr;
+ if (i == path.size() - 1)
+ next = aggregate->findFunctionChild(path.at(i), parameters);
+ else
+ next = aggregate->findChildNode(path.at(i), genus);
+
+ if (!next && aggregate->isClass()) {
+ ClassList bases = allBaseClasses(static_cast<const ClassNode*>(aggregate));
+ foreach (ClassNode *base, bases) {
+ if (i == path.size() - 1)
+ next = base->findFunctionChild(path.at(i), parameters);
+ else
+ next = base->findChildNode(path.at(i), genus);
+
+ if (next != nullptr)
+ break;
+ }
+ }
+
+ node = next;
+ } // for (i = 0; i < path.size(); ++i)
+
+ if (node && i == path.size() && node->isFunction()) {
+ // A function node was found at the end of the path.
+ // If it is not marked private, return it. If it is
+ // marked private, then if it overrides a function,
+ // find that function instead because it might not
+ // be marked private. If all the overloads are
+ // marked private, return the original function node.
+ // This should be replace with findOverriddenFunctionNode().
+ const FunctionNode *fn = static_cast<const FunctionNode*>(node);
+ const FunctionNode *FN = fn;
+ while (FN->isPrivate() && !FN->overridesThis().isEmpty()) {
+ QStringList path = FN->overridesThis().split("::");
+ FN = qdb_->findFunctionNode(path, parameters, relative, genus);
+ if (FN == nullptr)
+ break;
+ if (!FN->isPrivate())
+ return FN;
+ }
+ return fn;
+ }
+ relative = relative->parent();
+ } while (relative);
+ return nullptr;
}
/*!
@@ -1488,48 +1459,46 @@ TargetList* Tree::getTargetList(const QString& module)
node with the specified \a tag. If no function node is found
with the required \a tag, return 0.
*/
-Node* Tree::findFunctionNodeForTag(const QString &tag, Aggregate* parent)
+FunctionNode *Tree::findFunctionNodeForTag(const QString &tag, Aggregate *parent)
{
if (!parent)
parent = root();
const NodeList& children = parent->childNodes();
for (Node *n : children) {
if (n && n->isFunction() && n->hasTag(tag))
- return n;
+ return static_cast<FunctionNode*>(n);
}
for (Node *n : children) {
if (n && n->isAggregate()) {
- Aggregate* a = static_cast<Aggregate*>(n);
- n = findFunctionNodeForTag(tag, a);
+ n = findFunctionNodeForTag(tag, static_cast<Aggregate*>(n));
if (n)
- return n;
+ return static_cast<FunctionNode*>(n);
}
}
- return 0;
+ return nullptr;
}
/*!
There should only be one macro node for macro name \a t.
The macro node is not built until the \macro command is seen.
*/
-Node *Tree::findMacroNode(const QString &t, const Aggregate *parent)
+FunctionNode *Tree::findMacroNode(const QString &t, const Aggregate *parent)
{
if (!parent)
parent = root();
const NodeList &children = parent->childNodes();
for (Node *n : children) {
if (n && (n->isMacro() || n->isFunction()) && n->name() == t)
- return n;
+ return static_cast<FunctionNode*>(n);
}
for (Node *n : children) {
if (n && n->isAggregate()) {
- Aggregate *a = static_cast<Aggregate*>(n);
- n = findMacroNode(t, a);
- if (n)
- return n;
+ FunctionNode *fn = findMacroNode(t, static_cast<Aggregate*>(n));
+ if (fn)
+ return fn;
}
}
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/qdoc/tree.h b/src/qdoc/tree.h
index 145f9f8aa..86637bf3e 100644
--- a/src/qdoc/tree.h
+++ b/src/qdoc/tree.h
@@ -89,25 +89,37 @@ typedef QMap<QString, TargetList*> TargetListMap;
class Tree
{
- private:
friend class QDocForest;
friend class QDocDatabase;
+ private: // Note the constructor and destructor are private.
typedef QMap<PropertyNode::FunctionRole, QString> RoleMap;
typedef QMap<PropertyNode*, RoleMap> PropertyMap;
Tree(const QString& camelCaseModuleName, QDocDatabase* qdb);
~Tree();
+ public: // Of necessity, a few public functions remain.
+ const QString &camelCaseModuleName() const { return camelCaseModuleName_; }
+ const QString &physicalModuleName() const { return physicalModuleName_; }
+ const QString &indexFileName() const { return indexFileName_; }
+ long incrementLinkCount() { return --linkCount_; }
+ void clearLinkCount() { linkCount_ = 0; }
+ long linkCount() const { return linkCount_; }
+ const QString &indexTitle() const { return indexTitle_; }
+ void setIndexTitle(const QString &t) { indexTitle_ = t; }
+ NodeList &proxies() { return proxies_; }
+ void appendProxy(ProxyNode *t) { proxies_.append(t); }
+
+ private: // The rest of the class is private.
+ Aggregate *findAggregate(const QString &name);
Node* findNodeForInclude(const QStringList& path) const;
ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const;
NamespaceNode* findNamespaceNode(const QStringList& path) const;
- FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
- const Node* findFunctionNode(const QString& target,
- const QString& params,
- const Node* relative,
- Node::Genus genus) const;
-
+ const FunctionNode *findFunctionNode(const QStringList &path,
+ const Parameters &parameters,
+ const Node *relative,
+ Node::Genus genus) const;
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
@@ -132,14 +144,14 @@ class Tree
QString& ref) const;
const Node* findNode(const QStringList &path,
- const Node* relative, // = 0,
- int findFlags, // = 0,
- Node::Genus genus) const; // = Node::DontCare) const;
+ const Node *relative,
+ int flags,
+ Node::Genus genus) const;
QmlTypeNode* findQmlTypeNode(const QStringList& path);
Node* findNodeByNameAndType(const QStringList& path, Node::NodeType type) const;
- PageNode* findRelatesNode(const QStringList& path);
+ Aggregate *findRelatesNode(const QStringList &path);
QString getRef(const QString& target, const Node* node) const;
void insertTarget(const QString& name,
const QString& title,
@@ -153,22 +165,16 @@ class Tree
void addPropertyFunction(PropertyNode *property,
const QString &funcName,
PropertyNode::FunctionRole funcRole);
- void resolveInheritance(Aggregate* n = 0);
+ void resolveInheritance(Aggregate *n);
void resolveInheritanceHelper(int pass, ClassNode* cn);
void resolveProperties();
void resolveCppToQmlLinks();
void resolveUsingClauses();
- void fixInheritance(NamespaceNode *rootNode = 0);
+ void fixInheritance(NamespaceNode *rootNode);
NamespaceNode *root() { return &root_; }
-
- const FunctionNode *findFunctionNode(const QStringList &path,
- const QString& params,
- const Node *relative = 0,
- int findFlags = 0,
- Node::Genus genus = Node::DontCare) const;
const NamespaceNode *root() const { return &root_; }
- NodeList allBaseClasses(const ClassNode *classe) const;
+ ClassList allBaseClasses(const ClassNode *classe) const;
QString refForAtom(const Atom* atom);
CNMap* getCollectionMap(Node::NodeType type);
@@ -200,7 +206,6 @@ class Tree
void insertQmlType(const QString& key, QmlTypeNode* n);
void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); }
ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; }
- const Node* checkForCollision(const QString& name);
void setIndexFileName(const QString& t) { indexFileName_ = t; }
bool treeHasBeenAnalyzed() const { return treeHasBeenAnalyzed_; }
@@ -214,18 +219,8 @@ class Tree
bool broken);
TargetList* getTargetList(const QString& module);
QStringList getTargetListKeys() { return targetListMap_->keys(); }
- Node* findFunctionNodeForTag(const QString &tag, Aggregate* parent = 0);
- Node *findMacroNode(const QString &t, const Aggregate *parent = 0);
-
- public:
- const QString& camelCaseModuleName() const { return camelCaseModuleName_; }
- const QString& physicalModuleName() const { return physicalModuleName_; }
- const QString& indexFileName() const { return indexFileName_; }
- long incrementLinkCount() { return --linkCount_; }
- void clearLinkCount() { linkCount_ = 0; }
- long linkCount() const { return linkCount_; }
- const QString& indexTitle() const { return indexTitle_; }
- void setIndexTitle(const QString &t) { indexTitle_ = t; }
+ FunctionNode *findFunctionNodeForTag(const QString &tag, Aggregate *parent = 0);
+ FunctionNode *findMacroNode(const QString &t, const Aggregate *parent = 0);
private:
bool treeHasBeenAnalyzed_;
@@ -248,6 +243,7 @@ private:
QmlTypeMap qmlTypeMap_;
ExampleNodeMap exampleNodeMap_;
TargetListMap* targetListMap_;
+ NodeList proxies_;
};
QT_END_NAMESPACE
diff --git a/src/qdoc/webxmlgenerator.cpp b/src/qdoc/webxmlgenerator.cpp
index 167ba2496..7202d3651 100644
--- a/src/qdoc/webxmlgenerator.cpp
+++ b/src/qdoc/webxmlgenerator.cpp
@@ -71,17 +71,17 @@ int WebXMLGenerator::generateAtom(const Atom * /* atom, */,
return 0;
}
-void WebXMLGenerator::generateCppReferencePage(Node *node, CodeMarker *marker)
+void WebXMLGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker)
{
QByteArray data;
QXmlStreamWriter writer(&data);
writer.setAutoFormatting(true);
- beginSubPage(node, Generator::fileName(node, "webxml"));
+ beginSubPage(aggregate, Generator::fileName(aggregate, "webxml"));
writer.writeStartDocument();
writer.writeStartElement("WebXML");
writer.writeStartElement("document");
- generateIndexSections(writer, node, marker);
+ generateIndexSections(writer, aggregate, marker);
writer.writeEndElement(); // document
writer.writeEndElement(); // WebXML
@@ -93,7 +93,22 @@ void WebXMLGenerator::generateCppReferencePage(Node *node, CodeMarker *marker)
void WebXMLGenerator::generatePageNode(PageNode *pn, CodeMarker *marker)
{
- generateCppReferencePage(pn, marker);
+ QByteArray data;
+ QXmlStreamWriter writer(&data);
+ writer.setAutoFormatting(true);
+ beginSubPage(pn, Generator::fileName(pn, "webxml"));
+ writer.writeStartDocument();
+ writer.writeStartElement("WebXML");
+ writer.writeStartElement("document");
+
+ generateIndexSections(writer, pn, marker);
+
+ writer.writeEndElement(); // document
+ writer.writeEndElement(); // WebXML
+ writer.writeEndDocument();
+
+ out() << data;
+ endSubPage();
}
void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer,
@@ -166,8 +181,6 @@ void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer,
if (node->isAggregate()) {
for (auto child : static_cast<Aggregate *>(node)->childNodes())
generateIndexSections(writer, child, marker);
- for (auto related : static_cast<Aggregate *>(node)->relatedNodes())
- generateIndexSections(writer, related, marker);
}
writer.writeEndElement();
}
@@ -191,7 +204,7 @@ void WebXMLGenerator::generateDocumentation(Node *node)
if (node->wasSeen()) {
// see remarks in base class impl.
qdb_->mergeCollections(static_cast<CollectionNode *>(node));
- generateCppReferencePage(node, marker);
+ generatePageNode(static_cast<PageNode *>(node), marker);
}
}
else if (node->isTextPageNode())
diff --git a/src/qdoc/webxmlgenerator.h b/src/qdoc/webxmlgenerator.h
index 6e6f8069f..b5cb0e8b4 100644
--- a/src/qdoc/webxmlgenerator.h
+++ b/src/qdoc/webxmlgenerator.h
@@ -50,7 +50,7 @@ public:
protected:
int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override;
- void generateCppReferencePage(Node *node, CodeMarker *marker) override;
+ void generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker) override;
void generatePageNode(PageNode *pn, CodeMarker *marker) override;
void generateDocumentation(Node *node) override;
QString fileExtension() const override;