summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/qdoc/clangcodeparser.cpp41
-rw-r--r--src/qdoc/codemarker.cpp2
-rw-r--r--src/qdoc/codeparser.cpp26
-rw-r--r--src/qdoc/codeparser.h2
-rw-r--r--src/qdoc/cppcodeparser.cpp47
-rw-r--r--src/qdoc/cppcodeparser.h4
-rw-r--r--src/qdoc/generator.cpp12
-rw-r--r--src/qdoc/helpprojectwriter.cpp10
-rw-r--r--src/qdoc/htmlgenerator.cpp40
-rw-r--r--src/qdoc/node.cpp81
-rw-r--r--src/qdoc/node.h31
-rw-r--r--src/qdoc/qdocdatabase.cpp14
-rw-r--r--src/qdoc/qdocdatabase.h12
-rw-r--r--src/qdoc/qdocindexfiles.cpp20
-rw-r--r--src/qdoc/qdoctagfiles.cpp8
-rw-r--r--src/qdoc/sections.cpp20
-rw-r--r--src/qdoc/tree.cpp144
-rw-r--r--src/qdoc/tree.h13
-rw-r--r--src/qdoc/webxmlgenerator.cpp4
19 files changed, 338 insertions, 193 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index cace61b9c..298669764 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -230,14 +230,15 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
return nullptr;
auto parent = static_cast<Aggregate *>(p);
+ QString name = fromCXString(clang_getCursorSpelling(cur));
switch (kind) {
case CXCursor_Namespace:
- return parent->findChildNode(fromCXString(clang_getCursorSpelling(cur)), Node::Namespace);
+ return parent->findNonfunctionChild(name, &Node::isNamespace);
case CXCursor_StructDecl:
case CXCursor_ClassDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassTemplate:
- return parent->findChildNode(fromCXString(clang_getCursorSpelling(cur)), Node::Class);
+ return parent->findNonfunctionChild(name, &Node::isClassNode);
case CXCursor_FunctionDecl:
case CXCursor_FunctionTemplate:
case CXCursor_CXXMethod:
@@ -288,12 +289,12 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) {
return nullptr;
}
case CXCursor_EnumDecl:
- return parent->findChildNode(fromCXString(clang_getCursorSpelling(cur)), Node::Enum);
+ return parent->findNonfunctionChild(name, &Node::isEnumType);
case CXCursor_FieldDecl:
case CXCursor_VarDecl:
- return parent->findChildNode(fromCXString(clang_getCursorSpelling(cur)), Node::Variable);
+ return parent->findNonfunctionChild(name, &Node::isVariable);
case CXCursor_TypedefDecl:
- return parent->findChildNode(fromCXString(clang_getCursorSpelling(cur)), Node::Typedef);
+ return parent->findNonfunctionChild(name, &Node::isTypedef);
default:
return nullptr;
}
@@ -462,7 +463,7 @@ private:
*/
QString adjustTypeName(const QString &typeName) {
auto parent = parent_->parent();
- if (parent && parent->isClass()) {
+ if (parent && parent->isClassNode()) {
QStringRef typeNameConstRemoved(&typeName);
if (typeNameConstRemoved.startsWith(QLatin1String("const ")))
typeNameConstRemoved = typeName.midRef(6);
@@ -575,7 +576,6 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
Q_FALLTHROUGH();
case CXCursor_ClassDecl:
case CXCursor_ClassTemplate: {
-
if (!clang_isCursorDefinition(cursor))
return CXChildVisit_Continue;
@@ -585,11 +585,18 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
QString className = fromCXString(clang_getCursorSpelling(cursor));
Aggregate* semanticParent = getSemanticParent(cursor);
- if (semanticParent && semanticParent->findChildNode(className, Node::Class)) {
+ if (semanticParent && semanticParent->findNonfunctionChild(className, &Node::isClassNode)) {
return CXChildVisit_Continue;
}
- ClassNode *classe = new ClassNode(semanticParent, className);
+ Node::NodeType type;
+ if (kind == CXCursor_ClassDecl || kind == CXCursor_ClassTemplate)
+ type = Node::Class;
+ else if (kind == CXCursor_StructDecl)
+ type = Node::Struct;
+ else
+ type = Node::Union;
+ ClassNode *classe = new ClassNode(type, semanticParent, className);
classe->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor)));
classe->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor)));
@@ -603,14 +610,14 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
}
case CXCursor_CXXBaseSpecifier: {
- if (!parent_->isClass())
+ if (!parent_->isClassNode())
return CXChildVisit_Continue;
auto access = fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor));
auto type = clang_getCursorType(cursor);
auto baseCursor = clang_getTypeDeclaration(type);
auto baseNode = findNodeForCursor(qdb_, baseCursor);
auto classe = static_cast<ClassNode*>(parent_);
- if (!baseNode || !baseNode->isClass()) {
+ if (!baseNode || !baseNode->isClassNode()) {
QString bcName = fromCXString(clang_getCursorSpelling(baseCursor));
classe->addUnresolvedBaseClass(access, QStringList(bcName), bcName);
return CXChildVisit_Continue;
@@ -623,7 +630,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
QString namespaceName = fromCXString(clang_getCursorDisplayName(cursor));
NamespaceNode* ns = nullptr;
if (parent_)
- ns = static_cast<NamespaceNode*>(parent_->findChildNode(namespaceName, Node::Namespace));
+ ns = static_cast<NamespaceNode*>(parent_->findNonfunctionChild(namespaceName, &Node::isNamespace));
if (!ns) {
ns = new NamespaceNode(parent_, namespaceName);
ns->setAccess(Node::Public);
@@ -734,7 +741,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
case CXCursor_FriendDecl: {
// Friend functions are declared in the enclosing namespace
Aggregate *ns = parent_;
- while (ns && ns->isClass())
+ while (ns && ns->isClassNode())
ns = ns->parent();
QScopedValueRollback<Aggregate *> setParent(parent_, ns);
// Visit the friend functions
@@ -748,8 +755,8 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
EnumNode* en = nullptr;
if (enumTypeName.isEmpty()) {
enumTypeName = "anonymous";
- if (parent_ && (parent_->isClass() || parent_->isNamespace())) {
- Node* n = parent_->findChildNode(enumTypeName, Node::Enum);
+ if (parent_ && (parent_->isClassNode() || parent_->isNamespace())) {
+ Node* n = parent_->findNonfunctionChild(enumTypeName, &Node::isEnumType);
if (n)
en = static_cast<EnumNode*>(n);
}
@@ -796,7 +803,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
var->setAccess(access);
var->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor)));
var->setLeftType(fromCXString(clang_getTypeSpelling(clang_getCursorType(cursor))));
- var->setStatic(kind == CXCursor_VarDecl && parent_->isClass());
+ var->setStatic(kind == CXCursor_VarDecl && parent_->isClassNode());
return CXChildVisit_Continue;
}
case CXCursor_TypedefDecl: {
@@ -824,7 +831,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
return CXChildVisit_Continue;
}
default:
- if (clang_isDeclaration(kind) && parent_->isClass()) {
+ if (clang_isDeclaration(kind) && parent_->isClassNode()) {
// maybe a static_assert (which is not exposed from the clang API)
QString spelling = getSpelling(clang_getCursorExtent(cursor));
if (spelling.startsWith(QLatin1String("Q_PROPERTY"))
diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp
index cd47942f0..3c88edf03 100644
--- a/src/qdoc/codemarker.cpp
+++ b/src/qdoc/codemarker.cpp
@@ -267,6 +267,8 @@ QString CodeMarker::taggedNode(const Node* node)
tag = QLatin1String("@namespace");
break;
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
tag = QLatin1String("@class");
break;
case Node::Enum:
diff --git a/src/qdoc/codeparser.cpp b/src/qdoc/codeparser.cpp
index 925f1c665..42adae244 100644
--- a/src/qdoc/codeparser.cpp
+++ b/src/qdoc/codeparser.cpp
@@ -303,23 +303,27 @@ void CodeParser::checkModuleInclusion(Node* n)
{
if (n->physicalModuleName().isEmpty()) {
n->setPhysicalModuleName(Generator::defaultModuleName());
+ QString word;
switch (n->nodeType()) {
case Node::Class:
- if (n->access() != Node::Private && !n->doc().isEmpty()) {
- n->doc().location().warning(tr("Class %1 has no \\inmodule command; "
- "using project name by default: %2")
- .arg(n->name()).arg(Generator::defaultModuleName()));
- }
+ word = QLatin1String("Class");
+ break;
+ case Node::Struct:
+ word = QLatin1String("Struct");
+ break;
+ case Node::Union:
+ word = QLatin1String("Union");
break;
case Node::Namespace:
- if (n->access() != Node::Private && !n->name().isEmpty() && !n->doc().isEmpty()) {
- n->doc().location().warning(tr("Namespace %1 has no \\inmodule command; "
- "using project name by default: %2")
- .arg(n->name()).arg(Generator::defaultModuleName()));
- }
+ word = QLatin1String("Namespace");
break;
default:
- break;
+ return;
+ }
+ if (!n->isPrivate() && !n->name().isEmpty() && !n->doc().isEmpty()) {
+ n->doc().location().warning(tr("%1 %2 has no \\inmodule command; "
+ "using project name by default: %3")
+ .arg(word).arg(n->name()).arg(Generator::defaultModuleName()));
}
}
}
diff --git a/src/qdoc/codeparser.h b/src/qdoc/codeparser.h
index 7bf6bb807..dd0191e86 100644
--- a/src/qdoc/codeparser.h
+++ b/src/qdoc/codeparser.h
@@ -167,6 +167,7 @@ private:
#define COMMAND_RELATES Doc::alias(QLatin1String("relates"))
#define COMMAND_RELEASEDATE Doc::alias(QLatin1String("releasedate"))
#define COMMAND_SINCE Doc::alias(QLatin1String("since"))
+#define COMMAND_STRUCT Doc::alias(QLatin1String("struct"))
#define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle"))
#define COMMAND_STARTPAGE Doc::alias(QLatin1String("startpage"))
#define COMMAND_THREADSAFE Doc::alias(QLatin1String("threadsafe"))
@@ -175,6 +176,7 @@ private:
#define COMMAND_TYPEDEF Doc::alias(QLatin1String("typedef"))
#define COMMAND_VARIABLE Doc::alias(QLatin1String("variable"))
#define COMMAND_VERSION Doc::alias(QLatin1String("version"))
+#define COMMAND_UNION Doc::alias(QLatin1String("union"))
#define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper"))
QT_END_NAMESPACE
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp
index a889c988e..4f5eb9bdc 100644
--- a/src/qdoc/cppcodeparser.cpp
+++ b/src/qdoc/cppcodeparser.cpp
@@ -93,7 +93,9 @@ CppCodeParser::CppCodeParser()
<< COMMAND_JSMETHOD
<< COMMAND_JSATTACHEDMETHOD
<< COMMAND_JSBASICTYPE
- << COMMAND_JSMODULE;
+ << COMMAND_JSMODULE
+ << COMMAND_STRUCT
+ << COMMAND_UNION;
}
if (metaCommands_.isEmpty()) {
metaCommands_ = commonMetaCommands();
@@ -121,13 +123,26 @@ void CppCodeParser::initializeParser(const Config &config)
All these can appear in a C++ namespace. Don't add
anything that can't be in a C++ namespace.
*/
- nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace);
- nodeTypeMap.insert(COMMAND_CLASS, Node::Class);
- nodeTypeMap.insert(COMMAND_ENUM, Node::Enum);
- nodeTypeMap.insert(COMMAND_TYPEALIAS, Node::Typedef);
- nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef);
- nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
- nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable);
+ nodeTypeMap_.insert(COMMAND_NAMESPACE, Node::Namespace);
+ nodeTypeMap_.insert(COMMAND_CLASS, Node::Class);
+ nodeTypeMap_.insert(COMMAND_STRUCT, Node::Struct);
+ nodeTypeMap_.insert(COMMAND_UNION, Node::Union);
+ nodeTypeMap_.insert(COMMAND_ENUM, Node::Enum);
+ nodeTypeMap_.insert(COMMAND_TYPEALIAS, Node::Typedef);
+ nodeTypeMap_.insert(COMMAND_TYPEDEF, Node::Typedef);
+ nodeTypeMap_.insert(COMMAND_PROPERTY, Node::Property);
+ nodeTypeMap_.insert(COMMAND_VARIABLE, Node::Variable);
+
+ nodeTypeTestFuncMap_.insert(COMMAND_NAMESPACE, &Node::isNamespace);
+ nodeTypeTestFuncMap_.insert(COMMAND_CLASS, &Node::isClassNode);
+ nodeTypeTestFuncMap_.insert(COMMAND_STRUCT, &Node::isStruct);
+ nodeTypeTestFuncMap_.insert(COMMAND_UNION, &Node::isUnion);
+ nodeTypeTestFuncMap_.insert(COMMAND_ENUM, &Node::isEnumType);
+ nodeTypeTestFuncMap_.insert(COMMAND_TYPEALIAS, &Node::isTypedef);
+ nodeTypeTestFuncMap_.insert(COMMAND_TYPEDEF, &Node::isTypedef);
+ nodeTypeTestFuncMap_.insert(COMMAND_PROPERTY, &Node::isProperty);
+ nodeTypeTestFuncMap_.insert(COMMAND_VARIABLE, &Node::isVariable);
+
exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES);
exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS);
@@ -158,7 +173,8 @@ void CppCodeParser::initializeParser(const Config &config)
*/
void CppCodeParser::terminateParser()
{
- nodeTypeMap.clear();
+ nodeTypeMap_.clear();
+ nodeTypeTestFuncMap_.clear();
excludeDirs.clear();
excludeFiles.clear();
CodeParser::terminateParser();
@@ -200,7 +216,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
if (command == COMMAND_FN) {
Q_UNREACHABLE();
}
- else if (nodeTypeMap.contains(command)) {
+ else if (nodeTypeMap_.contains(command)) {
/*
We should only get in here if the command refers to
something that can appear in a C++ namespace,
@@ -209,7 +225,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
this way to allow the writer to refer to the entity
without including the namespace qualifier.
*/
- Node::NodeType type = nodeTypeMap[command];
+ Node::NodeType type = nodeTypeMap_[command];
QStringList words = arg.first.split(QLatin1Char(' '));
QStringList path;
int idx = 0;
@@ -219,9 +235,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
idx = words.size() - 1;
path = words[idx].split("::");
- node = qdb_->findNodeInOpenNamespace(path, type);
+ node = qdb_->findNodeInOpenNamespace(path, nodeTypeTestFuncMap_[command]);
if (node == 0)
- node = qdb_->findNodeByNameAndType(path, type);
+ node = qdb_->findNodeByNameAndType(path, nodeTypeTestFuncMap_[command]);
if (node == 0) {
if (isWorthWarningAbout(doc)) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
@@ -237,7 +253,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
/*
This treats a class as a namespace.
*/
- if ((type == Node::Class) || (type == Node::Namespace)) {
+ if ((type == Node::Class) ||
+ (type == Node::Namespace) ||
+ (type == Node::Struct) ||
+ (type == Node::Union)) {
if (path.size() > 1) {
path.pop_back();
QString ns = path.join(QLatin1String("::"));
diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h
index 76669f965..12bed3ada 100644
--- a/src/qdoc/cppcodeparser.h
+++ b/src/qdoc/cppcodeparser.h
@@ -95,7 +95,9 @@ protected:
void setExampleFileLists(PageNode *pn);
protected:
- QMap<QString, Node::NodeType> nodeTypeMap;
+ typedef bool (Node::*NodeTypeTestFunc) () const;
+ QMap<QString, NodeTypeTestFunc> nodeTypeTestFuncMap_;
+ QMap<QString, Node::NodeType> nodeTypeMap_;
private:
static QStringList exampleFiles;
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 82878ac43..be5f6b20c 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -611,6 +611,8 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
switch (node->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
case Node::Namespace:
case Node::Proxy:
parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
@@ -692,7 +694,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
break;
}
- if (!node->isClass() && !node->isNamespace()) {
+ if (!node->isClassNode() && !node->isNamespace()) {
if (node->status() == Node::Obsolete)
parentName.replace(QLatin1Char('.') + currentGenerator()->fileExtension(),
"-obsolete." + currentGenerator()->fileExtension());
@@ -1143,7 +1145,7 @@ void Generator::generateDocumentation(Node* node)
generatePageNode(static_cast<PageNode*>(node), marker);
endSubPage();
} else if (node->isAggregate()) {
- if (node->isClass() || node->isHeader() ||
+ if (node->isClassNode() || node->isHeader() ||
(node->isNamespace() && node->docMustBeGenerated())) {
beginSubPage(node, fileName(node));
generateCppReferencePage(static_cast<Aggregate*>(node), marker);
@@ -1252,7 +1254,7 @@ bool Generator::generateQmlText(const Text& text,
void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *marker)
{
if (!fn->overridesThis().isEmpty()) {
- if (fn->parent()->isClass()) {
+ if (fn->parent()->isClassNode()) {
ClassNode* cn = static_cast<ClassNode*>(fn->parent());
const FunctionNode *overrides = cn->findOverriddenFunction(fn);
if (overrides && !overrides->isPrivate() && !overrides->parent()->isPrivate()) {
@@ -2185,6 +2187,10 @@ QString Generator::typeString(const Node *node)
return "namespace";
case Node::Class:
return "class";
+ case Node::Struct:
+ return "struct";
+ case Node::Union:
+ return "union";
case Node::QmlType:
return "type";
case Node::QmlBasicType:
diff --git a/src/qdoc/helpprojectwriter.cpp b/src/qdoc/helpprojectwriter.cpp
index ec6f46b59..f125a4a54 100644
--- a/src/qdoc/helpprojectwriter.cpp
+++ b/src/qdoc/helpprojectwriter.cpp
@@ -121,6 +121,8 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
QHash<QString, Node::NodeType> typeHash;
typeHash["namespace"] = Node::Namespace;
typeHash["class"] = Node::Class;
+ typeHash["struct"] = Node::Struct;
+ typeHash["union"] = Node::Union;
typeHash["header"] = Node::HeaderFile;
typeHash["headerfile"] = Node::HeaderFile;
typeHash["doc"] = Node::Page; // to be removed from qdocconf files
@@ -293,6 +295,8 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
switch (node->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
project.keywords.append(keywordDetails(node));
break;
case Node::QmlType:
@@ -559,7 +563,7 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write
return;
bool derivedClass = false;
- if (node->isClass())
+ if (node->isClassNode())
derivedClass = !(static_cast<const ClassNode *>(node)->baseClasses().isEmpty());
// Do not generate a 'List of all members' for namespaces or header files,
@@ -585,6 +589,8 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
switch (node->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
writer.writeStartElement("section");
writer.writeAttribute("ref", href);
if (node->parent() && !node->parent()->name().isEmpty())
@@ -708,7 +714,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
writer.writeStartElement("section");
const Node* node = qdb_->findPageNodeByTitle(project.indexTitle);
if (node == 0)
- node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Page);
+ node = qdb_->findNodeByNameAndType(QStringList("index.html"), &Node::isPageNode);
QString indexPath;
if (node)
indexPath = gen_->fullDocumentLocation(node, false);
diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp
index a466fe227..06da48698 100644
--- a/src/qdoc/htmlgenerator.cpp
+++ b/src/qdoc/htmlgenerator.cpp
@@ -1349,6 +1349,7 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
SectionVector *detailsSections = 0;
Sections sections(aggregate);
+ QString word = aggregate->typeWord(true);
if (aggregate->isNamespace()) {
rawTitle = aggregate->plainName();
fullTitle = aggregate->plainFullName();
@@ -1357,10 +1358,14 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
summarySections = &sections.stdSummarySections();
detailsSections = &sections.stdDetailsSections();
}
- else if (aggregate->isClass()) {
+ else if (aggregate->isClassNode()) {
rawTitle = aggregate->plainName();
fullTitle = aggregate->plainFullName();
- title = rawTitle + " Class";
+ if (aggregate->isStruct())
+ word = QLatin1String("Struct");
+ else if (aggregate->isUnion())
+ word = QLatin1String("Union");
+ title = rawTitle + " " + word;
summarySections = &sections.stdCppClassSummarySections();
detailsSections = &sections.stdCppClassDetailsSections();
}
@@ -1373,8 +1378,16 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
}
Text subtitleText;
- if (rawTitle != fullTitle)
- subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak);
+ if (rawTitle != fullTitle) {
+ if (aggregate->parent()->isClassNode()) {
+ QString word2 = aggregate->parent()->typeWord(false);
+ subtitleText << word << " " << rawTitle << " is declared in " << word2
+ << " " << Atom(Atom::AutoLink, aggregate->parent()->plainName())
+ << "." << Atom(Atom::LineBreak);
+ } else {
+ subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak);
+ }
+ }
generateHeader(title, aggregate, marker);
generateTableOfContents(aggregate, marker, summarySections);
@@ -1396,7 +1409,8 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
}
else
generateBrief(aggregate, marker);
- generateRequisites(aggregate, marker);
+ if (!aggregate->parent()->isClassNode())
+ generateRequisites(aggregate, marker);
generateStatus(aggregate, marker);
generateSince(aggregate, marker);
@@ -1499,7 +1513,7 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
out() << "<h2>" << protectEnc(s->title()) << "</h2>\n";
headerGenerated = true;
}
- if (!(*m)->isClass())
+ if (!(*m)->isClassNode())
generateDetailedMember(*m, aggregate, marker);
else {
out() << "<h3> class ";
@@ -1606,7 +1620,7 @@ void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker)
NodeVector::ConstIterator m = s->members().constBegin();
while (m != s->members().constEnd()) {
if (!(*m)->isPrivate()) { // ### check necessary?
- if (!(*m)->isClass())
+ if (!(*m)->isClassNode())
generateDetailedMember(*m, aggregate, marker);
else {
out() << "<h3> class ";
@@ -1971,7 +1985,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(itemRight);
- if (node->isClass()) {
+ if (node->isClassNode()) {
if (!cppclassespage.isEmpty() && !cppclassestitle.isEmpty())
navigationbar << Atom(itemLeft)
<< Atom(Atom::NavLink, cppclassespage)
@@ -2002,7 +2016,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
if (node->isAggregate()) {
QStringList groups = static_cast<const Aggregate*>(node)->groupNames();
if (groups.length() == 1) {
- const Node *groupNode = qdb_->findNodeByNameAndType(QStringList(groups[0]), Node::Group);
+ const Node *groupNode = qdb_->findNodeByNameAndType(QStringList(groups[0]), &Node::isGroup);
if (groupNode && !groupNode->title().isEmpty()) {
navigationbar << Atom(itemLeft)
<< Atom(Atom::NavLink, groupNode->name())
@@ -2283,7 +2297,7 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker)
requisites.insert(sinceText, text);
}
- if (aggregate->isClass() || aggregate->isNamespace()) {
+ if (aggregate->isClassNode() || aggregate->isNamespace()) {
//add the QT variable to the map
if (!aggregate->physicalModuleName().isEmpty()) {
const CollectionNode* cn = qdb_->getCollectionNode(aggregate->physicalModuleName(), Node::Module);
@@ -2295,7 +2309,7 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker)
}
}
- if (aggregate->isClass()) {
+ if (aggregate->isClassNode()) {
ClassNode* classe = static_cast<ClassNode*>(aggregate);
if (classe->qmlElement() != nullptr && classe->status() != Node::Internal) {
text.clear();
@@ -2567,7 +2581,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
}
}
}
- else if (sections && (node->isClass() ||
+ else if (sections && (node->isClassNode() ||
node->isNamespace() ||
node->isQmlType() ||
node->isJsType())) {
@@ -4092,6 +4106,8 @@ int HtmlGenerator::hOffset(const Node *node)
switch (node->nodeType()) {
case Node::Namespace:
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
case Node::Module:
return 2;
case Node::QmlModule:
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index f80aaf699..992d683f4 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -56,6 +56,8 @@ void Node::initialize()
{
goals_.insert("namespace", Node::Namespace);
goals_.insert("class", Node::Class);
+ goals_.insert("struct", Node::Struct);
+ goals_.insert("union", Node::Union);
goals_.insert("header", Node::HeaderFile);
goals_.insert("headerfile", Node::HeaderFile);
goals_.insert("page", Node::Page);
@@ -383,6 +385,8 @@ Node::PageType Node::getPageType(Node::NodeType t)
switch (t) {
case Node::Namespace:
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
case Node::HeaderFile:
case Node::Enum:
case Node::Function:
@@ -430,6 +434,8 @@ Node::Genus Node::getGenus(Node::NodeType t)
switch (t) {
case Node::Enum:
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
case Node::Module:
case Node::Typedef:
case Node::Property:
@@ -532,6 +538,10 @@ QString Node::nodeTypeString(unsigned char t)
return QLatin1String("namespace");
case Class:
return QLatin1String("class");
+ case Struct:
+ return QLatin1String("struct");
+ case Union:
+ return QLatin1String("union");
case HeaderFile:
return QLatin1String("header");
case Page:
@@ -989,7 +999,7 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF
if (genus == node->genus()) {
if (findFlags & TypesOnly) {
if (!node->isTypedef()
- && !node->isClass()
+ && !node->isClassNode()
&& !node->isQmlType()
&& !node->isQmlBasicType()
&& !node->isJsType()
@@ -1058,18 +1068,18 @@ void Aggregate::findChildren(const QString &name, NodeVector &nodes) const
}
/*!
- This function is like findChildNode(), but if a node
- with the specified \a name is found but it is not of the
- specified \a type, 0 is returned.
+ This function searches for a child node of this Aggregate,
+ such that the child node has the spacified \a name and the
+ function \a isMatch returns true for the node. The function
+ passed must be one of the isXxx() functions in class Node
+ that tests the node type.
*/
-Node* Aggregate::findChildNode(const QString& name, NodeType type)
+Node* Aggregate::findNonfunctionChild(const QString& name, bool (Node::*isMatch) () const)
{
- if (type == Function)
- 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)
+ Node* node = nodes.at(i);
+ if ((node->*(isMatch))())
return node;
}
return nullptr;
@@ -1778,7 +1788,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
while (bc != baseClasses().constEnd()) {
ClassNode* cn = bc->node_;
if (cn) {
- Node* n = cn->findChildNode(pn->name(), Node::Property);
+ Node* n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
if (n) {
PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
cn->fixPropertyUsingBaseClasses(baseProperty);
@@ -1797,7 +1807,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
*/
PropertyNode* ClassNode::findPropertyNode(const QString& name)
{
- Node* n = findChildNode(name, Node::Property);
+ Node* n = findNonfunctionChild(name, &Node::isProperty);
if (n)
return static_cast<PropertyNode*>(n);
@@ -2174,7 +2184,7 @@ void FunctionNode::setVirtualness(const QString& t)
virtualness_ = NormalVirtual;
else if (t == QLatin1String("pure")) {
virtualness_ = PureVirtual;
- if (parent() && parent()->isClass())
+ if (parent() && parent()->isClassNode())
parent()->setAbstract(true);
}
}
@@ -3303,12 +3313,12 @@ void Aggregate::findAllObsoleteThings()
if (!n->isPrivate()) {
QString name = n->name();
if (n->isObsolete()) {
- if (n->isClass())
+ if (n->isClassNode())
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);
+ } else if (n->isClassNode()) {
+ Aggregate* a = static_cast<Aggregate*>(n);
if (a->hasObsoleteMembers())
QDocDatabase::classesWithObsoleteMembers().insert(n->qualifyCppName(), n);
}
@@ -3334,7 +3344,7 @@ void Aggregate::findAllClasses()
foreach (Node *n, children_) {
if (!n->isPrivate() && !n->isInternal() &&
n->tree()->camelCaseModuleName() != QString("QDoc")) {
- if (n->isClass()) {
+ if (n->isClassNode()) {
QDocDatabase::cppClasses().insert(n->qualifyCppName().toLower(), n);
} else if (n->isQmlType() || n->isQmlBasicType() || n->isJsType() || n->isJsBasicType()) {
QString name = n->unqualifyQmlName();
@@ -3404,7 +3414,7 @@ void Aggregate::findAllSince()
if (!fn->isObsolete() && !fn->isSomeCtor() && !fn->isDtor())
nsmap.value().insert(fn->name(), fn);
}
- else if (n->isClass()) {
+ else if (n->isClassNode()) {
// Insert classes into the since and class maps.
QString name = n->qualifyWithParentName();
nsmap.value().insert(name, n);
@@ -3477,6 +3487,39 @@ void Aggregate::resolveQmlInheritance()
}
/*!
+ Returns a word representing the kind of Aggregate this node is.
+ Currently only works for class, struct, and union, but it can
+ easily be extended. If \a cap is true, the word is capitalised.
+ */
+QString Aggregate::typeWord(bool cap) const
+{
+ if (cap) {
+ switch (nodeType()) {
+ case Node::Class:
+ return QLatin1String("Class");
+ case Node::Struct:
+ return QLatin1String("Struct");
+ case Node::Union:
+ return QLatin1String("Union");
+ default:
+ break;
+ }
+ } else {
+ switch (nodeType()) {
+ case Node::Class:
+ return QLatin1String("class");
+ case Node::Struct:
+ return QLatin1String("struct");
+ case Node::Union:
+ return QLatin1String("union");
+ default:
+ break;
+ }
+ }
+ return QString();
+}
+
+/*!
\class ProxyNode
\brief A class for representing an Aggregate that is documented in a different module.
@@ -3561,7 +3604,7 @@ bool CollectionNode::hasClasses() const
if (!members_.isEmpty()) {
NodeList::const_iterator i = members_.cbegin();
while (i != members_.cend()) {
- if ((*i)->isClass())
+ if ((*i)->isClassNode())
return true;
++i;
}
@@ -3593,7 +3636,7 @@ void CollectionNode::getMemberClasses(NodeMap& out) const
out.clear();
NodeList::const_iterator i = members_.cbegin();
while (i != members_.cend()) {
- if ((*i)->isClass())
+ if ((*i)->isClassNode())
out.insert((*i)->name(),(*i));
++i;
}
diff --git a/src/qdoc/node.h b/src/qdoc/node.h
index f882ec565..155ece365 100644
--- a/src/qdoc/node.h
+++ b/src/qdoc/node.h
@@ -76,6 +76,8 @@ public:
NoType,
Namespace,
Class,
+ Struct,
+ Union,
HeaderFile,
Page,
Enum,
@@ -168,6 +170,7 @@ public:
static PageType getPageType(NodeType t);
bool isActive() const { return (status_ == (unsigned char) Active); }
+ bool isAnyType() const { return true; }
bool isClass() const { return nodeType_ == Class; }
bool isCppNode() const { return genus() == CPP; }
bool isEnumType() const { return nodeType_ == Enum; }
@@ -201,16 +204,20 @@ public:
bool isQmlPropertyGroup() const { return nodeType_ == QmlPropertyGroup; }
bool isQmlType() const { return nodeType_ == QmlType; }
bool isRelatedNonmember() const { return relatedNonmember_; }
+ bool isStruct() const { return nodeType_ == Struct; }
bool isSharedCommentNode() const { return nodeType_ == SharedComment; }
bool isTypeAlias() const { return nodeType_ == Typedef; }
bool isTypedef() const { return nodeType_ == Typedef; }
+ bool isUnion() const { return nodeType_ == Union; }
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"
+ virtual bool isFirstClassAggregate() const { return false; } // Aggregate but not proxy or prop group"
virtual bool isAlias() const { return false; }
virtual bool isAttached() const { return false; }
+ virtual bool isClassNode() const { return false; }
virtual bool isCollectionNode() const { return false; }
virtual bool isDefault() const { return false; }
virtual bool isInternal() const;
@@ -218,6 +225,7 @@ public:
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 isRelatableType() 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
@@ -442,10 +450,10 @@ class Aggregate : public PageNode
{
public:
Node* findChildNode(const QString& name, Node::Genus genus, int findFlags = 0) const;
- Node* findChildNode(const QString& name, NodeType type);
- void findChildren(const QString &name, NodeVector &nodes) const;
- FunctionNode *findFunctionChild(const QString &name, const Parameters &parameters);
- FunctionNode *findFunctionChild(const FunctionNode *clone);
+ Node* findNonfunctionChild(const QString& name, bool (Node::*) () 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 markUndocumentedChildrenInternal();
@@ -485,6 +493,7 @@ public:
bool hasOverloads(const FunctionNode *fn) const;
void appendToRelatedByProxy(const NodeList &t) { relatedByProxy_.append(t); }
NodeList &relatedByProxy() { return relatedByProxy_; }
+ QString typeWord(bool cap) const;
protected:
Aggregate(NodeType type, Aggregate *parent, const QString &name)
@@ -516,6 +525,7 @@ class ProxyNode : public Aggregate
public:
ProxyNode(Aggregate *parent, const QString &name);
bool docMustBeGenerated() const override { return true; }
+ bool isRelatableType() const override { return true; }
};
class NamespaceNode : public Aggregate
@@ -525,8 +535,10 @@ public:
seen_(false), documented_(false), tree_(0), docNode_(0) { }
virtual ~NamespaceNode();
Tree* tree() const override { return (parent() ? parent()->tree() : tree_); }
- bool wasSeen() const override { return seen_; }
+ bool isFirstClassAggregate() const override { return true; }
+ bool isRelatableType() const override { return true; }
+ bool wasSeen() const override { return seen_; }
void markSeen() { seen_ = true; }
void markNotSeen() { seen_ = false; }
void setTree(Tree* t) { tree_ = t; }
@@ -585,9 +597,12 @@ struct UsingClause
class ClassNode : public Aggregate
{
public:
- ClassNode(Aggregate* parent, const QString& name) : Aggregate(Class, parent, name),
+ ClassNode(NodeType type, Aggregate* parent, const QString& name) : Aggregate(type, parent, name),
abstract_(false), wrapper_(false), qmlelement(0) { }
virtual ~ClassNode() { }
+ bool isFirstClassAggregate() const override { return true; }
+ bool isClassNode() const override { return true; }
+ bool isRelatableType() const override { return true; }
bool isWrapper() const override { return wrapper_; }
QString obsoleteLink() const override { return obsoleteLink_; }
void setObsoleteLink(const QString& t) override { obsoleteLink_ = t; }
@@ -634,6 +649,8 @@ class HeaderNode : public Aggregate
public:
HeaderNode(Aggregate* parent, const QString& name) : Aggregate(HeaderFile, parent, name) { }
virtual ~HeaderNode() { }
+ bool isFirstClassAggregate() const override { return true; }
+ bool isRelatableType() const override { return true; }
QString title() const override { return (title_.isEmpty() ? name() : title_); }
QString subtitle() const override { return subtitle_; }
QString fullTitle() const override { return (title_.isEmpty() ? name() : name() + " - " + title_); }
@@ -692,6 +709,7 @@ class QmlTypeNode : public Aggregate
public:
QmlTypeNode(Aggregate* parent, const QString& name, NodeType type = QmlType);
virtual ~QmlTypeNode();
+ bool isFirstClassAggregate() const override { return true; }
bool isQtQuickNode() const override {
return (logicalModuleName() == QLatin1String("QtQuick"));
}
@@ -746,6 +764,7 @@ class QmlBasicTypeNode : public Aggregate
public:
QmlBasicTypeNode(Aggregate* parent, const QString& name, NodeType type = QmlBasicType);
virtual ~QmlBasicTypeNode() { }
+ bool isFirstClassAggregate() const override { return true; }
};
class QmlPropertyGroupNode : public Aggregate
diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp
index bed2f0be1..1d08f8d45 100644
--- a/src/qdoc/qdocdatabase.cpp
+++ b/src/qdoc/qdocdatabase.cpp
@@ -799,7 +799,7 @@ QmlTypeNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name)
}
QStringList path(name);
- Node* n = forest_.findNodeByNameAndType(path, Node::QmlType);
+ Node* n = forest_.findNodeByNameAndType(path, &Node::isQmlType);
if (n && (n->isQmlType() || n->isJsType()))
return static_cast<QmlTypeNode*>(n);
return 0;
@@ -823,7 +823,7 @@ Aggregate* QDocDatabase::findQmlBasicType(const QString& qmid, const QString& na
}
QStringList path(name);
- Node* n = forest_.findNodeByNameAndType(path, Node::QmlBasicType);
+ Node* n = forest_.findNodeByNameAndType(path, &Node::isQmlBasicType);
if (n && n->isQmlBasicType())
return static_cast<Aggregate*>(n);
return 0;
@@ -1337,7 +1337,7 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
if (target.isEmpty())
node = relative;
else if (target.endsWith(".html"))
- node = findNodeByNameAndType(QStringList(target), Node::Page);
+ node = findNodeByNameAndType(QStringList(target), &Node::isPageNode);
else {
QStringList path = target.split("::");
int flags = SearchBaseClasses | SearchEnumValues;
@@ -1402,7 +1402,7 @@ void QDocDatabase::generateIndex(const QString &fileName, const QString &url, co
This function only searches in the current primary tree.
*/
-Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path, Node::NodeType type)
+Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path, bool (Node::*isMatch) () const)
{
if (path.isEmpty())
return 0;
@@ -1414,7 +1414,7 @@ Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path, Node::NodeType ty
p = t.split("::") + path;
else
p = path;
- n = primaryTree()->findNodeByNameAndType(p, type);
+ n = primaryTree()->findNodeByNameAndType(p, isMatch);
if (n) {
path = p;
break;
@@ -1540,7 +1540,7 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
node = relative; // search for a target on the current page.
else if (domain) {
if (first.endsWith(".html"))
- node = domain->findNodeByNameAndType(QStringList(first), Node::Page);
+ node = domain->findNodeByNameAndType(QStringList(first), &Node::isPageNode);
else if (first.endsWith(QChar(')'))) {
QString signature;
QString function = first;
@@ -1569,7 +1569,7 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
}
else {
if (first.endsWith(".html"))
- node = findNodeByNameAndType(QStringList(first), Node::Page);
+ node = findNodeByNameAndType(QStringList(first), &Node::isPageNode);
else if (first.endsWith(QChar(')')))
node = findFunctionNode(first, relative, genus);
if (!node)
diff --git a/src/qdoc/qdocdatabase.h b/src/qdoc/qdocdatabase.h
index 8d9899042..2b4d43ac0 100644
--- a/src/qdoc/qdocdatabase.h
+++ b/src/qdoc/qdocdatabase.h
@@ -95,9 +95,9 @@ class QDocForest
return 0;
}
- Node* findNodeByNameAndType(const QStringList& path, Node::NodeType type) {
+ Node* findNodeByNameAndType(const QStringList& path, bool (Node::*isMatch) () const) {
foreach (Tree* t, searchOrder()) {
- Node* n = t->findNodeByNameAndType(path, type);
+ Node* n = t->findNodeByNameAndType(path, isMatch);
if (n)
return n;
}
@@ -303,8 +303,8 @@ class QDocDatabase
/*******************************************************************
The functions declared below are called for the current tree only.
********************************************************************/
- Aggregate *findRelatesNode(const QStringList &path) { return primaryTree()->findRelatesNode(path); }
- Node* findNodeInOpenNamespace(QStringList& path, Node::NodeType type);
+ Aggregate* findRelatesNode(const QStringList& path) { return primaryTree()->findRelatesNode(path); }
+ Node* findNodeInOpenNamespace(QStringList& path, bool (Node::*) () const);
/*******************************************************************/
/*****************************************************************************
@@ -324,8 +324,8 @@ class QDocDatabase
const PageNode* findPageNodeByTitle(const QString& title) {
return forest_.findPageNodeByTitle(title);
}
- Node* findNodeByNameAndType(const QStringList& path, Node::NodeType type) {
- return forest_.findNodeByNameAndType(path, type);
+ Node* findNodeByNameAndType(const QStringList& path, bool (Node::*isMatch) () const) {
+ return forest_.findNodeByNameAndType(path, isMatch);
}
const CollectionNode* getCollectionNode(const QString& name, Node::NodeType type) {
return forest_.getCollectionNode(name, type);
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index 2b957a439..47e89d651 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -208,8 +208,16 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
ns->setDocumented();
}
- } else if (elementName == QLatin1String("class")) {
- node = new ClassNode(parent, name);
+ } else if (elementName == QLatin1String("class") || elementName == QLatin1String("struct") ||
+ elementName == QLatin1String("union")) {
+ Node::NodeType type = Node::Class;
+ if (elementName == QLatin1String("class"))
+ type = Node::Class;
+ else if (elementName == QLatin1String("struct"))
+ type = Node::Struct;
+ else if (elementName == QLatin1String("union"))
+ type = Node::Union;
+ node = new ClassNode(type, parent, name);
if (attributes.hasAttribute(QLatin1String("bases"))) {
QString bases = attributes.value(QLatin1String("bases")).toString();
if (!bases.isEmpty())
@@ -799,6 +807,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node)
case Node::Class:
nodeName = "class";
break;
+ case Node::Struct:
+ nodeName = "struct";
+ break;
+ case Node::Union:
+ nodeName = "union";
+ break;
case Node::HeaderFile:
nodeName = "header";
break;
@@ -953,6 +967,8 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node)
QString brief = node->doc().trimmedBriefText(node->name()).toString();
switch (node->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
{
// Classes contain information about their base classes.
const ClassNode* classNode = static_cast<const ClassNode*>(node);
diff --git a/src/qdoc/qdoctagfiles.cpp b/src/qdoc/qdoctagfiles.cpp
index 4cc1735d3..136ca87d7 100644
--- a/src/qdoc/qdoctagfiles.cpp
+++ b/src/qdoc/qdoctagfiles.cpp
@@ -105,6 +105,8 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter &writer, const Aggr
kind = "namespace";
break;
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
case Node::QmlType:
case Node::JsType:
kind = "class";
@@ -128,7 +130,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter &writer, const Aggr
writer.writeStartElement("compound");
writer.writeAttribute("kind", kind);
- if (node->isClass()) {
+ if (node->isClassNode()) {
writer.writeTextElement("name", node->fullDocumentName());
writer.writeTextElement("filename", gen_->fullDocumentLocation(node, false));
@@ -194,6 +196,8 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter &writer, const Aggreg
nodeName = "namespace";
break;
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
nodeName = "class";
break;
case Node::Variable:
@@ -227,6 +231,8 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter &writer, const Aggreg
switch (node->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
writer.writeCharacters(node->fullDocumentName());
writer.writeEndElement();
break;
diff --git a/src/qdoc/sections.cpp b/src/qdoc/sections.cpp
index 69683d358..28f9878b8 100644
--- a/src/qdoc/sections.cpp
+++ b/src/qdoc/sections.cpp
@@ -155,7 +155,7 @@ QString Section::sortName(const Node *node, const QString* name)
if (fn->isJsMethod() || fn->isJsSignal() || fn->isJsSignalHandler())
return QLatin1Char('E') + nodeName;
}
- if (node->isClass())
+ if (node->isClassNode())
return QLatin1Char('A') + nodeName;
if (node->isProperty() || node->isVariable())
@@ -189,7 +189,7 @@ void Section::insert(Node *node)
FunctionNode *func = static_cast<FunctionNode *>(node);
irrelevant = (inherited && (func->isSomeCtor() || func->isDtor()));
}
- else if (node->isClass() || node->isEnumType() || node->isTypedef() || node->isVariable()) {
+ else if (node->isClassNode() || node->isEnumType() || node->isTypedef() || node->isVariable()) {
irrelevant = (inherited && style_ != AllMembers);
if (!irrelevant && style_ == Details && node->isTypedef()) {
const TypedefNode* tdn = static_cast<const TypedefNode*>(node);
@@ -209,7 +209,7 @@ void Section::insert(Node *node)
if (!memberMap_.contains(key))
memberMap_.insertMulti(key, node);
}
- if (inherited && (node->parent()->isClass() || node->parent()->isNamespace())) {
+ if (inherited && (node->parent()->isClassNode() || node->parent()->isNamespace())) {
if (inheritedMembers_.isEmpty() || inheritedMembers_.last().first != node->parent()) {
QPair<Aggregate *, int> p(node->parent(), 0);
inheritedMembers_.append(p);
@@ -324,6 +324,8 @@ Sections::Sections(Aggregate *aggregate) : aggregate_(aggregate)
initAggregate(allMembers_, aggregate_);
switch (aggregate_->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
initAggregate(stdCppClassSummarySections_, aggregate_);
initAggregate(stdCppClassDetailsSections_, aggregate_);
buildStdCppClassRefPageSections();
@@ -369,6 +371,8 @@ Sections::Sections(const NodeMultiMap& nsmap) : aggregate_(0)
sections[SinceNamespaces].appendMember(node);
break;
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
sections[SinceClasses].appendMember(node);
break;
case Node::Enum:
@@ -398,7 +402,7 @@ Sections::Sections(const NodeMultiMap& nsmap) : aggregate_(0)
else {
Node* p = fn->parent();
if (p) {
- if (p->isClass())
+ if (p->isClassNode())
sections[SinceMemberFunctions].appendMember(node);
else if (p->isNamespace()) {
if (p->name().isEmpty())
@@ -444,6 +448,8 @@ Sections::~Sections()
if (aggregate_) {
switch (aggregate_->nodeType()) {
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
clear(stdCppClassSummarySections());
clear(stdCppClassDetailsSections());
allMembersSection().clear();
@@ -617,6 +623,8 @@ void Sections::stdRefPageSwitch(SectionVector &v, Node *n)
v[StdNamespaces].insert(n);
return;
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
v[StdClasses].insert(n);
return;
case Node::Enum:
@@ -1053,7 +1061,7 @@ void Sections::buildStdQmlTypeRefPageSections()
bool Sections::hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVector *details_spv) const
{
const SectionVector *sv = 0;
- if (aggregate_->isClass())
+ if (aggregate_->isClassNode())
sv = &stdCppClassSummarySections();
else if (aggregate_->isQmlType() || aggregate_->isQmlBasicType())
sv = &stdQmlTypeSummarySections();
@@ -1065,7 +1073,7 @@ bool Sections::hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVecto
summary_spv->append(&(*s));
++s;
}
- if (aggregate_->isClass())
+ if (aggregate_->isClassNode())
sv = &stdCppClassDetailsSections();
else if (aggregate_->isQmlType() || aggregate_->isQmlBasicType())
sv = &stdQmlTypeDetailsSections();
diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp
index 0561b36b4..d8ec47ced 100644
--- a/src/qdoc/tree.cpp
+++ b/src/qdoc/tree.cpp
@@ -134,20 +134,6 @@ 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
@@ -160,7 +146,7 @@ Aggregate *Tree::findAggregate(const QString &name)
{
QStringList path;
path << name;
- return static_cast<Aggregate*>(findNodeRecursive(path, 0, const_cast<NamespaceNode*>(root()), aggregateTypes()));
+ return static_cast<Aggregate*>(findNodeRecursive(path, 0, const_cast<NamespaceNode*>(root()), &Node::isFirstClassAggregate));
}
/*!
@@ -173,7 +159,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, const Node* start) const
{
if (!start)
start = const_cast<NamespaceNode*>(root());
- return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class));
+ return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, &Node::isClassNode));
}
/*!
@@ -184,7 +170,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, const Node* start) const
NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
{
Node* start = const_cast<NamespaceNode*>(root());
- return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace));
+ return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, &Node::isNamespace));
}
/*!
@@ -208,20 +194,7 @@ QmlTypeNode* Tree::findQmlTypeNode(const QStringList& path)
if (qcn)
return qcn;
}
- return static_cast<QmlTypeNode*>(findNodeRecursive(path, 0, root(), Node::QmlType));
-}
-
-static QList<int> relatesTypes_;
-static const QList<int>& relatesTypes()
-{
- if (relatesTypes_.isEmpty()) {
- relatesTypes_.reserve(4);
- relatesTypes_.append(Node::Class);
- relatesTypes_.append(Node::Namespace);
- relatesTypes_.append(Node::HeaderFile);
- relatesTypes_.append(Node::Proxy);
- }
- return relatesTypes_;
+ return static_cast<QmlTypeNode*>(findNodeRecursive(path, 0, root(), &Node::isQmlType));
}
/*!
@@ -238,7 +211,7 @@ static const QList<int>& relatesTypes()
*/
Aggregate *Tree::findRelatesNode(const QStringList &path)
{
- Node* n = findNodeRecursive(path, 0, root(), relatesTypes());
+ Node* n = findNodeRecursive(path, 0, root(), &Node::isRelatableType);
return ((n && n->isAggregate()) ? static_cast<Aggregate*>(n) : 0);
}
@@ -267,7 +240,7 @@ void Tree::resolveInheritance(Aggregate* n)
for (int pass = 0; pass < 2; pass++) {
NodeList::ConstIterator c = n->constBegin();
while (c != n->constEnd()) {
- if ((*c)->isClass()) {
+ if ((*c)->isClassNode()) {
resolveInheritanceHelper(pass, static_cast<ClassNode*>(*c));
resolveInheritance(static_cast<ClassNode*>(*c));
} else if ((*c)->isNamespace()) {
@@ -416,8 +389,8 @@ void Tree::resolveCppToQmlLinks()
void Tree::resolveUsingClauses()
{
const NodeList &children = root_.childNodes();
- foreach (Node *child, children) {
- if (child->isClass()) {
+ foreach (Node* child, children) {
+ if (child->isClassNode()) {
ClassNode* cn = static_cast<ClassNode*>(child);
QList<UsingClause>& usingClauses = cn->usingClauses();
QList<UsingClause>::iterator uc = usingClauses.begin();
@@ -442,7 +415,7 @@ void Tree::fixInheritance(NamespaceNode* rootNode)
NodeList::ConstIterator c = rootNode->constBegin();
while (c != rootNode->constEnd()) {
- if ((*c)->isClass())
+ if ((*c)->isClassNode())
static_cast<ClassNode*>(*c)->fixBaseClasses();
else if ((*c)->isNamespace())
fixInheritance(static_cast<NamespaceNode*>(*c));
@@ -471,9 +444,9 @@ ClassList Tree::allBaseClasses(const ClassNode *classNode) const
search at the tree root. \a subtype is not used unless
\a type is \c{Page}.
*/
-Node* Tree::findNodeByNameAndType(const QStringList& path, Node::NodeType type) const
+Node* Tree::findNodeByNameAndType(const QStringList& path, bool (Node::*isMatch) () const) const
{
- return findNodeRecursive(path, 0, root(), type);
+ return findNodeRecursive(path, 0, root(), isMatch);
}
/*!
@@ -495,17 +468,17 @@ Node* Tree::findNodeByNameAndType(const QStringList& path, Node::NodeType type)
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
- Node::NodeType type) const
+ bool (Node::*isMatch) () const) const
{
- if (!start || path.isEmpty())
- return 0; // no place to start, or nothing to search for.
+ if (start == nullptr || path.isEmpty())
+ return nullptr;
Node* node = const_cast<Node*>(start);
- if (!start->isAggregate()) {
- if (pathIndex >= path.size())
- return node; // found a match.
- return 0; // premature leaf
- }
-
+ if (!node->isAggregate())
+ return ((pathIndex >= path.size()) ? node : nullptr);
+#if 0
+ if (pathIndex >= path.size())
+ return nullptr;
+#endif
Aggregate* current = static_cast<Aggregate*>(node);
const NodeList& children = current->childNodes();
const QString& name = path.at(pathIndex);
@@ -513,64 +486,77 @@ Node* Tree::findNodeRecursive(const QStringList& path,
if (!n)
continue;
if (n->isQmlPropertyGroup()) {
- if (type == Node::QmlProperty) {
- n = findNodeRecursive(path, pathIndex, n, type);
- if (n)
- return n;
- }
+ n = findNodeRecursive(path, pathIndex, n, isMatch);
+ if (n)
+ return n;
}
else if (n->name() == name) {
if (pathIndex+1 >= path.size()) {
- if ((n->nodeType() == type) || (type == Node::NoType))
+ if ((n->*(isMatch))())
return n;
continue;
}
else { // Search the children of n for the next name in the path.
- n = findNodeRecursive(path, pathIndex+1, n, type);
+ n = findNodeRecursive(path, pathIndex+1, n, isMatch);
if (n)
return n;
}
}
}
- return 0;
+ return nullptr;
}
-
+#if 0
/*!
Recursive search for a node identified by \a path. Each
path element is a name. \a pathIndex specifies the index
of the name in \a path to try to match. \a start is the
node whose children shoulod be searched for one that has
- that name. Each time a name match is found, increment the
+ that name. Each time a match is found, increment the
\a pathIndex and call this function recursively.
If the end of the path is reached (i.e. if a matching
- node is found for each name in the \a path), test the
- matching node's type and subtype values against the ones
- listed in \a types. If a match is found there, return the
- pointer to the final node. Otherwise return 0.
+ node is found for each name in the \a path), the \a type
+ must match the type of the last matching node, and if the
+ type is \e{Page}, the \a subtype must match as well.
+
+ If the algorithm is successful, the pointer to the final
+ node is returned. Otherwise 0 is returned.
*/
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
- Node* start,
- const QList<int> &types) const
+ const Node* start,
+ Node::NodeType type) const
{
if (!start || path.isEmpty())
- return 0;
- if (!start->isAggregate())
- return ((pathIndex >= path.size()) ? start : 0);
- if (pathIndex >= path.size())
- return 0;
+ return 0; // no place to start, or nothing to search for.
+ Node* node = const_cast<Node*>(start);
+ if (!start->isAggregate()) {
+ if (pathIndex >= path.size())
+ return node; // found a match.
+ return 0; // premature leaf
+ }
- Aggregate* current = static_cast<Aggregate*>(start);
- const NodeList &children = current->childNodes();
+ Aggregate* current = static_cast<Aggregate*>(node);
+ const NodeList& children = current->childNodes();
+ const QString& name = path.at(pathIndex);
foreach (Node *n, children) {
- if (n && n->name() == path.at(pathIndex)) {
+ if (!n)
+ continue;
+ if (n->isQmlPropertyGroup()) {
+ if (type == Node::QmlProperty) {
+ n = findNodeRecursive(path, pathIndex, n, type);
+ if (n)
+ return n;
+ }
+ }
+ else if (n->name() == name) {
if (pathIndex+1 >= path.size()) {
- if (n->match(types))
+ if ((n->nodeType() == type) || (type == Node::NoType))
return n;
+ continue;
}
- else if (n->isAggregate()) {
- n = findNodeRecursive(path, pathIndex+1, n, types);
+ else { // Search the children of n for the next name in the path.
+ n = findNodeRecursive(path, pathIndex+1, n, type);
if (n)
return n;
}
@@ -578,7 +564,7 @@ Node* Tree::findNodeRecursive(const QStringList& path,
}
return 0;
}
-
+#endif
/*!
Searches the tree for a node that matches the \a path plus
the \a target. The search begins at \a start and moves up
@@ -732,7 +718,7 @@ const Node* Tree::matchPathAndTarget(const QStringList& path,
}
}
if (((genus == Node::CPP) || (genus == Node::DontCare)) &&
- node->isClass() && (flags & SearchBaseClasses)) {
+ node->isClassNode() && (flags & SearchBaseClasses)) {
ClassList bases = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const ClassNode *base, bases) {
const Node *t = matchPathAndTarget(path, idx, target, base, flags, genus, ref);
@@ -802,7 +788,7 @@ const Node* Tree::findNode(const QStringList& path,
next = static_cast<const Aggregate*>(node)->findEnumNodeForValue(path.at(i));
}
if (!next && ((genus == Node::CPP) || (genus == Node::DontCare)) &&
- node->isClass() && (flags & SearchBaseClasses)) {
+ node->isClassNode() && (flags & SearchBaseClasses)) {
ClassList bases = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const ClassNode *base, bases) {
next = base->findChildNode(path.at(i), genus, tmpFlags);
@@ -1336,7 +1322,7 @@ const FunctionNode *Tree::findFunctionNode(const QStringList &path,
QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
- Node *n = findNodeByNameAndType(p, Node::QmlType);
+ Node* n = findNodeByNameAndType(p, &Node::isQmlType);
if (n && (n->isQmlType() || n->isJsType()))
qcn = static_cast<QmlTypeNode*>(n);
}
@@ -1366,7 +1352,7 @@ const FunctionNode *Tree::findFunctionNode(const QStringList &path,
else
next = aggregate->findChildNode(path.at(i), genus);
- if (!next && aggregate->isClass()) {
+ if (!next && aggregate->isClassNode()) {
ClassList bases = allBaseClasses(static_cast<const ClassNode*>(aggregate));
foreach (ClassNode *base, bases) {
if (i == path.size() - 1)
diff --git a/src/qdoc/tree.h b/src/qdoc/tree.h
index 86637bf3e..abef4cca1 100644
--- a/src/qdoc/tree.h
+++ b/src/qdoc/tree.h
@@ -123,12 +123,13 @@ class Tree
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
- Node::NodeType type) const;
+ bool (Node::*) () const) const;
+#if 0
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
- Node* start,
- const QList<int> &types) const;
-
+ const Node* start,
+ Node::NodeType type) const;
+#endif
const Node* findNodeForTarget(const QStringList& path,
const QString& target,
const Node* node,
@@ -150,8 +151,8 @@ class Tree
QmlTypeNode* findQmlTypeNode(const QStringList& path);
- Node* findNodeByNameAndType(const QStringList& path, Node::NodeType type) const;
- Aggregate *findRelatesNode(const QStringList &path);
+ Node* findNodeByNameAndType(const QStringList& path, bool (Node::*isMatch) () const) const;
+ Aggregate* findRelatesNode(const QStringList& path);
QString getRef(const QString& target, const Node* node) const;
void insertTarget(const QString& name,
const QString& title,
diff --git a/src/qdoc/webxmlgenerator.cpp b/src/qdoc/webxmlgenerator.cpp
index 7202d3651..f6a9ae916 100644
--- a/src/qdoc/webxmlgenerator.cpp
+++ b/src/qdoc/webxmlgenerator.cpp
@@ -198,7 +198,7 @@ void WebXMLGenerator::generateDocumentation(Node *node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent()) {
- if (node->isNamespace() || node->isClass() || node->isHeader())
+ if (node->isNamespace() || node->isClassNode() || node->isHeader())
generateCppReferencePage(static_cast<Aggregate*>(node), marker);
else if (node->isCollectionNode()) {
if (node->wasSeen()) {
@@ -702,6 +702,8 @@ QString WebXMLGenerator::targetType(const Node *node)
case Node::Namespace:
return "namespace";
case Node::Class:
+ case Node::Struct:
+ case Node::Union:
return "class";
case Node::Page:
return "page";