summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2019-01-14 14:42:23 +0100
committerMartin Smith <martin.smith@qt.io>2019-02-08 08:46:37 +0000
commit438e477d35c4e62251664878bdbf9f8efc85cd0d (patch)
treebebb6979e234c6f22b7ba59d4e55e5d6f5c63bee
parent1e8fc9db36a002a5ff5bdf9f9271de13478ef4a2 (diff)
downloadqttools-438e477d35c4e62251664878bdbf9f8efc85cd0d.tar.gz
qdoc: Correct ref pages for inner classes
This update corrects the documentation pages for classes, structs, and unions that are declared inside a class or a struct. In Qt, a struct is often declared inside a class. For such internal declarations, the requirements for making the inner entity available were incorrectly shown. All that is really necessary is to include the parent class. So the requirements for including the inner entity are now replaced with, for example, "Struct State is declared in class QAccessible," where QAccessible becomes a link to the reference page for that class. It was easier to implement this change by teaching qdoc to recognize structs and unions in addition to classes, so that is also included in this change. Change-Id: I1a0d46ef19a130506c7bcbf77b46e298f6ab2f71 Task-number: QTBUG-66872 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.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";