diff options
-rw-r--r-- | src/qdoc/clangcodeparser.cpp | 41 | ||||
-rw-r--r-- | src/qdoc/codemarker.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/codeparser.cpp | 26 | ||||
-rw-r--r-- | src/qdoc/codeparser.h | 2 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 47 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.h | 4 | ||||
-rw-r--r-- | src/qdoc/generator.cpp | 12 | ||||
-rw-r--r-- | src/qdoc/helpprojectwriter.cpp | 10 | ||||
-rw-r--r-- | src/qdoc/htmlgenerator.cpp | 40 | ||||
-rw-r--r-- | src/qdoc/node.cpp | 81 | ||||
-rw-r--r-- | src/qdoc/node.h | 31 | ||||
-rw-r--r-- | src/qdoc/qdocdatabase.cpp | 14 | ||||
-rw-r--r-- | src/qdoc/qdocdatabase.h | 12 | ||||
-rw-r--r-- | src/qdoc/qdocindexfiles.cpp | 20 | ||||
-rw-r--r-- | src/qdoc/qdoctagfiles.cpp | 8 | ||||
-rw-r--r-- | src/qdoc/sections.cpp | 20 | ||||
-rw-r--r-- | src/qdoc/tree.cpp | 144 | ||||
-rw-r--r-- | src/qdoc/tree.h | 13 | ||||
-rw-r--r-- | src/qdoc/webxmlgenerator.cpp | 4 |
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 = §ions.stdSummarySections(); detailsSections = §ions.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 = §ions.stdCppClassSummarySections(); detailsSections = §ions.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 ¶meters); - 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 ¶meters); + 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"; |