diff options
author | Topi Reinio <topi.reinio@qt.io> | 2022-05-25 21:59:06 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-06-13 09:52:47 +0000 |
commit | aa20eefca427123e591ff05af452b3c0c4805589 (patch) | |
tree | c0039111574911426808e9606907eec36f682272 | |
parent | 7b52506eb739536867655692cc247fa9ac45cef7 (diff) |
qdoc: Automatically resolve read-only attribute for QML properties
QDoc had code for automatically resolving the writability of a QML
property for properties that have an associated C++ property
declaration. However, this code path was never executed as it was
behind a conditional statement that always resolved to false.
Enable the automatic resolution - note that in Qt, many QML types
are nowadays implemented so that the C++ type is exposed to QML
via a private class that modify/extend the public type listed in
the documentation using the \instantiates command. Relations
of these private implementations to QML types are not possible
for QDoc to resolve; therefore this feature does not produce
reliable results for all existing properties.
To address this, turn the previous documentation warnings into a
debug message; these can be used to find the properties for which
auto-resolution fails; the \readonly command can be then inserted
manually as needed, or the public \instantiates C++ type declaration
can be amended with a QDOC_PROPERTY() macro.
Fixes: QTBUG-103828
Change-Id: I41ff613650668aef336394582ccc6f2b860fe8e1
Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io>
(cherry picked from commit 4be3d11129af9e26cd52b4a0b0c55c97f9a7b896)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
8 files changed, 92 insertions, 31 deletions
diff --git a/src/qdoc/qmlpropertynode.cpp b/src/qdoc/qmlpropertynode.cpp index 681b878b3..39e35512b 100644 --- a/src/qdoc/qmlpropertynode.cpp +++ b/src/qdoc/qmlpropertynode.cpp @@ -33,6 +33,7 @@ #include <utility> #include "qdocdatabase.h" +#include "utilities.h" QT_BEGIN_NAMESPACE @@ -53,15 +54,14 @@ QmlPropertyNode::QmlPropertyNode(Aggregate *parent, const QString &name, QString /*! Returns \c true if a QML property or attached property is - not read-only. The algorithm for figuring this out is long - amd tedious and almost certainly will break. It currently - doesn't work for the qmlproperty: + not read-only. If the read-only status is not set explicitly + using the \\readonly command, QDoc attempts to resolve it + from the associated C++ class instantiated by the QML type + that this property belongs to. - \code - bool PropertyChanges::explicit, - \endcode - - ...because the tokenizer gets confused on \e{explicit}. + \note Depending on how the QML type is implemented, this + information may not be available to QDoc. If so, add a debug + line but do not treat it as a warning. */ bool QmlPropertyNode::isWritable() { @@ -69,26 +69,18 @@ bool QmlPropertyNode::isWritable() return !fromFlagValue(readOnly_, false); QmlTypeNode *qcn = qmlTypeNode(); - if (qcn) { - if (qcn->cppClassRequired()) { - if (qcn->classNode()) { - PropertyNode *pn = findCorrespondingCppProperty(); - if (pn) - return pn->isWritable(); - else - defLocation().warning( - QStringLiteral( - "No Q_PROPERTY for QML property %1::%2::%3 " - "in C++ class documented as QML type: " - "(property not found in the C++ class or its base classes)") - .arg(logicalModuleName(), qmlTypeName(), name())); - } else - defLocation().warning(QStringLiteral("No Q_PROPERTY for QML property %1::%2::%3 " - "in C++ class documented as QML type: " - "(C++ class not specified or not found).") - .arg(logicalModuleName(), qmlTypeName(), name())); - } - } + if (qcn && qcn->classNode()) { + PropertyNode *pn = findCorrespondingCppProperty(); + if (pn) + return pn->isWritable(); + else + qCDebug(lcQdoc).nospace() + << qPrintable(defLocation().toString()) + << ": Automatic resolution of QML property attributes failed for " + << name() + << " (Q_PROPERTY not found in the C++ class hierarchy known to QDoc. " + << "Likely, the type is replaced with a private implementation.)"; +} return true; } diff --git a/src/qdoc/qmltypenode.h b/src/qdoc/qmltypenode.h index 612564dc4..60d34e35e 100644 --- a/src/qdoc/qmltypenode.h +++ b/src/qdoc/qmltypenode.h @@ -73,7 +73,6 @@ public: void setQmlBaseName(const QString &name) { m_qmlBaseName = name; } [[nodiscard]] QmlTypeNode *qmlBaseNode() const override { return m_qmlBaseNode; } void resolveInheritance(NodeMap &previousSearches); - [[nodiscard]] bool cppClassRequired() const { return m_classNodeRequired; } static void addInheritedBy(const Node *base, Node *sub); static void subclasses(const Node *base, NodeList &subs); static void terminate(); @@ -84,7 +83,6 @@ public: private: bool m_abstract { false }; - bool m_classNodeRequired { false }; bool m_wrapper { false }; ClassNode *m_classNode { nullptr }; QString m_qmlBaseName {}; diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml b/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml index 260426726..22b176815 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml @@ -30,6 +30,18 @@ </db:listitem> </db:varlistentry> <db:varlistentry> +<db:term>Inherited By</db:term> +<db:listitem> +<db:para/> +</db:listitem> +</db:varlistentry> +<db:varlistentry> +<db:term>Instantiated By</db:term> +<db:listitem> +<db:para>qml-thetype.xml</db:para> +</db:listitem> +</db:varlistentry> +<db:varlistentry> <db:term>Inherits</db:term> <db:listitem> <db:para><db:link xlink:href="testqdoc-test.xml" xlink:role="class">TestQDoc::Test</db:link></db:para> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/qml-thetype.html b/tests/auto/qdoc/generatedoutput/expected_output/properties/qml-thetype.html new file mode 100644 index 000000000..f518fe2bb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/qml-thetype.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> +<!-- properties.qdoc --> + <title>TheType QML Type | TestCPP</title> +</head> +<body> +<li>TheType</li> +<div class="sidebar"> +<div class="toc"> +<h3 id="toc">Contents</h3> +<ul> +<li class="level1"><a href="#properties">Properties</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">TheType QML Type</h1> +<div class="table"><table class="alignedsummary"> +<tr><td class="memItemLeft rightAlign topAlign"> Instantiates:</td><td class="memItemRight bottomAlign"> <a href="testqdoc-testderived.html">TestDerived</a></td></tr></table></div><ul> +<li><a href="qml-thetype-members.html">List of all members, including inherited members</a></li> +</ul> +<h2 id="properties">Properties</h2> +<ul> +<li class="fn"><b><a href="qml-thetype.html#name-prop">name</a></b> : string</li> +</ul> +<!-- $$$TheType-description --> +<h2 id="details">Detailed Description</h2> +<!-- @@@TheType --> +<h2>Property Documentation</h2> +<!-- $$$name --> +<div class="qmlitem"><div class="qmlproto"> +<div class="table"><table class="qmlname"> +<tr valign="top" class="odd" id="name-prop"> +<td class="tblQmlPropNode"><p> +<span class="qmlextra">[read-only] </span><span class="name">name</span> : <span class="type">string</span></p></td></tr> +</table></div></div> +<div class="qmldoc"><p>Read-only status of this property is resolved from Q_PROPERTY.</p> +</div></div><!-- @@@name --> +<br/> +</body> +</html> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index b/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index index 4a6de7b7d..8b1afc762 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index @@ -103,10 +103,14 @@ </property> </class> </namespace> + <qmlclass name="TheType" qml-module-name="TheType" href="qml-thetype.html" status="active" access="public" location="properties.qdoc" documented="true" title="TheType" fulltitle="TheType" subtitle=""> + <qmlproperty name="name" fullname="TheType::name" href="qml-thetype.html#name-prop" status="active" access="public" location="properties.qdoc" documented="true" type="string" attached="false" writable="false" brief="Read-only status of this property is resolved from Q_PROPERTY"/> + </qmlclass> <group name="testgroup" href="testgroup.html" status="internal" seen="false" title=""/> <module name="TestCPP" href="testcpp-module.html" status="active" documented="true" seen="true" title="QDoc Test C++ Classes" brief="A test module page"> <contents name="linking-to-function-like-things" title="Linking to function-like things" level="1"/> <contents name="section" title="section()" level="2"/> </module> + <qmlmodule name="TheModule" qml-module-name="TheModule" href="themodule-qmlmodule.html" status="internal" seen="false" title=""/> </namespace> </INDEX> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html index 52997f234..689465a13 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html @@ -30,7 +30,7 @@ <div class="table"><table class="alignedsummary"> <tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <span class="preprocessor">#include <TestDerived></span> </td></tr><tr><td class="memItemLeft rightAlign topAlign"> CMake:</td><td class="memItemRight bottomAlign"> find_package(Qt6 REQUIRED COMPONENTS QDocTest) <br/> -target_link_libraries(mytarget PRIVATE Qt6::QDocTest)</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Inherits:</td><td class="memItemRight bottomAlign"> <a href="testqdoc-test.html">TestQDoc::Test</a></td></tr></table></div> +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)</td></tr><tr><td class="memItemLeft rightAlign topAlign"> qmake:</td><td class="memItemRight bottomAlign"> QT += testcpp</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Instantiated By:</td><td class="memItemRight bottomAlign"> <a href="qml-thetype.html">TheType</a></td></tr><tr><td class="memItemLeft rightAlign topAlign"> Inherits:</td><td class="memItemRight bottomAlign"> <a href="testqdoc-test.html">TestQDoc::Test</a></td></tr></table></div> <ul> <li><a href="testqdoc-testderived-members.html">List of all members, including inherited members</a></li> <li><a href="testqdoc-testderived-obsolete.html">Deprecated members</a></li> diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc b/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc index 0ef6f4ea7..b097c03f5 100644 --- a/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc @@ -57,6 +57,17 @@ */ /*! + \qmltype TheType + \instantiates TestQDoc::TestDerived + \inqmlmodule TheModule +*/ + +/*! + \qmlproperty string TheType::name + \brief Read-only status of this property is resolved from Q_PROPERTY. +*/ + +/*! //! avoid link warnings for auto-generated links to QProperty \externalpage https://wiki.qt.io/QProperty \title QProperty diff --git a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp index c53c10acc..5fa03f486 100644 --- a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp +++ b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp @@ -529,6 +529,7 @@ void tst_generatedOutput::properties() testAndCompare("testdata/configs/properties.qdocconf", "properties/testqdoc-testderived.html " "properties/testqdoc-testderived-members.html " + "properties/qml-thetype.html " "properties/testcpp.index " "properties-docbook/testqdoc-testderived.xml", m_extraParams.toLatin1().data()); |