summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTopi Reinio <topi.reinio@qt.io>2020-01-17 14:21:46 +0100
committerTopi Reiniƶ <topi.reinio@qt.io>2020-01-20 12:11:44 +0000
commit03f1c6e3ed01f8270463ab8aa4afb4f7c2321cdb (patch)
treed4ce1dd46b47df7bab812196b4f9272d70a223f4
parentf7ef0f5bc1d6b1e4ed9b0983c0e364bbf2654624 (diff)
qdoc: Teach QDoc to output function and class template parameters
Add a visitor functor that reconstructs template parameters from the Clang AST, and use it when either a class or a method template is detected. Store this information in the node - for now, they are used only in the class reference page subtitle (for classes), and detailed section of function documentation. Template parameters are not considered when searching/linking to entities, they are for display only. [ChangeLog][qdoc] Added capability to display class/method template parameters in the generated documentation. Fixes: QTBUG-17456 Change-Id: I300cc63b9fa20d4f6efaeaa27ea3769635a7b32c Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io>
-rw-r--r--src/qdoc/clangcodeparser.cpp67
-rw-r--r--src/qdoc/cppcodemarker.cpp8
-rw-r--r--src/qdoc/docbookgenerator.cpp7
-rw-r--r--src/qdoc/htmlgenerator.cpp16
-rw-r--r--src/qdoc/node.cpp50
-rw-r--r--src/qdoc/node.h10
-rw-r--r--tests/auto/qdoc/generatedoutput/TestCPP4
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml2
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml2
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html2
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/template/bar.html34
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/template/baz.html34
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/template/foo.html34
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html96
-rw-r--r--tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html2
-rw-r--r--tests/auto/qdoc/generatedoutput/testcpp.cpp9
-rw-r--r--tests/auto/qdoc/generatedoutput/testcpp.h5
-rw-r--r--tests/auto/qdoc/generatedoutput/testtemplate.cpp47
-rw-r--r--tests/auto/qdoc/generatedoutput/testtemplate.h53
-rw-r--r--tests/auto/qdoc/generatedoutput/testtemplate.qdocconf8
-rw-r--r--tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp9
21 files changed, 451 insertions, 48 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index 7d10ae089..848f2b828 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -110,6 +110,55 @@ static QString fromCXString(CXString &&string)
return ret;
}
+static QString templateDecl(CXCursor cursor);
+
+/*!
+ Returns a list of template parameters at \a cursor.
+*/
+static QStringList getTemplateParameters(CXCursor cursor)
+{
+ QStringList parameters;
+ visitChildrenLambda(cursor, [&parameters](CXCursor cur) {
+ QString name = fromCXString(clang_getCursorSpelling(cur));
+ QString type;
+
+ switch (clang_getCursorKind(cur)) {
+ case CXCursor_TemplateTypeParameter:
+ type = QStringLiteral("typename");
+ break;
+ case CXCursor_NonTypeTemplateParameter:
+ type = fromCXString(clang_getTypeSpelling(clang_getCursorType(cur)));
+ // Hack: Omit QtPrivate template parameters from public documentation
+ if (type.startsWith(QLatin1String("QtPrivate")))
+ return CXChildVisit_Continue;
+ break;
+ case CXCursor_TemplateTemplateParameter:
+ type = templateDecl(cur) + QLatin1String(" class");
+ break;
+ default:
+ return CXChildVisit_Continue;
+ }
+
+ if (!name.isEmpty())
+ name.prepend(QLatin1Char(' '));
+
+ parameters << type + name;
+ return CXChildVisit_Continue;
+ });
+
+ return parameters;
+}
+
+/*!
+ Gets the template declaration at specified \a cursor.
+ */
+static QString templateDecl(CXCursor cursor)
+{
+ QStringList params = getTemplateParameters(cursor);
+ return QLatin1String("template <") + params.join(QLatin1String(", ")) +
+ QLatin1Char('>');
+}
+
/*!
convert a CXSourceLocation to a qdoc Location
*/
@@ -573,6 +622,7 @@ CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocat
CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation loc)
{
auto kind = clang_getCursorKind(cursor);
+ QString templateString;
switch (kind) {
case CXCursor_TypeAliasDecl: {
QString spelling = getSpelling(clang_getCursorExtent(cursor));
@@ -595,8 +645,10 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
if (fromCXString(clang_getCursorSpelling(cursor)).isEmpty()) // anonymous struct or union
return CXChildVisit_Continue;
Q_FALLTHROUGH();
- case CXCursor_ClassDecl:
- case CXCursor_ClassTemplate: {
+ case CXCursor_ClassTemplate:
+ templateString = templateDecl(cursor);
+ Q_FALLTHROUGH();
+ case CXCursor_ClassDecl: {
if (!clang_isCursorDefinition(cursor))
return CXChildVisit_Continue;
@@ -622,10 +674,8 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
classe->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor)));
classe->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor)));
- if (kind == CXCursor_ClassTemplate) {
- QString displayName = fromCXString(clang_getCursorSpelling(cursor));
- classe->setTemplateStuff(displayName.mid(className.size()));
- }
+ if (kind == CXCursor_ClassTemplate)
+ classe->setTemplateDecl(templateString);
QScopedValueRollback<Aggregate *> setParent(parent_, classe);
return visitChildren(cursor);
@@ -661,8 +711,10 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
QScopedValueRollback<Aggregate *> setParent(parent_, ns);
return visitChildren(cursor);
}
- case CXCursor_FunctionDecl:
case CXCursor_FunctionTemplate:
+ templateString = templateDecl(cursor);
+ Q_FALLTHROUGH();
+ case CXCursor_FunctionDecl:
case CXCursor_CXXMethod:
case CXCursor_Constructor:
case CXCursor_Destructor:
@@ -760,6 +812,7 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l
if (clang_isFunctionTypeVariadic(funcType))
parameters.append(QStringLiteral("..."));
readParameterNamesAndAttributes(fn, cursor);
+ fn->setTemplateDecl(templateString);
return CXChildVisit_Continue;
}
#if CINDEX_VERSION >= 36
diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp
index b23312d19..25c2f630b 100644
--- a/src/qdoc/cppcodemarker.cpp
+++ b/src/qdoc/cppcodemarker.cpp
@@ -136,9 +136,13 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, const Node * /* relati
break;
case Node::Function:
func = (const FunctionNode *)node;
-
+ if (style == Section::Details) {
+ QString templateDecl = node->templateDecl();
+ if (!templateDecl.isEmpty())
+ synopsis = templateDecl + QLatin1Char(' ');
+ }
if (style != Section::AllMembers && !func->returnType().isEmpty())
- synopsis = typified(func->returnType(), true);
+ synopsis += typified(func->returnType(), true);
synopsis += name;
if (!func->isMacroWithoutParams()) {
synopsis += QLatin1Char('(');
diff --git a/src/qdoc/docbookgenerator.cpp b/src/qdoc/docbookgenerator.cpp
index 36149a8ca..7653261e1 100644
--- a/src/qdoc/docbookgenerator.cpp
+++ b/src/qdoc/docbookgenerator.cpp
@@ -2425,8 +2425,11 @@ void DocBookGenerator::generateCppReferencePage(Node *node)
ns = static_cast<const NamespaceNode *>(aggregate);
} else if (aggregate->isClass()) {
rawTitle = aggregate->plainName();
- fullTitle = aggregate->plainFullName();
- title = rawTitle + " Class";
+ QString templateDecl = node->templateDecl();
+ if (!templateDecl.isEmpty())
+ fullTitle = QString("%1 %2 ").arg(templateDecl, aggregate->typeWord(false));
+ fullTitle += aggregate->plainFullName();
+ title = rawTitle + QLatin1Char(' ') + aggregate->typeWord(true);
}
QString subtitleText;
diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp
index 6196a6641..3f38ba96d 100644
--- a/src/qdoc/htmlgenerator.cpp
+++ b/src/qdoc/htmlgenerator.cpp
@@ -1171,6 +1171,7 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
Sections sections(aggregate);
QString word = aggregate->typeWord(true);
+ QString templateDecl = aggregate->templateDecl();
if (aggregate->isNamespace()) {
rawTitle = aggregate->plainName();
fullTitle = aggregate->plainFullName();
@@ -1181,11 +1182,7 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
} else if (aggregate->isClassNode()) {
rawTitle = aggregate->plainName();
fullTitle = aggregate->plainFullName();
- if (aggregate->isStruct())
- word = QLatin1String("Struct");
- else if (aggregate->isUnion())
- word = QLatin1String("Union");
- title = rawTitle + " " + word;
+ title = rawTitle + QLatin1Char(' ') + word;
summarySections = &sections.stdCppClassSummarySections();
detailsSections = &sections.stdCppClassDetailsSections();
} else if (aggregate->isHeader()) {
@@ -1195,10 +1192,13 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m
}
Text subtitleText;
- if (rawTitle != fullTitle) {
- if (aggregate->parent()->isClassNode()) {
+ if (rawTitle != fullTitle || !templateDecl.isEmpty()) {
+ if (aggregate->isClassNode()) {
+ if (!templateDecl.isEmpty())
+ subtitleText << templateDecl + QLatin1Char(' ');
+ subtitleText << aggregate->typeWord(false) + QLatin1Char(' ');
const QStringList ancestors = fullTitle.split(QLatin1String("::"));
- for (const auto a : ancestors) {
+ for (const auto &a : ancestors) {
if (a == rawTitle) {
subtitleText << a;
break;
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index ed88de6e5..cd89737d7 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -1488,11 +1488,13 @@ QString Node::physicalModuleName() const
\sa PageType
*/
-/*! \fn QString Node::signature(bool values, bool noReturnType) const
+/*! \fn QString Node::signature(bool values, bool noReturnType, bool templateParams) const
If this node is a FunctionNode, this function returns the function's
- signature, including default values if \a values is \c true, and
- including the function's return type if \a noReturnType is \c false.
+ signature, including default values if \a values is \c true,
+ function's return type if \a noReturnType is \c false, and
+ prefixed with 'template <parameter_list>' for function templates
+ if templateParams is \true.
If this node is not a FunctionNode, this function returns plainName().
*/
@@ -4240,27 +4242,35 @@ bool FunctionNode::hasActiveAssociatedProperty() const
/*!
Reconstructs and returns the function's signature. If \a values
- is true, the default values of the parameters are included, if
- present.
+ is \c true, the default values of the parameters are included.
+ The return type is included unless \a noReturnType is \c true.
+ Function templates are prefixed with \c {template <parameter_list>}
+ if \a templateParams is \c true.
*/
-QString FunctionNode::signature(bool values, bool noReturnType) const
+QString FunctionNode::signature(bool values, bool noReturnType, bool templateParams) const
{
- QString result;
- if (!noReturnType && !returnType().isEmpty())
- result = returnType() + QLatin1Char(' ');
- result += name();
+ QStringList elements;
+
+ if (templateParams)
+ elements << templateDecl();
+ if (!noReturnType)
+ elements << returnType_;
+ elements.removeAll({});
+
if (!isMacroWithoutParams()) {
- result += QLatin1Char('(') + parameters_.signature(values) + QLatin1Char(')');
- if (isMacro())
- return result;
+ elements << name() + QLatin1Char('(') + parameters_.signature(values) + QLatin1Char(')');
+ if (!isMacro()) {
+ if (isConst())
+ elements << QStringLiteral("const");
+ if (isRef())
+ elements << QStringLiteral("&");
+ else if (isRefRef())
+ elements << QStringLiteral("&&");
+ }
+ } else {
+ elements << name();
}
- if (isConst())
- result += " const";
- if (isRef())
- result += " &";
- else if (isRefRef())
- result += " &&";
- return result;
+ return elements.join(QLatin1Char(' '));
}
/*!
diff --git a/src/qdoc/node.h b/src/qdoc/node.h
index d400fc1d4..ea075e6ed 100644
--- a/src/qdoc/node.h
+++ b/src/qdoc/node.h
@@ -232,7 +232,7 @@ public:
QString plainFullName(const Node *relative = nullptr) const;
QString plainSignature() const;
QString fullName(const Node *relative = nullptr) const;
- virtual QString signature(bool, bool) const { return plainName(); }
+ virtual QString signature(bool, bool, bool = false) const { return plainName(); }
const QString &fileNameBase() const { return fileNameBase_; }
bool hasFileNameBase() const { return !fileNameBase_.isEmpty(); }
@@ -251,7 +251,7 @@ public:
void setSince(const QString &since);
void setPhysicalModuleName(const QString &name) { physicalModuleName_ = name; }
void setUrl(const QString &url) { url_ = url; }
- void setTemplateStuff(const QString &t) { templateStuff_ = t; }
+ void setTemplateDecl(const QString &t) { templateDecl_ = t; }
void setReconstitutedBrief(const QString &t) { reconstitutedBrief_ = t; }
void setParent(Aggregate *n) { parent_ = n; }
void setIndexNodeFlag(bool isIndexNode = true) { indexNodeFlag_ = isIndexNode; }
@@ -319,7 +319,7 @@ public:
ThreadSafeness threadSafeness() const;
ThreadSafeness inheritedThreadSafeness() const;
QString since() const { return since_; }
- QString templateStuff() const { return templateStuff_; }
+ const QString &templateDecl() const { return templateDecl_; }
const QString &reconstitutedBrief() const { return reconstitutedBrief_; }
QString nodeSubtypeString() const;
virtual void addPageKeywords(const QString &) {}
@@ -387,7 +387,7 @@ private:
QString physicalModuleName_;
QString url_;
QString since_;
- QString templateStuff_;
+ QString templateDecl_;
QString reconstitutedBrief_;
// mutable QString uuid_;
QString outSubDir_;
@@ -1053,7 +1053,7 @@ public:
const Parameters &parameters() const { return parameters_; }
bool isPrivateSignal() const { return parameters_.isPrivateSignal(); }
void setParameters(const QString &signature) { parameters_.set(signature); }
- QString signature(bool values, bool noReturnType) const override;
+ QString signature(bool values, bool noReturnType, bool templateParams = false) const override;
const QString &overridesThis() const { return overridesThis_; }
const NodeList &associatedProperties() const { return associatedProperties_; }
diff --git a/tests/auto/qdoc/generatedoutput/TestCPP b/tests/auto/qdoc/generatedoutput/TestCPP
index 50cce69ff..4ed786108 100644
--- a/tests/auto/qdoc/generatedoutput/TestCPP
+++ b/tests/auto/qdoc/generatedoutput/TestCPP
@@ -1 +1,5 @@
#include "testcpp.h"
+
+#ifdef test_template
+# include "testtemplate.h"
+#endif
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 39292e2dc..0cfeb1724 100644
--- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml
+++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml
@@ -2,7 +2,7 @@
<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.2" xml:lang="en">
<db:info>
<db:title>Test Class</db:title>
-<db:subtitle>(TestQDoc::Test)</db:subtitle>
+<db:subtitle>TestQDoc::Test</db:subtitle>
<db:productname>TestCPP</db:productname>
<db:titleabbrev>TestCPP Reference Documentation</db:titleabbrev>
<db:abstract>
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 7a07adb85..9bb613cfc 100644
--- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml
+++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml
@@ -2,7 +2,7 @@
<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.2" xml:lang="en">
<db:info>
<db:title>TestDerived Class</db:title>
-<db:subtitle>(TestQDoc::TestDerived)</db:subtitle>
+<db:subtitle>TestQDoc::TestDerived</db:subtitle>
<db:productname>TestCPP</db:productname>
<db:titleabbrev>TestCPP Reference Documentation</db:titleabbrev>
<db:abstract>
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 0cb766e42..71c54c2e9 100644
--- a/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html
+++ b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html
@@ -19,7 +19,7 @@
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Test Class</h1>
-<span class="small-subtitle">(<a href="testqdoc-test.html">TestQDoc::Test</a>)<br/></span>
+<span class="small-subtitle">class <a href="testqdoc.html">TestQDoc</a>::Test</span>
<!-- $$$Test-brief -->
<p>A class in a namespace. <a href="#details">More...</a></p>
<!-- @@@Test -->
diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html b/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html
new file mode 100644
index 000000000..552cbe9cd
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testtemplate.cpp -->
+ <title>Bar Class | TestCPP</title>
+</head>
+<body>
+<li>Bar</li>
+<div class="sidebar">
+<div class="toc">
+<h3><a name="toc">Contents</a></h3>
+<ul>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title">Bar Class</h1>
+<span class="small-subtitle">template &lt;typename T, typename D&gt; class Bar</span>
+<!-- $$$Bar-brief -->
+<p>Another class template. <a href="#details">More...</a></p>
+<!-- @@@Bar -->
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include &lt;Bar&gt;</span>
+</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr></table></div><ul>
+</ul>
+<a name="details"></a>
+<!-- $$$Bar-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@Bar -->
+</body>
+</html>
diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html b/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html
new file mode 100644
index 000000000..4ab135c20
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testtemplate.cpp -->
+ <title>Baz Class | TestCPP</title>
+</head>
+<body>
+<li>Baz</li>
+<div class="sidebar">
+<div class="toc">
+<h3><a name="toc">Contents</a></h3>
+<ul>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title">Baz Class</h1>
+<span class="small-subtitle">template &lt;template &lt;typename&gt; class X, typename Y&gt; class Baz</span>
+<!-- $$$Baz-brief -->
+<p>Class template template. <a href="#details">More...</a></p>
+<!-- @@@Baz -->
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include &lt;Baz&gt;</span>
+</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr></table></div><ul>
+</ul>
+<a name="details"></a>
+<!-- $$$Baz-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@Baz -->
+</body>
+</html>
diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html b/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html
new file mode 100644
index 000000000..9e92a01b5
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testtemplate.cpp -->
+ <title>Foo Class | TestCPP</title>
+</head>
+<body>
+<li>Foo</li>
+<div class="sidebar">
+<div class="toc">
+<h3><a name="toc">Contents</a></h3>
+<ul>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title">Foo Class</h1>
+<span class="small-subtitle">template &lt;typename T&gt; class Foo</span>
+<!-- $$$Foo-brief -->
+<p>Class template. <a href="#details">More...</a></p>
+<!-- @@@Foo -->
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include &lt;Foo&gt;</span>
+</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr></table></div><ul>
+</ul>
+<a name="details"></a>
+<!-- $$$Foo-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@Foo -->
+</body>
+</html>
diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html
new file mode 100644
index 000000000..d19d15535
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testcpp.cpp -->
+ <title>Test Class | TestCPP</title>
+</head>
+<body>
+<li>Test</li>
+<div class="sidebar">
+<div class="toc">
+<h3><a name="toc">Contents</a></h3>
+<ul>
+<li class="level1"><a href="#public-functions">Public Functions</a></li>
+<li class="level1"><a href="#protected-functions">Protected Functions</a></li>
+<li class="level1"><a href="#macros">Macros</a></li>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title">Test Class</h1>
+<span class="small-subtitle">class <a href="testqdoc.html">TestQDoc</a>::Test</span>
+<!-- $$$Test-brief -->
+<p>A class in a namespace. <a href="#details">More...</a></p>
+<!-- @@@Test -->
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include &lt;Test&gt;</span>
+</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Inherited By:</td><td class="memItemRight bottomAlign"> <p><a href="testqdoc-testderived.html">TestQDoc::TestDerived</a></p>
+</td></tr></table></div><ul>
+<li><a href="testqdoc-test-members.html">List of all members, including inherited members</a></li>
+<li><a href="testqdoc-test-obsolete.html">Obsolete members</a></li>
+</ul>
+<a name="public-functions"></a>
+<h2 id="public-functions">Public Functions</h2>
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#inlineFunction">inlineFunction</a></b>()</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> int </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#someFunction">someFunction</a></b>(int <i>v</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#someFunctionDefaultArg">someFunctionDefaultArg</a></b>(int <i>i</i>, bool <i>b</i> = false)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> virtual void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#virtualFun">virtualFun</a></b>()</td></tr>
+</table></div>
+<a name="protected-functions"></a>
+<h2 id="protected-functions">Protected Functions</h2>
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#funcTemplate">funcTemplate</a></b>(T1 <i>a</i>, T2 <i>b</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#overload">overload</a></b>()</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#overload-1">overload</a></b>(bool <i>b</i>)</td></tr>
+</table></div>
+<a name="macros"></a>
+<h2 id="macros">Macros</h2>
+<div class="table"><table class="alignedsummary">
+<tr><td class="memItemLeft rightAlign topAlign"> </td><td class="memItemRight bottomAlign"><b><a href="testqdoc-test.html#QDOCTEST_MACRO2">QDOCTEST_MACRO2</a></b>(<i>x</i>)</td></tr>
+</table></div>
+<a name="details"></a>
+<!-- $$$Test-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@Test -->
+<div class="func">
+<h2>Member Function Documentation</h2>
+<!-- $$$ -->
+<div class="fngroup">
+<h3 class="fn fngroupitem" id="overload"><a name="overload"></a><code>[protected] </code><span class="type">void</span> Test::<span class="name">overload</span>()</h3><h3 class="fn fngroupitem" id="overload-1"><a name="overload-1"></a><code>[protected] </code><span class="type">void</span> Test::<span class="name">overload</span>(<span class="type">bool</span> <i>b</i>)</h3></div>
+<p>Overloads that share a documentation comment, optionally taking a parameter <i>b</i>.</p>
+<!-- @@@ -->
+<!-- $$$funcTemplate[overload1]$$$funcTemplateT1T2 -->
+<h3 class="fn" id="funcTemplate"><a name="funcTemplate"></a><code>[protected] </code>template &lt;typename T1, typename T2&gt; <span class="type">void</span> Test::<span class="name">funcTemplate</span>(<span class="type">T1</span> <i>a</i>, <span class="type">T2</span> <i>b</i>)</h3>
+<p>Function template with two parameters, <i>a</i> and <i>b</i>.</p>
+<!-- @@@funcTemplate -->
+<!-- $$$inlineFunction[overload1]$$$inlineFunction -->
+<h3 class="fn" id="inlineFunction"><a name="inlineFunction"></a><span class="type">void</span> Test::<span class="name">inlineFunction</span>()</h3>
+<p>An inline function, documented using the \fn QDoc command.</p>
+<!-- @@@inlineFunction -->
+<!-- $$$someFunction[overload1]$$$someFunctionint -->
+<h3 class="fn" id="someFunction"><a name="someFunction"></a><span class="type">int</span> Test::<span class="name">someFunction</span>(<span class="type">int</span> <i>v</i>)</h3>
+<p>Function that takes a parameter <i>v</i>. Also returns the value of <i>v</i>.</p>
+<!-- @@@someFunction -->
+<!-- $$$someFunctionDefaultArg[overload1]$$$someFunctionDefaultArgintbool -->
+<h3 class="fn" id="someFunctionDefaultArg"><a name="someFunctionDefaultArg"></a><span class="type">void</span> Test::<span class="name">someFunctionDefaultArg</span>(<span class="type">int</span> <i>i</i>, <span class="type">bool</span> <i>b</i> = false)</h3>
+<p>Function that takes a parameter <i>i</i> and <i>b</i>.</p>
+<!-- @@@someFunctionDefaultArg -->
+<!-- $$$virtualFun[overload1]$$$virtualFun -->
+<h3 class="fn" id="virtualFun"><a name="virtualFun"></a><code>[virtual] </code><span class="type">void</span> Test::<span class="name">virtualFun</span>()</h3>
+<p>Function that must be reimplemented.</p>
+<!-- @@@virtualFun -->
+</div>
+<div class="macros">
+<h2>Macro Documentation</h2>
+<!-- $$$QDOCTEST_MACRO2[overload1]$$$QDOCTEST_MACRO2 -->
+<h3 class="fn" id="QDOCTEST_MACRO2"><a name="QDOCTEST_MACRO2"></a><span class="name">QDOCTEST_MACRO2</span>(<i>x</i>)</h3>
+<p>A macro with argument <i>x</i>.</p>
+<p>This function was introduced in Test 1.1.</p>
+<!-- @@@QDOCTEST_MACRO2 -->
+</div>
+</body>
+</html>
diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html
index f373f725a..f3c8d55d0 100644
--- a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html
+++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html
@@ -19,7 +19,7 @@
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Test Class</h1>
-<span class="small-subtitle">(<a href="testqdoc-test.html">TestQDoc::Test</a>)<br/></span>
+<span class="small-subtitle">class <a href="testqdoc.html">TestQDoc</a>::Test</span>
<!-- $$$Test-brief -->
<p>A class in a namespace. <a href="#details">More...</a></p>
<!-- @@@Test -->
diff --git a/tests/auto/qdoc/generatedoutput/testcpp.cpp b/tests/auto/qdoc/generatedoutput/testcpp.cpp
index 3073148c2..b703a844b 100644
--- a/tests/auto/qdoc/generatedoutput/testcpp.cpp
+++ b/tests/auto/qdoc/generatedoutput/testcpp.cpp
@@ -162,4 +162,13 @@ void TestDerived::virtualFun()
a parameter \a b.
*/
+/*!
+\if defined(test_template)
+ \fn template <typename T1, typename T2> void TestQDoc::Test::funcTemplate(T1 a, T2 b)
+ \brief Function template with two parameters, \a a and \a b.
+\else
+ //! nothing
+\endif
+*/
+
} // namespace TestQDoc
diff --git a/tests/auto/qdoc/generatedoutput/testcpp.h b/tests/auto/qdoc/generatedoutput/testcpp.h
index c34ada99b..5cb542dc4 100644
--- a/tests/auto/qdoc/generatedoutput/testcpp.h
+++ b/tests/auto/qdoc/generatedoutput/testcpp.h
@@ -44,6 +44,11 @@ public:
protected:
void overload() {}
void overload(bool b) { if (!b) return; }
+#ifdef test_template
+ template <typename T1, typename T2> void funcTemplate(T1 a, T2 b) {
+ a = b;
+ }
+#endif
};
class TestDerived : public Test {
diff --git a/tests/auto/qdoc/generatedoutput/testtemplate.cpp b/tests/auto/qdoc/generatedoutput/testtemplate.cpp
new file mode 100644
index 000000000..e9755769f
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/testtemplate.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testtemplate.h"
+
+/*!
+ \class Foo
+ \inmodule TestCPP
+ \brief Class template.
+*/
+
+/*!
+ \class Bar
+ \inmodule TestCPP
+ \brief Another class template.
+*/
+
+/*!
+ \class Baz
+ \inmodule TestCPP
+ \brief Class template template.
+*/
diff --git a/tests/auto/qdoc/generatedoutput/testtemplate.h b/tests/auto/qdoc/generatedoutput/testtemplate.h
new file mode 100644
index 000000000..d60ab0da4
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/testtemplate.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+template <typename T>
+class Foo {
+public:
+ Foo() {}
+private:
+ T t;
+};
+
+template <typename T, typename D>
+class Bar {
+public:
+ Bar() {}
+private:
+ T t;
+ D d;
+};
+
+template<template<typename> class X, typename Y>
+struct Baz
+{
+ X<Y> z;
+ Baz() : z() {}
+};
diff --git a/tests/auto/qdoc/generatedoutput/testtemplate.qdocconf b/tests/auto/qdoc/generatedoutput/testtemplate.qdocconf
new file mode 100644
index 000000000..437319683
--- /dev/null
+++ b/tests/auto/qdoc/generatedoutput/testtemplate.qdocconf
@@ -0,0 +1,8 @@
+include(testcpp.qdocconf)
+defines += test_template
+
+headers += testtemplate.h
+sources += testtemplate.cpp
+
+HTML.nosubdirs = true
+HTML.outputsubdir = template
diff --git a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp
index 01608e95f..a47f4735f 100644
--- a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp
+++ b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp
@@ -57,6 +57,7 @@ private slots:
// Output format independent tests
void examplesManifestXml();
void ignoresinceVariable();
+ void templateParameters();
private:
QScopedPointer<QTemporaryDir> m_outputDir;
@@ -275,6 +276,14 @@ void tst_generatedOutput::ignoresinceVariable()
"ignoresince/testqdoc-test.html");
}
+void tst_generatedOutput::templateParameters()
+{
+ testAndCompare("testtemplate.qdocconf", "template/testqdoc-test.html "
+ "template/foo.html "
+ "template/bar.html "
+ "template/baz.html");
+}
+
QTEST_APPLESS_MAIN(tst_generatedOutput)
#include "tst_generatedoutput.moc"