From e967772fe884dd8a488a359c122c9cbae9d94c55 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 21 Apr 2020 23:57:46 +0200 Subject: qdoc: properly implement \typealias command \typealias was already a command recognized by QDoc, but it was simply treated as a synonym for \typedef and was not documented. Implement proper support for the command: - Add [alias] designation both in type summary and details. - Auto-generate information about the aliased type, including a link if aliasing a public, documented type. - Auto-convert aliases documented with \typedef to type aliases. - Add basic support for aliases also to DocBook and WebXML generators. - Document \typealias. Fixes: QTBUG-82712 Change-Id: Iafa8c7def0a7488d7521fbc2862290a9bb3167ff Reviewed-by: Qt CI Bot Reviewed-by: Paul Wicking --- src/qdoc/clangcodeparser.cpp | 16 ++---- src/qdoc/cppcodemarker.cpp | 7 +++ src/qdoc/cppcodeparser.cpp | 4 +- src/qdoc/doc/qdoc-manual-cmdindex.qdoc | 1 + src/qdoc/doc/qdoc-manual-topiccmds.qdoc | 36 ++++++++++++ src/qdoc/docbookgenerator.cpp | 64 ++++++++++++++++------ src/qdoc/docbookgenerator.h | 3 +- src/qdoc/generator.cpp | 41 +++++++++++--- src/qdoc/generator.h | 5 +- src/qdoc/helpprojectwriter.cpp | 3 +- src/qdoc/node.cpp | 4 +- src/qdoc/node.h | 20 ++++--- src/qdoc/qdocindexfiles.cpp | 13 +++++ src/qdoc/qdoctagfiles.cpp | 2 + src/qdoc/sections.cpp | 5 ++ src/qdoc/sections.h | 1 + src/qdoc/tree.cpp | 15 ++++- src/qdoc/tree.h | 2 +- src/qdoc/xmlgenerator.cpp | 6 ++ .../crossmodule/testtype-members.html | 3 + .../expected_output/docbook/testqdoc-test.xml | 13 +++++ .../docbook/testqdoc-testderived.xml | 25 +++++++++ .../expected_output/html/testqdoc-test.webxml | 5 ++ .../html/testqdoc-testderived.webxml | 10 ++++ .../expected_output/ignoresince/testqdoc-test.html | 13 +++++ .../expected_output/scopedenum/testqdoc-test.html | 5 ++ .../expected_output/template/testqdoc-test.html | 13 +++++ .../qdoc/generatedoutput/expected_output/test.qhp | 3 + .../generatedoutput/expected_output/testcpp.index | 3 + .../expected_output/testqdoc-test-members.html | 1 + .../expected_output/testqdoc-test.html | 13 +++++ .../testqdoc-testderived-members.html | 6 +- .../expected_output/testqdoc-testderived.html | 22 +++++++- .../generatedoutput/testdata/testcpp/testcpp.cpp | 15 +++++ .../generatedoutput/testdata/testcpp/testcpp.h | 5 ++ .../qdoc/generatedoutput/tst_generatedoutput.cpp | 2 + 36 files changed, 351 insertions(+), 54 deletions(-) diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index b5c6a8ac6..0a0b7e7ac 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -632,18 +632,14 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l QString templateString; switch (kind) { case CXCursor_TypeAliasDecl: { - QString spelling = getSpelling(clang_getCursorExtent(cursor)); - QStringList typeAlias = spelling.split(QChar('=')); + QString aliasDecl = getSpelling(clang_getCursorExtent(cursor)).simplified(); + QStringList typeAlias = aliasDecl.split(QLatin1Char('=')); if (typeAlias.size() == 2) { - typeAlias[0] = typeAlias[0].trimmed(); + typeAlias[0] = typeAlias[0].trimmed().split(QLatin1Char(' ')).last(); typeAlias[1] = typeAlias[1].trimmed(); - int lastBlank = typeAlias[0].lastIndexOf(QChar(' ')); - if (lastBlank > 0) { - typeAlias[0] = typeAlias[0].right(typeAlias[0].size() - (lastBlank + 1)); - TypeAliasNode *ta = new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]); - ta->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); - ta->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); - } + TypeAliasNode *ta = new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]); + ta->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); + ta->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); } return CXChildVisit_Continue; } diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp index 38dd8e79f..79313e2dd 100644 --- a/src/qdoc/cppcodemarker.cpp +++ b/src/qdoc/cppcodemarker.cpp @@ -252,6 +252,13 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, const Node * /* relati synopsis += QLatin1Char('}'); } break; + case Node::TypeAlias: + if (style == Section::Summary) + synopsis = "(alias) "; + else if (style == Section::Details) + extra = QStringLiteral("[alias] "); + synopsis += name; + break; case Node::Typedef: typedeff = static_cast(node); if (typedeff->associatedEnum()) { diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 5248c990d..cccc1d86d 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -102,7 +102,7 @@ void CppCodeParser::initializeParser() 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_TYPEALIAS, Node::TypeAlias); nodeTypeMap_.insert(COMMAND_TYPEDEF, Node::Typedef); nodeTypeMap_.insert(COMMAND_PROPERTY, Node::Property); nodeTypeMap_.insert(COMMAND_VARIABLE, Node::Variable); @@ -112,7 +112,7 @@ void CppCodeParser::initializeParser() 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_TYPEALIAS, &Node::isTypeAlias); nodeTypeTestFuncMap_.insert(COMMAND_TYPEDEF, &Node::isTypedef); nodeTypeTestFuncMap_.insert(COMMAND_PROPERTY, &Node::isProperty); nodeTypeTestFuncMap_.insert(COMMAND_VARIABLE, &Node::isVariable); diff --git a/src/qdoc/doc/qdoc-manual-cmdindex.qdoc b/src/qdoc/doc/qdoc-manual-cmdindex.qdoc index 430fdf0f8..5cd55c667 100644 --- a/src/qdoc/doc/qdoc-manual-cmdindex.qdoc +++ b/src/qdoc/doc/qdoc-manual-cmdindex.qdoc @@ -144,6 +144,7 @@ \li \l {threadsafe-command} {\\threadsafe} \li \l {title-command} {\\title} \li \l {tt-command} {\\tt} + \li \l {typealias-command} {\\typealias} \li \l {typedef-command} {\\typedef} \li \l {uicontrol-command} {\\uicontrol} \li \l {underline-command} {\\underline} diff --git a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc index 8e142f5af..a537c7499 100644 --- a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc @@ -1410,6 +1410,40 @@ {\\instantiates} to specify that a Transform is instantiated by the C++ class QGraphicsTransform. A \\qmltype comment should + \target typealias-command + \section1 \\typealias + + The \\typealias command is similar to \l {typedef-command}{\\typedef}, + but specific to documenting a C++ type alias: + + \code + class Foo + { + public: + using ptr = void*; + // ... + } + \endcode + + This can be documented as + + \badcode * + /\1! + \typealias Foo::ptr + \1/ + \endcode + + QDoc will automatically generate a sentence in the documentation describing + the alias: + + \quotation + This is a type alias for \c {void*}. + \endquotation + + The \\typealias command was introduced in QDoc 5.15. + + See also \l {typedef-command}{\\typedef}. + \target typedef-command \section1 \\typedef @@ -1498,6 +1532,8 @@ Qt-style synonym for QList::iterator. \endquotation + See also \l {typealias-command}{\\typealias}. + \target variable-command \section1 \\variable diff --git a/src/qdoc/docbookgenerator.cpp b/src/qdoc/docbookgenerator.cpp index f6476c9ec..a7e5df290 100644 --- a/src/qdoc/docbookgenerator.cpp +++ b/src/qdoc/docbookgenerator.cpp @@ -2105,10 +2105,11 @@ void DocBookGenerator::generateBody(const Node *node) writer->writeTextElement(dbNamespace, "para", t); } } else if (!node->isSharingComment()) { - if (fn) { - if (!fn->overridesThis().isEmpty()) - generateReimplementsClause(fn); - } + // Reimplements clause and type alias info precede body text + if (fn && !fn->overridesThis().isEmpty()) + generateReimplementsClause(fn); + else if (node->isTypeAlias()) + generateAddendum(node, TypeAlias, nullptr, false); if (!generateText(node->doc().body(), node)) { if (node->isMarkedReimp()) @@ -2726,6 +2727,8 @@ void DocBookGenerator::generateDocBookSynopsis(const Node *node) else if (functionNode->isDefault()) signature += " = default"; generateSynopsisInfo("signature", signature); + } else if (node->isTypedef()) { + writer->writeTextElement(dbNamespace, "type", node->plainName()); } else { node->doc().location().warning(tr("Unexpected node type in generateDocBookSynopsis: %1") .arg(node->nodeTypeString())); @@ -3157,10 +3160,10 @@ void DocBookGenerator::generateSynopsis(const Node *node, const Node *relative, // First generate the extra part if needed (condition from HtmlGenerator::generateSynopsis). if (generateExtra) { - if (node->nodeType() == Node::Function) { - const auto func = static_cast(node); - if (style != Section::Summary && style != Section::Accessors) { - QStringList bracketed; + if (style != Section::Summary && style != Section::Accessors) { + QStringList bracketed; + if (node->isFunction()) { + const auto func = static_cast(node); if (func->isStatic()) { bracketed += "static"; } else if (!func->isNonvirtual()) { @@ -3182,11 +3185,12 @@ void DocBookGenerator::generateSynopsis(const Node *node, const Node *relative, bracketed += "signal"; else if (func->isSlot()) bracketed += "slot"; - - if (!bracketed.isEmpty()) - writer->writeCharacters(QLatin1Char('[') + bracketed.join(' ') - + QStringLiteral("] ")); + } else if (node->isTypeAlias()) { + bracketed += "alias"; } + if (!bracketed.isEmpty()) + writer->writeCharacters(QLatin1Char('[') + bracketed.join(' ') + + QStringLiteral("] ")); } if (style == Section::Summary) { @@ -3197,6 +3201,8 @@ void DocBookGenerator::generateSynopsis(const Node *node, const Node *relative, extra = "(deprecated) "; else if (node->isObsolete()) extra = "(obsolete) "; + else if (node->isTypeAlias()) + extra = "(alias) "; if (!extra.isEmpty()) writer->writeCharacters(extra); @@ -3407,12 +3413,15 @@ void DocBookGenerator::generateOverloadedSignal(const Node *node) Generates an addendum note of type \a type for \a node. \a marker is unused in this generator. */ -void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker) +void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote) { Q_UNUSED(marker); Q_ASSERT(node && !node->name().isEmpty()); - writer->writeStartElement(dbNamespace, "note"); - newLine(); + if (generateNote) { + writer->writeStartElement(dbNamespace, "note"); + newLine(); + } switch (type) { case Invokable: writer->writeStartElement(dbNamespace, "para"); @@ -3475,12 +3484,33 @@ void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMar } break; } + case TypeAlias: + { + if (!node->isTypeAlias()) + return; + writer->writeStartElement(dbNamespace, "para"); + const auto *ta = static_cast(node); + writer->writeCharacters("This is a type alias for "); + if (ta->aliasedNode() && ta->aliasedNode()->isInAPI()) + generateSimpleLink(linkForNode(ta->aliasedNode(), nullptr), + ta->aliasedNode()->plainFullName(ta->parent())); + else + writer->writeTextElement(dbNamespace, "code", ta->aliasedType()); + + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + break; + } + default: break; } - writer->writeEndElement(); // note - newLine(); + if (generateNote) { + writer->writeEndElement(); // note + newLine(); + } } void DocBookGenerator::generateDetailedMember(const Node *node, const PageNode *relative) diff --git a/src/qdoc/docbookgenerator.h b/src/qdoc/docbookgenerator.h index 5eea595f7..753f5be33 100644 --- a/src/qdoc/docbookgenerator.h +++ b/src/qdoc/docbookgenerator.h @@ -81,7 +81,8 @@ protected: bool generateStatus(const Node *node); bool generateThreadSafeness(const Node *node); bool generateSince(const Node *node); - void generateAddendum(const Node *node, Generator::Addendum type, CodeMarker *marker = nullptr) override; + void generateAddendum(const Node *node, Generator::Addendum type, CodeMarker *marker = nullptr, + bool generateNote = true) override; using Generator::generateBody; void generateBody(const Node *node); diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index bdeeec2be..b3aacb623 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -644,6 +644,9 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) case Node::Enum: anchorRef = QLatin1Char('#') + node->name() + "-enum"; break; + case Node::TypeAlias: + anchorRef = QLatin1Char('#') + node->name() + "-alias"; + break; case Node::Typedef: { const TypedefNode *tdef = static_cast(node); if (tdef->associatedEnum()) { @@ -818,10 +821,11 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) tr("No documentation for '%1'").arg(node->plainSignature())); } } else if (!node->isSharingComment()) { - if (fn) { - if (!fn->overridesThis().isEmpty()) - generateReimplementsClause(fn, marker); - } + // Reimplements clause and type alias info precede body text + if (fn && !fn->overridesThis().isEmpty()) + generateReimplementsClause(fn, marker); + else if (node->isTypeAlias()) + generateAddendum(node, TypeAlias, marker, false); if (!generateText(node->doc().body(), node, marker)) { if (node->isMarkedReimp()) @@ -1357,12 +1361,17 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) Generates an addendum note of type \a type for \a node, using \a marker as the code marker. */ -void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker) +void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote) { Q_ASSERT(node && !node->name().isEmpty()); Text text; - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + text << Atom::ParaLeft; + + if (generateNote) { + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + } switch (type) { case Invokable: @@ -1419,6 +1428,22 @@ void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *ma } break; } + case TypeAlias: + { + if (!node->isTypeAlias()) + return; + const auto *ta = static_cast(node); + text << "This is a type alias for "; + if (ta->aliasedNode() && ta->aliasedNode()->isInAPI()) { + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(ta->aliasedNode())) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, ta->aliasedNode()->plainFullName(ta->parent())) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << "."; + } else { + text << Atom(Atom::String, ta->aliasedType()) << "."; + } + break; + } default: return; } @@ -2195,6 +2220,8 @@ QString Generator::typeString(const Node *node) return "enum"; case Node::Typedef: return "typedef"; + case Node::TypeAlias: + return "alias"; case Node::Function: { const auto fn = static_cast(node); switch (fn->metaness()) { diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h index dca915ba7..8a613224f 100644 --- a/src/qdoc/generator.h +++ b/src/qdoc/generator.h @@ -53,7 +53,7 @@ class Generator public: enum ListType { Generic, Obsolete }; - enum Addendum { Invokable, PrivateSignal, QmlSignalHandler, AssociatedProperties }; + enum Addendum { Invokable, PrivateSignal, QmlSignalHandler, AssociatedProperties, TypeAlias }; Generator(); virtual ~Generator(); @@ -141,7 +141,8 @@ protected: static QString formatSince(const Node *node); void generateSince(const Node *node, CodeMarker *marker); void generateStatus(const Node *node, CodeMarker *marker); - virtual void generateAddendum(const Node *node, Addendum type, CodeMarker *marker); + virtual void generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote = true); void generateThreadSafeness(const Node *node, CodeMarker *marker); QString getMetadataElement(const Aggregate *inner, const QString &t); QStringList getMetadataElements(const Aggregate *inner, const QString &t); diff --git a/src/qdoc/helpprojectwriter.cpp b/src/qdoc/helpprojectwriter.cpp index a372ea762..d411802dc 100644 --- a/src/qdoc/helpprojectwriter.cpp +++ b/src/qdoc/helpprojectwriter.cpp @@ -137,6 +137,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["example"] = Node::Example; typeHash["externalpage"] = Node::ExternalPage; typeHash["typedef"] = Node::Typedef; + typeHash["typealias"] = Node::TypeAlias; typeHash["function"] = Node::Function; typeHash["property"] = Node::Property; typeHash["variable"] = Node::Variable; @@ -389,7 +390,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, QXmlStreamWriter & if (node->parent()) project.memberStatus[node->parent()].insert(node->status()); } break; - + case Node::TypeAlias: case Node::Typedef: { const TypedefNode *typedefNode = static_cast(node); QStringList typedefDetails = keywordDetails(node); diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 634cce3ec..cf8fa00f5 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -94,7 +94,7 @@ void Node::initialize() goals_.insert("example", Node::Example); goals_.insert("externalpage", Node::ExternalPage); goals_.insert("typedef", Node::Typedef); - goals_.insert("typealias", Node::Typedef); + goals_.insert("typealias", Node::TypeAlias); goals_.insert("function", Node::Function); goals_.insert("proxy", Node::Proxy); goals_.insert("property", Node::Property); @@ -938,6 +938,8 @@ QString Node::nodeTypeString(NodeType t) return QLatin1String("example"); case ExternalPage: return QLatin1String("external page"); + case TypeAlias: + return QLatin1String("alias"); case Typedef: return QLatin1String("typedef"); case Function: diff --git a/src/qdoc/node.h b/src/qdoc/node.h index b7293f408..4ec01673f 100644 --- a/src/qdoc/node.h +++ b/src/qdoc/node.h @@ -86,6 +86,7 @@ public: ExternalPage, Function, Typedef, + TypeAlias, Property, Variable, Group, @@ -198,8 +199,8 @@ public: 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 isTypeAlias() const { return nodeType_ == TypeAlias; } + bool isTypedef() const { return nodeType_ == Typedef || nodeType_ == TypeAlias; } bool isUnion() const { return nodeType_ == Union; } bool isVariable() const { return nodeType_ == Variable; } bool isGenericCollection() const { return (nodeType_ == Node::Collection); } @@ -892,8 +893,8 @@ private: class TypedefNode : public Node { public: - TypedefNode(Aggregate *parent, const QString &name) - : Node(Typedef, parent, name), associatedEnum_(nullptr) + TypedefNode(Aggregate *parent, const QString &name, NodeType type = Typedef) + : Node(type, parent, name), associatedEnum_(nullptr) { } @@ -912,16 +913,21 @@ private: class TypeAliasNode : public TypedefNode { public: - TypeAliasNode(Aggregate *parent, const QString &name, const QString &aliasedType) - : TypedefNode(parent, name), aliasedType_(aliasedType) + TypeAliasNode(Aggregate *parent, + const QString &name, + const QString &aliasedType) + : TypedefNode(parent, name, NodeType::TypeAlias), aliasedType_(aliasedType) { } - QString aliasedType() { return aliasedType_; } + const QString &aliasedType() const { return aliasedType_; } + const Node *aliasedNode() const { return aliasedNode_; } + void setAliasedNode(const Node *node) { aliasedNode_ = node; } Node *clone(Aggregate *parent) override; private: QString aliasedType_; + const Node *aliasedNode_ {}; }; inline void EnumNode::setFlagsType(TypedefNode *t) diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp index 60cace3c9..d2768803d 100644 --- a/src/qdoc/qdocindexfiles.cpp +++ b/src/qdoc/qdocindexfiles.cpp @@ -454,6 +454,13 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader &reader, Node *current, else if (!indexUrl.isNull()) location = Location(parent->name().toLower() + ".html"); + } else if (elementName == QLatin1String("alias")) { + node = new TypeAliasNode(parent, name, attributes.value(QLatin1String("aliasedtype")).toString()); + if (!indexUrl.isEmpty()) + location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html"); + else if (!indexUrl.isNull()) + location = Location(parent->name().toLower() + ".html"); + } else if (elementName == QLatin1String("property")) { node = new PropertyNode(parent, name); @@ -864,6 +871,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node, case Node::Typedef: nodeName = "typedef"; break; + case Node::TypeAlias: + nodeName = "alias"; + break; case Node::Property: nodeName = "property"; break; @@ -1196,6 +1206,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node, if (typedefNode->associatedEnum()) writer.writeAttribute("enum", typedefNode->associatedEnum()->fullDocumentName()); } break; + case Node::TypeAlias: + writer.writeAttribute("aliasedtype", static_cast(node)->aliasedType()); + break; case Node::Function: // Now processed in generateFunctionSection() default: break; diff --git a/src/qdoc/qdoctagfiles.cpp b/src/qdoc/qdoctagfiles.cpp index 0d9b0aee0..2d9bce006 100644 --- a/src/qdoc/qdoctagfiles.cpp +++ b/src/qdoc/qdoctagfiles.cpp @@ -183,6 +183,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter &writer, const Aggreg nodeName = "member"; kind = "enumeration"; break; + case Node::TypeAlias: // Treated as typedef case Node::Typedef: nodeName = "member"; kind = "typedef"; @@ -309,6 +310,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter &writer, const Aggreg writer.writeEndElement(); // member } } break; + case Node::TypeAlias: // Treated as typedef case Node::Typedef: { const TypedefNode *typedefNode = static_cast(node); if (typedefNode->associatedEnum()) diff --git a/src/qdoc/sections.cpp b/src/qdoc/sections.cpp index c9012e21c..00357c246 100644 --- a/src/qdoc/sections.cpp +++ b/src/qdoc/sections.cpp @@ -373,6 +373,9 @@ Sections::Sections(const NodeMultiMap &nsmap) : aggregate_(nullptr) case Node::Typedef: sections[SinceTypedefs].appendMember(node); break; + case Node::TypeAlias: + sections[SinceTypeAliases].appendMember(node); + break; case Node::Function: { const FunctionNode *fn = static_cast(node); switch (fn->metaness()) { @@ -552,6 +555,7 @@ void Sections::initSections() v[SinceMacros].init(" New Macros"); v[SinceEnumTypes].init(" New Enum Types"); v[SinceTypedefs].init(" New Typedefs"); + v[SinceTypeAliases].init(" New Type Aliases"); v[SinceProperties].init(" New Properties"); v[SinceVariables].init(" New Variables"); v[SinceQmlTypes].init(" New QML Types"); @@ -623,6 +627,7 @@ void Sections::stdRefPageSwitch(SectionVector &v, Node *n, Node *t) return; case Node::Enum: case Node::Typedef: + case Node::TypeAlias: v[StdTypes].insert(n); return; case Node::Function: { diff --git a/src/qdoc/sections.h b/src/qdoc/sections.h index c8d17b141..dfcaaed7b 100644 --- a/src/qdoc/sections.h +++ b/src/qdoc/sections.h @@ -180,6 +180,7 @@ public: QmlAttachedMethods = 6, ProtectedTypes = 7, SinceTypedefs = 7, + SinceTypeAliases = 7, ProtectedFunctions = 8, SinceProperties = 8, ProtectedSlots = 9, diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp index f6477b6b1..e20b8cc65 100644 --- a/src/qdoc/tree.cpp +++ b/src/qdoc/tree.cpp @@ -355,11 +355,14 @@ void Tree::resolveCppToQmlLinks() /*! For each C++ class node, resolve any \c using clauses that appeared in the class declaration. + + For type aliases, resolve the aliased node. */ -void Tree::resolveUsingClauses() +void Tree::resolveUsingClauses(Aggregate *parent) { - const NodeList &children = root_.childNodes(); - for (auto *child : children) { + if (!parent) + parent = &root_; + for (auto *child : parent->childNodes()) { if (child->isClassNode()) { ClassNode *cn = static_cast(child); QVector &usingClauses = cn->usingClauses(); @@ -370,7 +373,13 @@ void Tree::resolveUsingClauses() usingClause.setNode(n); } } + } else if (child->isTypeAlias()) { + TypeAliasNode *ta = static_cast(child); + ta->setAliasedNode(qdb_->findNodeForTarget(ta->aliasedType(), child->parent())); } + + if (child->genus() == Node::CPP && child->isAggregate()) + resolveUsingClauses(static_cast(child)); } } diff --git a/src/qdoc/tree.h b/src/qdoc/tree.h index b7e4dce75..10272ec84 100644 --- a/src/qdoc/tree.h +++ b/src/qdoc/tree.h @@ -151,7 +151,7 @@ private: // The rest of the class is private. void resolvePropertyOverriddenFromPtrs(Aggregate *n); void resolveProperties(); void resolveCppToQmlLinks(); - void resolveUsingClauses(); + void resolveUsingClauses(Aggregate *parent = nullptr); void removePrivateAndInternalBases(NamespaceNode *rootNode); NamespaceNode *root() { return &root_; } const NamespaceNode *root() const { return &root_; } diff --git a/src/qdoc/xmlgenerator.cpp b/src/qdoc/xmlgenerator.cpp index 8b266ca18..ffffc283a 100644 --- a/src/qdoc/xmlgenerator.cpp +++ b/src/qdoc/xmlgenerator.cpp @@ -76,6 +76,7 @@ int XmlGenerator::hOffset(const Node *node) case Node::Page: return 1; case Node::Enum: + case Node::TypeAlias: case Node::Typedef: case Node::Function: case Node::Property: @@ -239,6 +240,9 @@ QString XmlGenerator::refForNode(const Node *node) case Node::Enum: ref = node->name() + "-enum"; break; + case Node::TypeAlias: + ref = node->name() + "-alias"; + break; case Node::Typedef: { const auto tdn = static_cast(node); if (tdn->associatedEnum()) @@ -450,6 +454,8 @@ QString XmlGenerator::targetType(const Node *node) return QStringLiteral("page"); case Node::Enum: return QStringLiteral("enum"); + case Node::TypeAlias: + return QStringLiteral("alias"); case Node::Typedef: return QStringLiteral("typedef"); case Node::Property: diff --git a/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html index 21870bb3f..1b7260e33 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html @@ -11,6 +11,9 @@

List of All Members for TestType

This is the complete list of members for TestType, including inherited members.

    +
  • DerivedType
  • +
  • NotTypedef
  • +
  • typedef SomeType
  • inlineFunction()
  • nothing()
  • overload()
  • diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml index 76025b06e..768e4d8f1 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml @@ -32,6 +32,19 @@ Detailed Description + +Member Type Documentation + +Test::typedef SomeType + +SomeTypepublic +active +unspecified +TestCPP + +A typedef. + + Member Function Documentation diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml index 9bb613cfc..ced1bea5b 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml @@ -32,6 +32,31 @@ Detailed Description + +Member Type Documentation + +[alias] TestDerived::DerivedType + +DerivedTypepublic +active +unspecified +TestCPP + +This is a type alias for TestQDoc::Test::SomeType. +An aliased typedef. + + +[alias] TestDerived::NotTypedef + +NotTypedefpublic +active +unspecified +TestCPP + +This is a type alias for int. +I'm an alias, not a typedef. + + Member Function Documentation diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml index 7ae77ec5a..d7ee1f834 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml @@ -56,6 +56,11 @@ Function that must be reimplemented. + + + A typedef. + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml index 76a335658..7711b09df 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml @@ -8,6 +8,16 @@ + + + An aliased typedef. + + + + + I'm an alias, not a typedef. + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html index 0d4283a8f..7165b2bdb 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html @@ -11,6 +11,7 @@

    Contents

    + +

    Public Types

    +
    + +
    typedef SomeType

    Public Functions

    @@ -55,6 +61,13 @@

    Detailed Description

    +
    +

    Member Type Documentation

    + +

    typedef Test::SomeType

    +

    A typedef.

    + +

    Member Function Documentation

    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html index 864205274..1fc1a19d9 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html @@ -35,6 +35,7 @@

    Public Types

    +
    enum class ScopedEnum { This, That, All }
    typedef SomeType

    Public Functions

    @@ -71,6 +72,10 @@ TestQDoc::Test::ScopedEnum::AllThis | ThatEverything
    + +

    typedef Test::SomeType

    +

    A typedef.

    +

    Member Function Documentation

    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html index 75643dede..0ec969042 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html @@ -11,6 +11,7 @@

    Contents

    + +

    Public Types

    +
    + +
    typedef SomeType

    Public Functions

    @@ -56,6 +62,13 @@

    Detailed Description

    +
    +

    Member Type Documentation

    + +

    typedef Test::SomeType

    +

    A typedef.

    + +

    Member Function Documentation

    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/test.qhp b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp index 387e018ae..ebc12ce8f 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/test.qhp +++ b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp @@ -61,7 +61,10 @@ + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index b/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index index ae3b4a875..3c0a54885 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index +++ b/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index @@ -29,9 +29,12 @@ + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html index 5554519af..fc87f8613 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html @@ -11,6 +11,7 @@

    List of All Members for Test

    This is the complete list of members for TestQDoc::Test, including inherited members.

    + +
    typedef SomeType

    Public Functions

    @@ -55,6 +61,13 @@

    Detailed Description

    +
    +

    Member Type Documentation

    + +

    typedef Test::SomeType

    +

    A typedef.

    + +

    Member Function Documentation

    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html index 89b206b27..4dc3649db 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html @@ -11,8 +11,12 @@

    List of All Members for TestDerived

    This is the complete list of members for TestQDoc::TestDerived, including inherited members.

    TestDerived Class

    -(TestQDoc::TestDerived)
    +class TestQDoc::TestDerived

    A derived class in a namespace. More...

    @@ -26,6 +27,12 @@
    qmake: QT += testcpp
    Inherits: TestQDoc::Test
    + +

    Public Types

    +
    + + +
    (alias) DerivedType
    (alias) NotTypedef

    Reimplemented Public Functions

    @@ -37,6 +44,19 @@

    Detailed Description

    +
    +

    Member Type Documentation

    + +

    [alias] TestDerived::DerivedType

    +

    This is a type alias for TestQDoc::Test::SomeType.

    +

    An aliased typedef.

    + + +

    [alias] TestDerived::NotTypedef

    +

    This is a type alias for int.

    +

    I'm an alias, not a typedef.

    + +

    Member Function Documentation

    diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp index 31b910fae..e43ecf0b7 100644 --- a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp @@ -154,6 +154,11 @@ void Test::virtualFun() return; } +/*! + \typedef Test::SomeType + \brief A typedef. +*/ + /*! \reimp */ @@ -172,6 +177,16 @@ void TestDerived::virtualFun() a parameter \a b. */ +/*! + \typealias TestDerived::DerivedType + An aliased typedef. +*/ + +/*! + \typedef TestDerived::NotTypedef + I'm an alias, not a typedef. +*/ + /*! \if defined(test_template) \fn template void TestQDoc::Test::funcTemplate(T1 a, T2 b) diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h index cb812375b..b9644eb94 100644 --- a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h @@ -41,6 +41,9 @@ public: OmittedValue = 99 }; #endif + typedef struct { + int data; + } SomeType; int someFunction(int v = 0); void someFunctionDefaultArg(int i, bool b); void obsoleteMember(); @@ -61,6 +64,8 @@ protected: class TestDerived : public Test { public: + using DerivedType = Test::SomeType; + using NotTypedef = int; void virtualFun() override; }; diff --git a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp index f8abee1b4..7cc0e67ab 100644 --- a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp +++ b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp @@ -217,6 +217,8 @@ void tst_generatedOutput::htmlFromCpp() "testcpp-module.html " "testqdoc-test.html " "testqdoc-test-members.html " + "testqdoc-testderived.html " + "testqdoc-testderived-members.html " "testqdoc.html"); } -- cgit v1.2.3