diff options
author | Luca Di Sera <luca.disera@qt.io> | 2023-01-12 11:45:22 +0100 |
---|---|---|
committer | Luca Di Sera <luca.disera@qt.io> | 2023-01-25 20:38:46 +0100 |
commit | 0ce9d75602550c9b2d9413d446375f038a71ccb1 (patch) | |
tree | 5693dcd56910d5737fc1ce860556042268c50177 /tests/auto/qdoc/generatedoutput/expected_output/docbook | |
parent | 2b64bb59c4964282aae039e6267e13889e735d85 (diff) | |
download | qttools-0ce9d75602550c9b2d9413d446375f038a71ccb1.tar.gz |
QDoc: Tag C++ elements as "noexcept" when they are marked as such
C++'s allows certain declarations to be marked by
the `noexcept` specifier, so as to signify that the element will not
throw any exception.
A `noexcept` specifier might be unconditional, such the the relevant
element is always to be considered "noexcept", or conditional, such that
the element is or is not "noexcept" based on the evaluation of a
compile-time, user-defined expression.
This information is important to the user of an API, as it may dictate
when and how they can use a certain element.
Nonetheless, up to now, QDoc would not treat the "noexcept" specifier,
such that this information was lost between source-code and
documentation.
To avoid the issue and ensure that users are given a way to discern
whether something is marked "noexcept" or not, QDoc will now "tag" a
relevant documentable element that is a callable, such as a C++ method,
as "noexcept" when the `noexcept` specifier appears in its
declaration or the element is implicitly noexcept (e.g destructors).
To store this information, `FunctionNode`, the internal representation
for "callable" documentable elements, such as a C++ constructor or
method, was modified to expose an optional string, `m_noexcept`, trough
the setter, `markNoexcept` and the getter, `getNoexcept`.
`markNoexcept` allows the element as being "noexcept". Optionally a
string can be provided which represents the expression of a conditional
"noexcept".
`getNoexcept` returns an optional value. If the value is Nothing, the
element is to not be considered "noexcept".
If the value is Just, it will contain a string that represents the
condition under which the element is "noexcept".
An empty string is to be considered marking a non-conditional
"noexcept".
Generally, this kind of information is extracted from the codebase in
`ClangCodeParser::processFunction`, where an instance of a
`FunctionNode` is populated based on the Libclang-provided `CXCursor`
that generated it.
LibClang has only partial support for the `noexcept` specifier. It
allows the extraction of a `CXCursor_ExceptionSpecificationKind`, which
provides information about the present or not of a `noexcept` specifier,
but it doesn't provide a direct way to extract the
expression of a conditional `noexcept` specifier.
The expression of a conditioanl `noexcept` specifiers should generally
be, in some way, presented to the user, as the user would not otherwise
be able to ascertain whether an element is "noexcept" or not in its use
case, thus requiring us to extract it in some way.
For similar issues, we have generally taken to tokenizing the source
code to manually extract the required information.
For the specific case of a `noexcept` specifier, we consider this
unfeasible due to grammar of of the C++ language.
In a function signature, in particular due to the existence of the
`noexcept` operator, an operator that returns whether an expression is
"noexcept" or not, the `noexcept` keyword can appear many times, in many
places with different meanings.
The extraction of the very specific `noexcept` specifier, and its
expression should it be conditional, is thus hindered so that it is not
easy to cover all possible cases without actually parsing the signature
itself.
To be able to find the information we are looking for, we drop down from
LibClang's to clang's C++ AST, which provides full support for this kind
of extraction.
To do so, a new function, `get_cursor_declaration`, is added to
"src/qdoc/clangcodeparser.cpp".
Each `CXCursor` in LibClang stores a reference to the C++ AST element
that generated it.
`get_cursor_declaration` extracts this information, for CXCursors that
represent a declaration, and returns the underlying C++ AST node, which
can be used to access the more thorough functionalities that the C++ AST
provides.
`ClangCodeParser::processFunction`, was modified to call
`get_cursor_declaration` for its processed elements.
From the retrieved declaration, the normal methods of the C++ AST are
used to extract information about the presence, or lack thereof, of a
`noexcept` specifier and its expression, should it be conditional.
This information is then stored into the processed `Node`, using the
newly introduced `markNoexcept`.
Later on, during the "Generation Phase", where QDoc destructures the
provided documentable elements to produce the final output
documentation, QDoc will call a `CodeMarker` to generate the set of
"tags", small strings that appear near the detailed documentation of an
element, to enhance the final documentation with certain information
about the documented element.
To make use of the now stored "noexcept" information,
`CodeMarker::extraSynopsis`, which is the particular methods that
generates the relevant set of "tags" for an element, was modified to
take into account the "noexcept" information of a `FunctionNode`.
If the `FunctionNode` is marked as "noexcept" a tag will be produced.
If the "noexcept" is not conditional, a "noexcept" tag is produced.
If the "noexcept" is conditional, a "noexcept(...)" tag is produced.
When this is the case, additional information will be generated for the
detailed documentation of the relevant element to provide more
information about the conditionality of the "noexcept".
That is, a not will be produced that contains the expression that the
"noexcept" is conditioned on.
To do so, a new method `generateNoexceptNote` was added to `Generator`,
the base class of the components that take care of producing the
effective output during a QDoc execution.
The method is implemented using the same pattern of similar procedures,
such as `Generator::generateSince`, where, starting from the processed
`Node`, a `Text`, an internal representation for certain formatted
output, instance is produced and delivered to `Generator::generateText`,
which takes care of producing the marked-up output documentation.
In particular, a note element containing the extracted conditional
expression and a small text about the lack of exceptions depending on
this expression is produced.
`HtmlGenerator`, the child class of `Generator` that specifically
generates the HTML formatted output documentation, was modified to call
the `Generator::generateSince` method when producing the detailed
documentation of an element.
The conditional expression for a `noexcept` specifier, while necessary
for the user to see, might not necessarily be legible without additional
context.
This context cannot generally be auto-generated and, thus, the specific
format in which we present this information is not to be considered
final and is expected to change in the near future.
When QDoc parses the source code for a project, it generates an
XML-based "index" file, containing certain information about the
extracted documentable elements that can be consumed by external tools
and is consumed by QDoc itself to enable cross-module linking.
To allow the newly added "noexcept" information to be retained between
modules and to enable the inspection of such information for external
consumers, `QDocIndexFiles::generateFunctionSection`, which writes the
relevant information about a `FunctionNode` in the index file, was
modified to write a "noexcept" attribute in the XML-element
representing the `FunctionNode`.
The attribute is elided when the `FunctionNode` is not marked as
"noexcept", the default state, to save space and avoid cluttering the
output.
If the "noexcept" is conditional, a further attribute,
"noexcept_expression" is written, containing the extracted conditional
expression of the "noexcept".
Similarly, `QDocIndexFiles::readIndexSection`, which retrieves the
information stored in a certain index file and rebuilds the internal
representations that QDoc uses for the represented elements, was
modified to read the "noexcept" and "noexcept_expression" attributes that
were added.
If the "noexcept" attribute is present and has a "true" value in a "function"
element, the reconstructed `FunctionNode` will be marked as "noexcept",
to retain the information.
If the "noexcept_expression" attribute is present, the `FunctionNode`
will further contain a copy of the conditional expression in string form.
The regression files for `tst_generatedOutput` were regenerated to take
into account the addition of the new tag.
Fixes: QTBUG-93439
Change-Id: Ic6e15c53309db6c4f398c15670fe3f15886bca3e
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io>
Diffstat (limited to 'tests/auto/qdoc/generatedoutput/expected_output/docbook')
-rw-r--r-- | tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml | 4 |
1 files changed, 2 insertions, 2 deletions
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 9186b87a1..06b8f5816 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml @@ -74,7 +74,7 @@ <db:para>Overloads that share a documentation comment, optionally taking a parameter <db:code role="parameter">b</db:code>.</db:para> </db:section> <db:section xml:id="Test"> -<db:title>[default] Test::Test()</db:title> +<db:title>[noexcept default] Test::Test()</db:title> <db:constructorsynopsis> <db:methodname>Test</db:methodname> <db:void/> @@ -236,7 +236,7 @@ <db:para>Function that must be reimplemented.</db:para> </db:section> <db:section xml:id="operator-eq"> -<db:title>[default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&<db:emphasis>other</db:emphasis>)</db:title> +<db:title>[noexcept default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&<db:emphasis>other</db:emphasis>)</db:title> <db:methodsynopsis> <db:type>TestQDoc::Test &</db:type> <db:methodname>operator=</db:methodname> |