summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Di Sera <luca.disera@qt.io>2023-12-22 15:27:06 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-12-29 19:42:02 +0000
commitc0c5fa0a33055ee17c5146558bbe6a97639ce029 (patch)
treea1eb2fe59df179e4d2ebbce9f16b3edf1b2969a9
parent45f1d7eea495ae89e18792b3af5580c1743b8116 (diff)
QDoc: Allow brace enclosed arguments in compareswith
QDoc allows documenting the ordering relationship between a type and one or more other types through the use of the "\compareswith"/"\endcompareswith" command pair. "\compareswith" takes one word to use as the comparison category, such as "strong", and then a space separated list of words that are used to specify the compared with types. Due to the list being space separated, it is impossible to correctly provide to the command a type that contains a space in its name. For example, "unsigned long" would be always be treated as the two types "unsigned" and "long". To avoid the issue, the command now interprets brace-enclosed elements as a single type, similar to how other commands in QDoc work. For example, "{unsigned long}" will now be treated as the single type "unsigned long". To allow for this, "processComparesWithCommand", which takes care of parsing the arguments passed to a "\compareswith" command, in "docparser.cpp", was modified to parse the arguments so that brace-enclosed arguments are treated accordingly ot the new specification. While QDoc already has certain procedures to parse a similar structure, such as `DocParser::getBracedArgument`, they are coupled to the state of the parser and are unusable in a more general situation. In particular, due to certain structural limits and the current implementation of the "\compareswith" command, especially its two phase parsing to handle continued lines, the available procedures are unusable without multiple structural changes. Hence, an inline parser that approximates the usual braced behavior, with some simplifications, was implemented directly in "processComparesWithCommand". After the command is processed and the a list of types is extracted, the list is stored back as a string that is later extracted and used during the generation of the output documentation set. Previously, the list of types was joined as a space separated string, later reconstructed during the generation by splitting on spaces. This makes it so the original collection of words in a braced argument that has spaces in it is lost in the translation. To avoid this, the current behavior is kept but the list is encoded as a semi-colon separated string and restored by splitting on semi-colons, so that meaningful spaces are preserved. The semi-colon character was chosen arbitrarily and has no particular meaning. The documentation for the "\compareswith" command was updated to reflect the new behavior. A simple specimen of brace-enclosed argument was added to "generatedoutput", QDoc's end-to-end regression testing suite, under the relevant tests for "\compareswith". The regression files for "generatedoutput" were regenerated to respect the changes in the regression sources. Fixes: QTBUG-120265 Change-Id: I6872d396ae05b831478d79e66bf426f9fb353b69 Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io> (cherry picked from commit e66b37641bee97d0e52931ee73d1ba9ac609a7d0) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc19
-rw-r--r--src/qdoc/qdoc/src/qdoc/docparser.cpp78
-rw-r--r--src/qdoc/qdoc/src/qdoc/generator.cpp2
-rw-r--r--src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.html2
-rw-r--r--src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.xml2
-rw-r--r--src/qdoc/qdoc/tests/generatedoutput/testdata/cxx20/classes_with_various_ordering.cpp2
6 files changed, 99 insertions, 6 deletions
diff --git a/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc b/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
index 7745129f9..49de3e0c4 100644
--- a/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
+++ b/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
@@ -214,6 +214,25 @@
considered further details that apply to all types subject
to the comparison category argument.
+ Types that have one or more space in their name, such as
+ \c{unsigned long}, should be enclosed in braces.
+
+ For example:
+
+ \badcode *
+ /\1!
+ ...
+ \compareswith strong int long {unsigned long} {unsigned int} char
+ ...
+ \endcompareswith
+ ...
+ \1/
+ \endcode
+
+ Argument enclosed in braces have their leading and trailing whitespaces
+ removed.
+ For example, \c{unsigned long} and \c{ unsigned long } are equivalent.
+
The comparison category argument must be one of the following:
\include qdoc-manual-contextcmds.qdoc comparison-categories
diff --git a/src/qdoc/qdoc/src/qdoc/docparser.cpp b/src/qdoc/qdoc/src/qdoc/docparser.cpp
index c790da8db..5ef93e8cb 100644
--- a/src/qdoc/qdoc/src/qdoc/docparser.cpp
+++ b/src/qdoc/qdoc/src/qdoc/docparser.cpp
@@ -2732,10 +2732,84 @@ bool DocParser::isQuote(const Atom *atom)
*/
static void processComparesWithCommand(DocPrivate *priv, const Location &location)
{
+ static auto take_while = [](QStringView input, auto predicate) {
+ QStringView::size_type end{0};
+
+ while (end < input.size() && std::invoke(predicate, input[end]))
+ ++end;
+
+ return std::make_tuple(input.sliced(0, end), input.sliced(end));
+ };
+
+ static auto peek = [](QStringView input, QChar c) {
+ return !input.empty() && input.first() == c;
+ };
+
+ static auto skip_one = [](QStringView input) {
+ if (input.empty()) return std::make_tuple(QStringView{}, input);
+ else return std::make_tuple(input.sliced(0, 1), input.sliced(1));
+ };
+
+ static auto enclosed = [](QStringView input, QChar open, QChar close) {
+ if (!peek(input, open)) return std::make_tuple(QStringView{}, input);
+
+ auto [opened, without_open] = skip_one(input);
+ auto [parsed, remaining] = take_while(without_open, [close](QChar c){ return c != close; });
+
+ if (remaining.empty()) return std::make_tuple(QStringView{}, input);
+
+ auto [closed, without_close] = skip_one(remaining);
+
+ return std::make_tuple(parsed.trimmed(), without_close);
+ };
+
+ static auto one_of = [](auto first, auto second) {
+ return [first, second](QStringView input) {
+ auto [parsed, remaining] = std::invoke(first, input);
+
+ if (parsed.empty()) return std::invoke(second, input);
+ else return std::make_tuple(parsed, remaining);
+ };
+ };
+
+ static auto collect = [](QStringView input, auto parser) {
+ QStringList collected{};
+
+ while (true) {
+ auto [parsed, remaining] = std::invoke(parser, input);
+
+ if (parsed.empty()) break;
+ collected.append(parsed.toString());
+
+ input = remaining;
+ };
+
+ return collected;
+ };
+
+ static auto spaces = [](QStringView input) {
+ return take_while(input, [](QChar c){ return c.isSpace(); });
+ };
+
+ static auto word = [](QStringView input) {
+ return take_while(input, [](QChar c){ return !c.isSpace(); });
+ };
+
+ static auto parse_argument = [](QStringView input) {
+ auto [_, without_spaces] = spaces(input);
+
+ return one_of(
+ [](QStringView input){ return enclosed(input, '{', '}'); },
+ word
+ )(without_spaces);
+ };
+
const QString cmd{DocParser::cmdName(CMD_COMPARESWITH)};
Text text = priv->m_text.splitAtFirst(Atom::ComparesLeft);
+
auto *atom = text.firstAtom();
- QStringList segments{atom->string().split(QLatin1Char(' '), Qt::SkipEmptyParts)};
+ QStringList segments = collect(atom->string(), parse_argument);
+
QString categoryString;
if (!segments.isEmpty())
categoryString = segments.takeFirst();
@@ -2755,7 +2829,7 @@ static void processComparesWithCommand(DocPrivate *priv, const Location &locatio
// Store cleaned-up type names back into the atom
segments.removeDuplicates();
- atom->setString(segments.join(QLatin1Char(' ')));
+ atom->setString(segments.join(QLatin1Char(';')));
// Add an entry to meta-command map for error handling in CppCodeParser
priv->m_metaCommandMap[cmd].append(ArgPair(categoryString, atom->string()));
diff --git a/src/qdoc/qdoc/src/qdoc/generator.cpp b/src/qdoc/qdoc/src/qdoc/generator.cpp
index a14cf6886..5440bb467 100644
--- a/src/qdoc/qdoc/src/qdoc/generator.cpp
+++ b/src/qdoc/qdoc/src/qdoc/generator.cpp
@@ -1533,7 +1533,7 @@ bool Generator::generateComparisonList(const Node *node)
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
<< " with "_L1;
- const QStringList types{description.firstAtom()->string().split(' '_L1)};
+ const QStringList types{description.firstAtom()->string().split(';'_L1)};
for (const auto &name : types)
relationshipText << Atom(Atom::AutoLink, name)
<< Utilities::separator(types.indexOf(name), types.size());
diff --git a/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.html b/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.html
index 42fe0a9d9..a92815465 100644
--- a/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.html
+++ b/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.html
@@ -19,7 +19,7 @@
<div class="table"><table class="alignedsummary" translate="no">
<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include &lt;ComparesStronglyWithThreeClasses&gt;</span></td></tr>
</table></div>
-<p>This class is <b>strongly comparable</b> with <a href="foo.html" translate="no">Foo</a>, <a href="bar.html" translate="no">Bar</a>, and <a href="baz.html" translate="no">Baz</a>.</p>
+<p>This class is <b>strongly comparable</b> with <a href="foo.html" translate="no">Foo</a>, Bar Bar Jinks, and <a href="baz.html" translate="no">Baz</a>.</p>
<!-- $$$ComparesStronglyWithThreeClasses-description -->
<div class="descr">
<h2 id="details">Detailed Description</h2>
diff --git a/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.xml b/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.xml
index ddca0d5ad..8c39c4fa7 100644
--- a/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.xml
+++ b/src/qdoc/qdoc/tests/generatedoutput/expected_output/cxx20/comparesstronglywiththreeclasses.xml
@@ -5,7 +5,7 @@
<db:productname>cxx20</db:productname>
<db:titleabbrev>cxx20 Reference Documentation</db:titleabbrev>
<db:abstract>
-<db:para>This class is <db:emphasis role="bold">strongly comparable</db:emphasis> with <db:link xlink:href="foo.xml">Foo</db:link>, <db:link xlink:href="bar.xml">Bar</db:link>, and <db:link xlink:href="baz.xml">Baz</db:link>.</db:para>
+<db:para>This class is <db:emphasis role="bold">strongly comparable</db:emphasis> with <db:link xlink:href="foo.xml">Foo</db:link>, Bar Bar Jinks, and <db:link xlink:href="baz.xml">Baz</db:link>.</db:para>
</db:abstract>
</db:info>
<db:variablelist>
diff --git a/src/qdoc/qdoc/tests/generatedoutput/testdata/cxx20/classes_with_various_ordering.cpp b/src/qdoc/qdoc/tests/generatedoutput/testdata/cxx20/classes_with_various_ordering.cpp
index 9fe053ee6..814fe04a5 100644
--- a/src/qdoc/qdoc/tests/generatedoutput/testdata/cxx20/classes_with_various_ordering.cpp
+++ b/src/qdoc/qdoc/tests/generatedoutput/testdata/cxx20/classes_with_various_ordering.cpp
@@ -41,7 +41,7 @@
\class ComparesStronglyWithThreeClasses
\inmodule TestQDoc
- \compareswith strong Foo Bar Baz
+ \compareswith strong Foo {Bar Bar Jinks} Baz
\endcompareswith
*/