summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Di Sera <luca.disera@qt.io>2022-12-27 14:12:32 +0100
committerLuca Di Sera <luca.disera@qt.io>2022-12-28 11:02:05 +0100
commitfeb4a767b2728f706996217fd90efc54b2c3b2f1 (patch)
tree48436ea58a7b68add5030da70b81b6e943e93ec5
parent6b5ffb7e139c03778479a15e73e02133fa2790aa (diff)
QDoc: Tag C++ elements as "constexpr" when they are marked as such
C++'s allows certain declarations to be marked by the `constexpr` specifier, so as to signify that the element can be used in constant expressions contexts. 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 "constexpr" 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 "constexpr" or not, QDoc will now "tag" a relevant documentable element that is a callable, such as a C++ method, as "constexpr" when the `constexpr` specifier appears in its declaration. To store this information, `FunctionNode`, the internal representation for "callable" documentable elements, such as a C++ constructor or method, was modified to expose a boolean flag, `m_constexpr`, trough the a setter, `markConstexpr`, which enables the flag, and a getter, `isConstexpr`, which allows to peek into the flag value. The flag is initially defaulted to `false` and is set only when the "constexpr" specifier is encountered in the declaration of the relevant element. 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. As Libclang does not have direct support for the `constexpr` specifier, at the current point in time, we extract the information based on the tokenized version of the relevant declaration. That is, the source code represented by the relevant `CXCursor`, which will generally represent a declaration, is tokenized by Clang, all keywords tokens that are part of the declaration are inspected and, if a "constexpr" keyword is encountered, we consider the given declaration to be marked "constexpr". To do so, we reuse the infrastructure that was introduced in a recent commit to preserve the information for `explicit` specifiers. The static function `get_specifiers` in "clangcodeparser.cpp", performs the above process, and is now modified to take into account the `constexpr` specifier. The function returns a structure, `CXXSpecifiers`, that contains some minimum information with regards to the specifiers that we are interested into that Libclang does not directly support. The structure is now updated to provide information about the presence, or lack thereof, of a `constexpr` specifier. Similarly, the body of `get_specifiers` was modified to correctly populate this information based on the available tokens. `ClangCodeParser::processFunction`, which calls `get_specifiers`, was modified to take into account the new "constexpr" information in the returned `CXXSpecifiers` value, marking the processed `FunctionNode` as "constexpr" if a `constexpr` specifier was encountered. 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 "constexpr" 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 "constexpr" flag of a `FunctionNode`, and generate an "constexpr" "tag" if it is set to `true`. 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 "constexpr" 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 "constexpr" attribute in the XML-element representing the `FunctionNode`. The attribute is elided when the `FunctionNode` is not marked as "constexpr", the default state, to save space and avoid cluttering the output. 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 "constexpr" attribute that was added. If the attribute is present and has a "true" value in a "function" element, the reconstructed `FunctionNode` will be marked as "constexpr", to retain the information. Task-number: QTBUG-93439 Pick-to: 6.5 Change-Id: I63b18c34d7b9f3d72047ab2ba823d105f5a694e7 Reviewed-by: Luca Di Sera <luca.disera@qt.io>
-rw-r--r--src/qdoc/clangcodeparser.cpp4
-rw-r--r--src/qdoc/codemarker.cpp1
-rw-r--r--src/qdoc/functionnode.cpp2
-rw-r--r--src/qdoc/functionnode.h4
-rw-r--r--src/qdoc/qdocindexfiles.cpp4
5 files changed, 15 insertions, 0 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index d5acfd1cd..0d27e2f3f 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -898,6 +898,7 @@ void ClangVisitor::readParameterNamesAndAttributes(FunctionNode *fn, CXCursor cu
struct CXXSpecifiers {
bool is_explicit = false;
+ bool is_constexpr = false;
};
static CXXSpecifiers get_specifiers(CXCursor cursor) {
@@ -913,7 +914,9 @@ static CXXSpecifiers get_specifiers(CXCursor cursor) {
for (unsigned index = 0; index < token_count; ++index) {
if (clang_getTokenKind(tokens[index]) == CXToken_Keyword) {
QString token_spelling{fromCXString(clang_getTokenSpelling(tu, tokens[index]))};
+
if (token_spelling == "explicit") specifiers.is_explicit = true;
+ else if (token_spelling == "constexpr") specifiers.is_constexpr = true;
}
}
@@ -948,6 +951,7 @@ void ClangVisitor::processFunction(FunctionNode *fn, CXCursor cursor)
CXXSpecifiers specifiers{get_specifiers(cursor)};
if (specifiers.is_explicit) fn->markExplicit();
+ if (specifiers.is_constexpr) fn->markConstexpr();
CXRefQualifierKind refQualKind = clang_Type_getCXXRefQualifier(funcType);
if (refQualKind == CXRefQualifier_LValue)
diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp
index 1ab0df106..55885daf6 100644
--- a/src/qdoc/codemarker.cpp
+++ b/src/qdoc/codemarker.cpp
@@ -150,6 +150,7 @@ QString CodeMarker::extraSynopsis(const Node *node, Section::Style style)
}
if (func->isExplicit()) extra << "explicit";
+ if (func->isConstexpr()) extra << "constexpr";
if (func->access() == Access::Protected)
extra << "protected";
diff --git a/src/qdoc/functionnode.cpp b/src/qdoc/functionnode.cpp
index 4f29b7e9d..90cc73ec6 100644
--- a/src/qdoc/functionnode.cpp
+++ b/src/qdoc/functionnode.cpp
@@ -61,6 +61,7 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString &name)
m_isRefRef(false),
m_isInvokable(false),
m_explicit{false},
+ m_constexpr{false},
m_metaness(Plain),
m_virtualness(NonVirtual),
m_overloadNumber(0),
@@ -93,6 +94,7 @@ FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString &name
m_isRefRef(false),
m_isInvokable(false),
m_explicit{false},
+ m_constexpr{false},
m_metaness(kind),
m_virtualness(NonVirtual),
m_overloadNumber(0),
diff --git a/src/qdoc/functionnode.h b/src/qdoc/functionnode.h
index 93dbab99e..ec790b454 100644
--- a/src/qdoc/functionnode.h
+++ b/src/qdoc/functionnode.h
@@ -78,6 +78,9 @@ public:
void markExplicit() { m_explicit = true; }
bool isExplicit() const { return m_explicit; }
+ void markConstexpr() { m_constexpr = true; }
+ bool isConstexpr() const { return m_constexpr; }
+
[[nodiscard]] bool isCppFunction() const { return m_metaness == Plain; } // Is this correct?
[[nodiscard]] bool isSignal() const { return (m_metaness == Signal); }
[[nodiscard]] bool isSlot() const { return (m_metaness == Slot); }
@@ -182,6 +185,7 @@ private:
bool m_isRefRef : 1;
bool m_isInvokable : 1;
bool m_explicit;
+ bool m_constexpr;
Metaness m_metaness {};
Virtualness m_virtualness {};
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index e40e9b41f..d8e6cf794 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -427,6 +427,9 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader &reader, Node *current,
if (attributes.value(QLatin1String("explicit")) == QLatin1String("true"))
fn->markExplicit();
+ if (attributes.value(QLatin1String("constexpr")) == QLatin1String("true"))
+ fn->markConstexpr();
+
qsizetype refness = attributes.value(QLatin1String("refness")).toUInt();
if (refness == 1)
fn->setRef(true);
@@ -1201,6 +1204,7 @@ void QDocIndexFiles::generateFunctionSection(QXmlStreamWriter &writer, FunctionN
writer.writeAttribute("override", fn->isOverride() ? "true" : "false");
if (fn->isExplicit()) writer.writeAttribute("explicit", "true");
+ if (fn->isConstexpr()) writer.writeAttribute("constexpr", "true");
/*
This ensures that for functions that have overloads,