summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTopi Reinio <topi.reinio@qt.io>2024-03-08 13:50:56 +0000
committerTopi Reinio <topi.reinio@qt.io>2024-03-21 13:03:57 +0000
commitdd934e4663aa220d8546326c453de725ec976a22 (patch)
tree2b20ed9632db7253216d51cfa0cea670093f0eb9
parent5c3800b7ff94b36b2ca13fc23acfd9209ea4c50b (diff)
qdoc: Support auto-generated values in QML docs from C++ enums
C++ classes registered to QML expose also enums to QML, with values available under <RegisteredQmlName>.<value>. Add a new meta-command, \qmlenumeratorsfrom, to use in \qmlproperty documentation. This command is used for associating a documented C++ enum with a QML property. The command takes a fully qualified C++ enum as an argument. When set, the enum values and their descriptions are retrieved from C++ \enum documentation during generation of the QML property. Instead of the '<namespace>::' prefix that's used in C++ enum documentation, use '<RegisteredQmlName>.' as the prefix. By default, the prefix is the parent QML type name, but a custom prefix can be provided with the optional argument in brackets. The auto-generated value table is appended at the end of the documentation body. Because QDoc cannot extract documentation from source files outside the current project, restrict the search for the C++ enum to the primary tree only. Make Tree::findNodeByNameAndType() a public function to enable this. Fixes: QTBUG-92450 Change-Id: If51c6f392e5f20c12a37c585bfd7ef93f23baa15 Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r--src/qdoc/qdoc/doc/qdoc-manual-cmdindex.qdoc1
-rw-r--r--src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc45
-rw-r--r--src/qdoc/qdoc/src/qdoc/codeparser.h3
-rw-r--r--src/qdoc/qdoc/src/qdoc/cppcodemarker.cpp12
-rw-r--r--src/qdoc/qdoc/src/qdoc/cppcodeparser.cpp8
-rw-r--r--src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp12
-rw-r--r--src/qdoc/qdoc/src/qdoc/generator.cpp40
-rw-r--r--src/qdoc/qdoc/src/qdoc/generator.h1
-rw-r--r--src/qdoc/qdoc/src/qdoc/qmlpropertynode.cpp38
-rw-r--r--src/qdoc/qdoc/src/qdoc/qmlpropertynode.h4
-rw-r--r--src/qdoc/qdoc/src/qdoc/qmlvisitor.cpp10
-rw-r--r--src/qdoc/qdoc/src/qdoc/tree.h5
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.cpp36
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.h10
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/class.xml136
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/module-module.xml18
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qml-qmlmodule-type.xml103
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qmlmodule-qmlmodule.xml16
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class-members.html18
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class.html59
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/module-module.html28
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type-members.html18
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type.html62
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlenumvaluesfromcpp.index23
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlmodule-qmlmodule.html18
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/class.webxml54
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/module-module.webxml4
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlenumvaluesfromcpp.index23
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlmodule-qmlmodule.webxml4
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmlenumvaluesfromcpp.qdocconf22
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmltype.qdoc23
31 files changed, 848 insertions, 6 deletions
diff --git a/src/qdoc/qdoc/doc/qdoc-manual-cmdindex.qdoc b/src/qdoc/qdoc/doc/qdoc-manual-cmdindex.qdoc
index 58307e811..fcab7f316 100644
--- a/src/qdoc/qdoc/doc/qdoc-manual-cmdindex.qdoc
+++ b/src/qdoc/qdoc/doc/qdoc-manual-cmdindex.qdoc
@@ -89,6 +89,7 @@
\li \l {qmlvaluetype-command} {\\qmlvaluetype}
\li \l {qmlclass-command} {\\qmlclass} (deprecated, use \\qmltype)
\li \l {qmldefault-command} {\\qmldefault}
+ \li \qdoccmd qmlenumeratorsfrom
\li \l {qmltype-command} {\\qmltype}
\li \l {qmlmethod-command} {\\qmlmethod}
\li \l {qmlproperty-command} {\\qmlproperty}
diff --git a/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc b/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
index 6d9e13fb0..bc5e36532 100644
--- a/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
+++ b/src/qdoc/qdoc/doc/qdoc-manual-contextcmds.qdoc
@@ -41,6 +41,7 @@
\li \l {previouspage-command}{\\previouspage}
\li \l {qmlabstract-command} {\\qmlabstract}
\li \l {qmldefault-command} {\\qmldefault}
+ \li \qdoccmd qmlenumeratorsfrom (Since QDoc 6.8)
\li \l {qtcmakepackage-command} {\\qtcmakepackage}
\li \l {qtcmaketargetitem-command} {\\qtcmaketargetitem}
\li \l {readonly-command} {\\readonly}
@@ -275,6 +276,50 @@
See how QDoc renders this property on the reference page for the
\l {QtQuick::State::changes}{State} type.
+ \target qmlenumeratorsfrom-command
+ \section1 \\qmlenenumeratorsfrom
+
+ Use the \\qmlenumeratorsfrom command in a \qdoccmd qmlproperty topic
+ with a property type \e enumeration, to automatically replicate the
+ documentation for enumerators from a C++ \qdoccmd enum topic.
+
+ The command takes a fully qualified C++ enum as an argument,
+ and generates a list of enumerators and their descriptions.
+
+ \note The C++ enum must be documented in the same project; QDoc
+ cannot access its documentation if it's part of an external
+ documentation set that the current project \qdocvar depends
+ on.
+
+ By default, each enumerator is prefixed with the type name the
+ property belongs to, with \c{.} as the separator.
+
+ For example:
+
+ \badcode *
+ /\1!
+ \qmlproperty enumeration QtMultimedia::Camera::error
+ \qmlenumeratorsfrom QCamera::Error
+
+ //! Outputs documentation for 'Camera.NoError', 'Camera.CameraError'
+ \1/
+ \endcode
+
+ If the enumerators are registered to QML under a different type
+ name, this name (prefix) can be specified using the optional
+ argument in square brackets:
+
+ \badcode
+ \qmlenumeratorsfrom [Errors] QCamera::Error
+
+ //! Outputs documentation for 'Errors.NoError', 'Errors.CameraError'
+ \1/
+ \endcode
+
+ This command was introduced in QDoc 6.8.
+
+ See also \qdoccmd {qmlproperty}, \qdoccmd {enum}, and \qdoccmd {value}.
+
\target dontdocument-command
\section1 \\dontdocument
diff --git a/src/qdoc/qdoc/src/qdoc/codeparser.h b/src/qdoc/qdoc/src/qdoc/codeparser.h
index 2b86df399..6357b3a21 100644
--- a/src/qdoc/qdoc/src/qdoc/codeparser.h
+++ b/src/qdoc/qdoc/src/qdoc/codeparser.h
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
#define COMMAND_QMLVALUETYPE QLatin1String("qmlvaluetype")
#define COMMAND_QMLCLASS QLatin1String("qmlclass")
#define COMMAND_QMLDEFAULT QLatin1String("qmldefault")
+#define COMMAND_QMLENUMERATORSFROM QLatin1String("qmlenumeratorsfrom")
#define COMMAND_QMLINHERITS QLatin1String("inherits")
#define COMMAND_QMLINSTANTIATES QLatin1String("instantiates")
#define COMMAND_QMLMETHOD QLatin1String("qmlmethod")
@@ -104,7 +105,7 @@ public:
COMMAND_ABSTRACT, COMMAND_DEFAULT, COMMAND_DEPRECATED, COMMAND_INGROUP,
COMMAND_INMODULE, COMMAND_INPUBLICGROUP, COMMAND_INQMLMODULE, COMMAND_INTERNAL,
COMMAND_MODULESTATE, COMMAND_NOAUTOLIST, COMMAND_NONREENTRANT, COMMAND_OBSOLETE,
- COMMAND_PRELIMINARY, COMMAND_QMLABSTRACT, COMMAND_QMLDEFAULT, COMMAND_QMLINHERITS,
+ COMMAND_PRELIMINARY, COMMAND_QMLABSTRACT, COMMAND_QMLDEFAULT, COMMAND_QMLENUMERATORSFROM, COMMAND_QMLINHERITS,
COMMAND_QMLREADONLY, COMMAND_QMLREQUIRED, COMMAND_QTCMAKEPACKAGE, COMMAND_QTCMAKETARGETITEM,
COMMAND_QTVARIABLE, COMMAND_REENTRANT, COMMAND_SINCE, COMMAND_STARTPAGE, COMMAND_SUBTITLE,
COMMAND_THREADSAFE, COMMAND_TITLE, COMMAND_WRAPPER, COMMAND_ATTRIBUTION,
diff --git a/src/qdoc/qdoc/src/qdoc/cppcodemarker.cpp b/src/qdoc/qdoc/src/qdoc/cppcodemarker.cpp
index 97560a696..7fb26db0c 100644
--- a/src/qdoc/qdoc/src/qdoc/cppcodemarker.cpp
+++ b/src/qdoc/qdoc/src/qdoc/cppcodemarker.cpp
@@ -292,10 +292,18 @@ QString CppCodeMarker::markedUpName(const Node *node)
QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, const Node *relative)
{
- if (!relative->isEnumType())
+ const auto *node = relative->parent();
+
+ if (relative->isQmlProperty()) {
+ const auto *qpn = static_cast<const QmlPropertyNode*>(relative);
+ if (qpn->enumNode() && !enumValue.startsWith("%1."_L1.arg(qpn->enumPrefix())))
+ return "%1<@op>.</@op>%2"_L1.arg(qpn->enumPrefix(), enumValue);
+ }
+
+ if (!relative->isEnumType()) {
return enumValue;
+ }
- const Node *node = relative->parent();
QStringList parts;
while (!node->isHeader() && node->parent()) {
parts.prepend(markedUpName(node));
diff --git a/src/qdoc/qdoc/src/qdoc/cppcodeparser.cpp b/src/qdoc/qdoc/src/qdoc/cppcodeparser.cpp
index 371e403c8..14297c0fd 100644
--- a/src/qdoc/qdoc/src/qdoc/cppcodeparser.cpp
+++ b/src/qdoc/qdoc/src/qdoc/cppcodeparser.cpp
@@ -485,6 +485,14 @@ void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command,
}
} else if (command == COMMAND_QMLDEFAULT) {
node->markDefault();
+ } else if (command == COMMAND_QMLENUMERATORSFROM) {
+ if (!node->isQmlProperty()) {
+ doc.location().warning("Ignored '\\%1', applies only to '\\%2'"_L1
+ .arg(command, COMMAND_QMLPROPERTY));
+ } else if (!static_cast<QmlPropertyNode*>(node)->setEnumNode(argPair.first, argPair.second)) {
+ doc.location().warning("Failed to find C++ enumeration '%2' passed to \\%1"_L1
+ .arg(command, arg), "Use \\value commands instead"_L1);
+ }
} else if (command == COMMAND_QMLREADONLY) {
node->markReadOnly(true);
} else if (command == COMMAND_QMLREQUIRED) {
diff --git a/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp b/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
index 10bf00a36..9c8901cc6 100644
--- a/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
+++ b/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
@@ -2665,6 +2665,7 @@ void DocBookGenerator::generateBody(const Node *node)
// Warning generation skipped with respect to Generator::generateBody.
}
+ generateEnumValuesForQmlProperty(node, nullptr);
generateRequiredLinks(node);
}
@@ -3883,13 +3884,22 @@ void DocBookGenerator::generateEnumValue(const QString &enumValue, const Node *r
// From CppCodeMarker::markedUpEnumValue, simplifications from Generator::plainCode (removing
// <@op>). With respect to CppCodeMarker::markedUpEnumValue, the order of generation of parents
// must be reversed so that they are processed in the order
+ const auto *node = relative->parent();
+
+ if (relative->isQmlProperty()) {
+ const auto *qpn = static_cast<const QmlPropertyNode*>(relative);
+ if (qpn->enumNode() && !enumValue.startsWith("%1."_L1.arg(qpn->enumPrefix()))) {
+ m_writer->writeCharacters("%1.%2"_L1.arg(qpn->enumPrefix(), enumValue));
+ return;
+ }
+ }
+
if (!relative->isEnumType()) {
m_writer->writeCharacters(enumValue);
return;
}
QList<const Node *> parents;
- const Node *node = relative->parent();
while (!node->isHeader() && node->parent()) {
parents.prepend(node);
if (node->parent() == relative || node->parent()->name().isEmpty())
diff --git a/src/qdoc/qdoc/src/qdoc/generator.cpp b/src/qdoc/qdoc/src/qdoc/generator.cpp
index e9b2d5076..fa30e93c8 100644
--- a/src/qdoc/qdoc/src/qdoc/generator.cpp
+++ b/src/qdoc/qdoc/src/qdoc/generator.cpp
@@ -20,6 +20,7 @@
#include "propertynode.h"
#include "qdocdatabase.h"
#include "qmltypenode.h"
+#include "qmlpropertynode.h"
#include "quoter.h"
#include "sharedcommentnode.h"
#include "tokenizer.h"
@@ -792,6 +793,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
}
+ generateEnumValuesForQmlProperty(node, marker);
generateRequiredLinks(node, marker);
}
@@ -2030,6 +2032,44 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
}
}
+void Generator::generateEnumValuesForQmlProperty(const Node *node, CodeMarker *marker)
+{
+ if (!node->isQmlProperty())
+ return;
+
+ const auto *qpn = static_cast<const QmlPropertyNode*>(node);
+
+ if (!qpn->enumNode())
+ return;
+
+ auto findNext =
+ [](const Atom *atom, Atom::AtomType type, const QString &str) {
+ while (atom && (atom->type() != type || atom->string() != str))
+ atom = atom->next();
+ return atom;
+ };
+
+ // Retrieve atoms from C++ enum \value list
+ const auto body{qpn->enumNode()->doc().body()};
+ const auto *start{body.firstAtom()};
+ Text text;
+
+ while ((start = findNext(start, Atom::ListLeft, ATOM_LIST_VALUE))) {
+ const auto end = findNext(start, Atom::ListRight, ATOM_LIST_VALUE);
+ // Skip subsequent ListLeft atoms, collating multiple lists into one
+ text << body.subText(text.isEmpty() ? start : start->next(), end);
+ start = end;
+ }
+ if (text.isEmpty())
+ return;
+
+ text << Atom(Atom::ListRight, ATOM_LIST_VALUE);
+ if (marker)
+ generateText(text, qpn, marker);
+ else
+ generateText(text, qpn);
+}
+
void Generator::terminate()
{
for (const auto &generator : std::as_const(s_generators)) {
diff --git a/src/qdoc/qdoc/src/qdoc/generator.h b/src/qdoc/qdoc/src/qdoc/generator.h
index 46e11bafe..8f2b34039 100644
--- a/src/qdoc/qdoc/src/qdoc/generator.h
+++ b/src/qdoc/qdoc/src/qdoc/generator.h
@@ -108,6 +108,7 @@ protected:
QMap<QString, QString> &formattingRightMap();
const Atom *generateAtomList(const Atom *atom, const Node *relative, CodeMarker *marker,
bool generate, int &numGeneratedAtoms);
+ void generateEnumValuesForQmlProperty(const Node *node, CodeMarker *marker);
void generateRequiredLinks(const Node *node, CodeMarker *marker);
void generateLinkToExample(const ExampleNode *en, CodeMarker *marker,
const QString &exampleUrl);
diff --git a/src/qdoc/qdoc/src/qdoc/qmlpropertynode.cpp b/src/qdoc/qdoc/src/qdoc/qmlpropertynode.cpp
index a8aaf1257..335b7d870 100644
--- a/src/qdoc/qdoc/src/qdoc/qmlpropertynode.cpp
+++ b/src/qdoc/qdoc/src/qdoc/qmlpropertynode.cpp
@@ -5,6 +5,7 @@
#include "classnode.h"
#include "propertynode.h"
+#include "enumnode.h"
#include <utility>
#include "qdocdatabase.h"
@@ -35,6 +36,43 @@ QmlPropertyNode::QmlPropertyNode(Aggregate *parent, const QString &name, QString
*/
/*!
+ \fn const EnumNode *QmlPropertyNode::enumNode() const
+
+ Returns the node representing the C++ enumeration associated
+ with this property, or \nullptr.
+*/
+
+/*!
+ Returns the prefix to use for documentated enumerators from
+ the associated C++ enum for this property.
+*/
+const QString &QmlPropertyNode::enumPrefix() const
+{
+ return !m_enumNode.second.isEmpty() ?
+ m_enumNode.second : parent()->name();
+}
+
+/*!
+ Locates the node specified by \a path and sets it as the C++ enumeration
+ associated with this property.
+
+ \a registeredQmlName is used as the prefix in the generated enum value
+ documentation.
+
+ \note The target EnumNode is searched under the primary tree only.
+
+ Returns \c true on success.
+*/
+bool QmlPropertyNode::setEnumNode(const QString &path, const QString &registeredQmlName)
+{
+ m_enumNode.first = static_cast<EnumNode*>(
+ QDocDatabase::qdocDB()->primaryTree()->findNodeByNameAndType(path.split("::"), &Node::isEnumType)
+ );
+ m_enumNode.second = registeredQmlName;
+ return m_enumNode.first != nullptr;
+}
+
+/*!
Returns \c true if this QML property or attached property is
read-only. If the read-only status is not set explicitly
using the \\readonly command, QDoc attempts to resolve it
diff --git a/src/qdoc/qdoc/src/qdoc/qmlpropertynode.h b/src/qdoc/qdoc/src/qdoc/qmlpropertynode.h
index fec5ff89f..19d1c9485 100644
--- a/src/qdoc/qdoc/src/qdoc/qmlpropertynode.h
+++ b/src/qdoc/qdoc/src/qdoc/qmlpropertynode.h
@@ -21,6 +21,7 @@ public:
void setStored(bool stored) { m_stored = toFlagValue(stored); }
void setDefaultValue(const QString &value) { m_defaultValue = value; }
void setRequired() { m_required = toFlagValue(true); }
+ bool setEnumNode(const QString &path, const QString &registeredQmlName);
[[nodiscard]] const QString &dataType() const { return m_type; }
[[nodiscard]] const QString &defaultValue() const { return m_defaultValue; }
@@ -46,6 +47,8 @@ public:
return parent()->logicalModuleIdentifier();
}
[[nodiscard]] QString element() const override { return parent()->name(); }
+ [[nodiscard]] const EnumNode *enumNode() const { return m_enumNode.first; }
+ [[nodiscard]] const QString &enumPrefix() const;
void markDefault() override { m_isDefault = true; }
void markReadOnly(bool flag) override { m_readOnly = toFlagValue(flag); }
@@ -62,6 +65,7 @@ private:
bool m_attached {};
FlagValue m_readOnly { FlagValueDefault };
FlagValue m_required { FlagValueDefault };
+ std::pair<EnumNode *, QString> m_enumNode { nullptr, {} };
};
QT_END_NAMESPACE
diff --git a/src/qdoc/qdoc/src/qdoc/qmlvisitor.cpp b/src/qdoc/qdoc/src/qdoc/qmlvisitor.cpp
index 54f00f7b8..d6ecf1986 100644
--- a/src/qdoc/qdoc/src/qdoc/qmlvisitor.cpp
+++ b/src/qdoc/qdoc/src/qdoc/qmlvisitor.cpp
@@ -22,6 +22,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
The constructor stores all the parameters in local data members.
*/
@@ -426,6 +428,14 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::SourceLocation, Node *node, Doc &d
}
} else if (command == COMMAND_QMLDEFAULT) {
node->markDefault();
+ } else if (command == COMMAND_QMLENUMERATORSFROM) {
+ if (!node->isQmlProperty()) {
+ doc.location().warning("Ignored '\\%1', applies only to '\\%2'"_L1
+ .arg(command, COMMAND_QMLPROPERTY));
+ } else if (!static_cast<QmlPropertyNode*>(node)->setEnumNode(args[0].first, args[0].second)) {
+ doc.location().warning("Failed to find C++ enumeration '%2' passed to \\%1"_L1
+ .arg(command, args[0].first), "Use \\value commands instead"_L1);
+ }
} else if (command == COMMAND_QMLREADONLY) {
node->markReadOnly(1);
} else if (command == COMMAND_QMLREQUIRED) {
diff --git a/src/qdoc/qdoc/src/qdoc/tree.h b/src/qdoc/qdoc/src/qdoc/tree.h
index 188746831..c7265b7b3 100644
--- a/src/qdoc/qdoc/src/qdoc/tree.h
+++ b/src/qdoc/qdoc/src/qdoc/tree.h
@@ -62,6 +62,9 @@ private: // Note the constructor and destructor are private.
~Tree();
public: // Of necessity, a few public functions remain.
+ [[nodiscard]] Node *findNodeByNameAndType(const QStringList &path,
+ bool (Node::*isMatch)() const) const;
+
[[nodiscard]] const QString &camelCaseModuleName() const { return m_camelCaseModuleName; }
[[nodiscard]] const QString &physicalModuleName() const { return m_physicalModuleName; }
[[nodiscard]] const QString &indexFileName() const { return m_indexFileName; }
@@ -91,8 +94,6 @@ private: // The rest of the class is private.
const Node *findNode(const QStringList &path, const Node *relative, int flags,
Node::Genus genus) const;
- [[nodiscard]] Node *findNodeByNameAndType(const QStringList &path,
- bool (Node::*isMatch)() const) const;
Aggregate *findRelatesNode(const QStringList &path);
const Node *findEnumNode(const Node *node, const Node *aggregate, const QStringList &path, int offset) const;
QString getRef(const QString &target, const Node *node) const;
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.cpp b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.cpp
new file mode 100644
index 000000000..fa3cc1e31
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "class.h"
+
+/*!
+ \module Module
+*/
+
+/*!
+ \class Class
+ \inmodule Module
+*/
+
+/*!
+ \enum Class::Values
+
+ Try now these exciting values in your C++ code:
+
+ \value One
+ One value
+
+ Wait, that's not all!
+
+ \value Two
+ 2nd value
+ \value Three
+ 3rd value
+*/
+
+/*!
+ \enum Class::MoreValues
+
+ \value Something something
+ \value Else entirely
+*/
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.h b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.h
new file mode 100644
index 000000000..8c4967a69
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/class.h
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#pragma once
+
+class Class {
+
+public:
+ enum Values { One, Two, Three };
+ enum class MoreValues { Something, Else };
+};
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/class.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/class.xml
new file mode 100644
index 000000000..d0bf4bac1
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/class.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:its="http://www.w3.org/2005/11/its" version="5.2" xml:lang="en">
+<db:info>
+<db:title its:translate="no">Class Class</db:title>
+<db:productname>QmlEnumValuesFromCpp</db:productname>
+<db:titleabbrev>QmlEnumValuesFromCpp Reference Documentation</db:titleabbrev>
+<db:abstract>
+<db:para>QmlEnumValuesFromCpp Reference Documentation.</db:para></db:abstract>
+</db:info>
+<db:variablelist its:translate="no">
+<db:varlistentry>
+<db:term>Header</db:term>
+<db:listitem>
+<db:para>Class</db:para>
+</db:listitem>
+</db:varlistentry>
+</db:variablelist>
+<db:section xml:id="details">
+<db:title>Detailed Description</db:title>
+</db:section>
+<db:section xml:id="member-type-documentation">
+<db:title>Member Type Documentation</db:title>
+<db:section xml:id="MoreValues-enum">
+<db:title its:translate="no">enum Class::MoreValues</db:title>
+<db:enumsynopsis>
+<db:enumname>MoreValues</db:enumname>
+<db:enumitem>
+<db:enumidentifier>Something</db:enumidentifier>
+<db:enumvalue>0</db:enumvalue>
+</db:enumitem>
+<db:enumitem>
+<db:enumidentifier>Else</db:enumidentifier>
+<db:enumvalue>1</db:enumvalue>
+</db:enumitem>
+<db:synopsisinfo role="access">public</db:synopsisinfo>
+<db:synopsisinfo role="status">active</db:synopsisinfo>
+<db:synopsisinfo role="threadsafeness">unspecified</db:synopsisinfo>
+</db:enumsynopsis>
+<db:informaltable>
+<db:thead>
+<db:tr>
+<db:th>Constant</db:th>
+<db:th>Value</db:th>
+<db:th>Description</db:th>
+</db:tr>
+</db:thead>
+<db:tr>
+<db:td>
+<db:para its:translate="no"><db:code><db:emphasis role="bold"><db:link xlink:href="class.xml">Class</db:link></db:emphasis>::<db:emphasis role="bold"><db:link xlink:href="">MoreValues</db:link></db:emphasis>::Something</db:code></db:para>
+</db:td>
+<db:td><db:code its:translate="no">0</db:code></db:td>
+<db:td>
+<db:para>something</db:para>
+</db:td>
+</db:tr>
+<db:tr>
+<db:td>
+<db:para its:translate="no"><db:code><db:emphasis role="bold"><db:link xlink:href="class.xml">Class</db:link></db:emphasis>::<db:emphasis role="bold"><db:link xlink:href="">MoreValues</db:link></db:emphasis>::Else</db:code></db:para>
+</db:td>
+<db:td><db:code its:translate="no">1</db:code></db:td>
+<db:td>
+<db:para>entirely</db:para>
+</db:td>
+</db:tr>
+</db:informaltable>
+</db:section>
+<db:section xml:id="Values-enum">
+<db:title its:translate="no">enum Class::Values</db:title>
+<db:enumsynopsis>
+<db:enumname>Values</db:enumname>
+<db:enumitem>
+<db:enumidentifier>One</db:enumidentifier>
+<db:enumvalue>0</db:enumvalue>
+</db:enumitem>
+<db:enumitem>
+<db:enumidentifier>Two</db:enumidentifier>
+<db:enumvalue>1</db:enumvalue>
+</db:enumitem>
+<db:enumitem>
+<db:enumidentifier>Three</db:enumidentifier>
+<db:enumvalue>2</db:enumvalue>
+</db:enumitem>
+<db:synopsisinfo role="access">public</db:synopsisinfo>
+<db:synopsisinfo role="status">active</db:synopsisinfo>
+<db:synopsisinfo role="threadsafeness">unspecified</db:synopsisinfo>
+</db:enumsynopsis>
+<db:para>Try now these exciting values in your C++ code:</db:para>
+<db:informaltable>
+<db:thead>
+<db:tr>
+<db:th>Constant</db:th>
+<db:th>Value</db:th>
+<db:th>Description</db:th>
+</db:tr>
+</db:thead>
+<db:tr>
+<db:td>
+<db:para its:translate="no"><db:code><db:emphasis role="bold"><db:link xlink:href="class.xml">Class</db:link></db:emphasis>::One</db:code></db:para>
+</db:td>
+<db:td><db:code its:translate="no">0</db:code></db:td>
+<db:td>
+<db:para>One value</db:para>
+</db:td>
+</db:tr>
+</db:informaltable>
+<db:para>Wait, that's not all!</db:para>
+<db:informaltable>
+<db:thead>
+<db:tr>
+<db:th>Constant</db:th>
+<db:th>Value</db:th>
+<db:th>Description</db:th>
+</db:tr>
+</db:thead>
+<db:tr>
+<db:td>
+<db:para its:translate="no"><db:code><db:emphasis role="bold"><db:link xlink:href="class.xml">Class</db:link></db:emphasis>::Two</db:code></db:para>
+</db:td>
+<db:td><db:code its:translate="no">1</db:code></db:td>
+<db:td>
+<db:para>2nd value</db:para>
+</db:td>
+</db:tr>
+<db:tr>
+<db:td>
+<db:para its:translate="no"><db:code><db:emphasis role="bold"><db:link xlink:href="class.xml">Class</db:link></db:emphasis>::Three</db:code></db:para>
+</db:td>
+<db:td><db:code its:translate="no">2</db:code></db:td>
+<db:td>
+<db:para>3rd value</db:para>
+</db:td>
+</db:tr>
+</db:informaltable>
+</db:section>
+</db:section>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/module-module.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/module-module.xml
new file mode 100644
index 000000000..972603249
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/module-module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:its="http://www.w3.org/2005/11/its" version="5.2" xml:lang="en">
+<db:info>
+<db:title its:translate="no"></db:title>
+<db:productname>QmlEnumValuesFromCpp</db:productname>
+<db:titleabbrev>QmlEnumValuesFromCpp Reference Documentation</db:titleabbrev>
+<db:abstract>
+<db:para>QmlEnumValuesFromCpp Reference Documentation.</db:para></db:abstract>
+</db:info>
+<db:section xml:id="classes">
+<db:title>Classes</db:title>
+<db:itemizedlist role="classes">
+<db:listitem>
+<db:para><db:link xlink:href="class.xml" xlink:role="class">Class</db:link></db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:section>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qml-qmlmodule-type.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qml-qmlmodule-type.xml
new file mode 100644
index 000000000..e98a0ff68
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qml-qmlmodule-type.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:its="http://www.w3.org/2005/11/its" version="5.2" xml:lang="en">
+<db:info>
+<db:title its:translate="no">Type QML Type</db:title>
+<db:productname>QmlEnumValuesFromCpp</db:productname>
+<db:titleabbrev>QmlEnumValuesFromCpp Reference Documentation</db:titleabbrev>
+<db:abstract>
+<db:para>QmlEnumValuesFromCpp Reference Documentation.</db:para></db:abstract>
+</db:info>
+<db:variablelist its:translate="no">
+<db:varlistentry>
+<db:term>Import Statement</db:term>
+<db:listitem>
+<db:para>import QmlModule</db:para>
+</db:listitem>
+</db:varlistentry>
+</db:variablelist>
+<db:section xml:id="details">
+<db:title>Detailed Description</db:title>
+</db:section>
+<db:section xml:id="property-documentation">
+<db:title>Property Documentation</db:title>
+<db:section xml:id="something-prop">
+<db:title>something : enumeration</db:title>
+<db:fieldsynopsis>
+<db:type>enumeration</db:type>
+<db:varname>something</db:varname>
+<db:modifier>writable</db:modifier>
+<db:synopsisinfo role="access">public</db:synopsisinfo>
+<db:synopsisinfo role="status">active</db:synopsisinfo>
+<db:synopsisinfo role="threadsafeness">unspecified</db:synopsisinfo>
+</db:fieldsynopsis>
+<db:informaltable>
+<db:thead>
+<db:tr>
+<db:th>Constant</db:th>
+<db:th>Description</db:th>
+</db:tr>
+</db:thead>
+<db:tr>
+<db:td>
+<db:para its:translate="no">SomeType.Something</db:para>
+</db:td>
+<db:td>
+<db:para>something</db:para>
+</db:td>
+</db:tr>
+<db:tr>
+<db:td>
+<db:para its:translate="no">SomeType.Else</db:para>
+</db:td>
+<db:td>
+<db:para>entirely</db:para>
+</db:td>
+</db:tr>
+</db:informaltable>
+</db:section>
+<db:section xml:id="values-prop">
+<db:title>values : enumeration</db:title>
+<db:fieldsynopsis>
+<db:type>enumeration</db:type>
+<db:varname>values</db:varname>
+<db:modifier>writable</db:modifier>
+<db:synopsisinfo role="access">public</db:synopsisinfo>
+<db:synopsisinfo role="status">active</db:synopsisinfo>
+<db:synopsisinfo role="threadsafeness">unspecified</db:synopsisinfo>
+</db:fieldsynopsis>
+<db:para>You can even use these values in QML.</db:para>
+<db:informaltable>
+<db:thead>
+<db:tr>
+<db:th>Constant</db:th>
+<db:th>Description</db:th>
+</db:tr>
+</db:thead>
+<db:tr>
+<db:td>
+<db:para its:translate="no">Type.One</db:para>
+</db:td>
+<db:td>
+<db:para>One value</db:para>
+</db:td>
+</db:tr>
+<db:tr>
+<db:td>
+<db:para its:translate="no">Type.Two</db:para>
+</db:td>
+<db:td>
+<db:para>2nd value</db:para>
+</db:td>
+</db:tr>
+<db:tr>
+<db:td>
+<db:para its:translate="no">Type.Three</db:para>
+</db:td>
+<db:td>
+<db:para>3rd value</db:para>
+</db:td>
+</db:tr>
+</db:informaltable>
+</db:section>
+</db:section>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qmlmodule-qmlmodule.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qmlmodule-qmlmodule.xml
new file mode 100644
index 000000000..12466c566
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/docbook/qmlmodule-qmlmodule.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:its="http://www.w3.org/2005/11/its" version="5.2" xml:lang="en">
+<db:info>
+<db:title its:translate="no"></db:title>
+<db:productname>QmlEnumValuesFromCpp</db:productname>
+<db:titleabbrev>QmlEnumValuesFromCpp Reference Documentation</db:titleabbrev>
+<db:abstract>
+<db:para>QmlEnumValuesFromCpp Reference Documentation.</db:para></db:abstract>
+</db:info>
+<db:anchor xml:id="details"/>
+<db:itemizedlist role="members">
+<db:listitem>
+<db:para><db:link xlink:href="qml-qmlmodule-type.xml" xlink:role="">Type</db:link></db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class-members.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class-members.html
new file mode 100644
index 000000000..8b5efb662
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class-members.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- class.cpp -->
+ <title>List of All Members for Class | QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<li>Class</li>
+<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title" translate="no">List of All Members for Class</h1>
+<p>This is the complete list of members for <a href="class.html">Class</a>, including inherited members.</p>
+<ul>
+<li class="fn" translate="no">enum class <span class="name"><b><a href="class.html#MoreValues-enum" translate="no">MoreValues</a></b></span></li>
+<li class="fn" translate="no">enum <span class="name"><b><a href="class.html#Values-enum" translate="no">Values</a></b></span></li>
+</ul>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class.html
new file mode 100644
index 000000000..e7d4ddc3d
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/class.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- class.cpp -->
+ <title>Class Class | QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<li>Class</li>
+<div class="sidebar">
+<div class="toc">
+<h3 id="toc">Contents</h3>
+<ul>
+<li class="level1"><a href="#public-types">Public Types</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" translate="no">Class Class</h1>
+<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;Class&gt;</span></td></tr>
+</table></div>
+<ul>
+<li><a href="class-members.html">List of all members, including inherited members</a></li>
+</ul>
+<h2 id="public-types">Public Types</h2>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft rightAlign topAlign"> enum class </td><td class="memItemRight bottomAlign"><b><a href="class.html#MoreValues-enum" translate="no">MoreValues</a></b> { Something, Else }</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> enum </td><td class="memItemRight bottomAlign"><b><a href="class.html#Values-enum" translate="no">Values</a></b> { One, Two, Three }</td></tr>
+</table></div>
+<!-- $$$Class-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@Class -->
+<div class="types">
+<h2>Member Type Documentation</h2>
+<!-- $$$MoreValues$$$Something$$$Else -->
+<h3 class="fn" translate="no" id="MoreValues-enum">enum class Class::<span class="name">MoreValues</span></h3>
+<div class="table"><table class="valuelist"><tr valign="top" class="odd"><th class="tblConst">Constant</th><th class="tblval">Value</th><th class="tbldscr">Description</th></tr>
+<tr><td class="topAlign"><code translate="no">Class::MoreValues::Something</code></td><td class="topAlign tblval"><code translate="no">0</code></td><td class="topAlign">something</td></tr>
+<tr><td class="topAlign"><code translate="no">Class::MoreValues::Else</code></td><td class="topAlign tblval"><code translate="no">1</code></td><td class="topAlign">entirely</td></tr>
+</table></div>
+<!-- @@@MoreValues -->
+<!-- $$$Values$$$One$$$Two$$$Three -->
+<h3 class="fn" translate="no" id="Values-enum">enum Class::<span class="name">Values</span></h3>
+<p>Try now these exciting values in your C++ code:</p>
+<div class="table"><table class="valuelist"><tr valign="top" class="odd"><th class="tblConst">Constant</th><th class="tblval">Value</th><th class="tbldscr">Description</th></tr>
+<tr><td class="topAlign"><code translate="no">Class::One</code></td><td class="topAlign tblval"><code translate="no">0</code></td><td class="topAlign">One value</td></tr>
+</table></div>
+<p>Wait, that's not all!</p>
+<div class="table"><table class="valuelist"><tr valign="top" class="even"><th class="tblConst">Constant</th><th class="tblval">Value</th><th class="tbldscr">Description</th></tr>
+<tr><td class="topAlign"><code translate="no">Class::Two</code></td><td class="topAlign tblval"><code translate="no">1</code></td><td class="topAlign">2nd value</td></tr>
+<tr><td class="topAlign"><code translate="no">Class::Three</code></td><td class="topAlign tblval"><code translate="no">2</code></td><td class="topAlign">3rd value</td></tr>
+</table></div>
+<!-- @@@Values -->
+</div>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/module-module.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/module-module.html
new file mode 100644
index 000000000..8bcf61f6b
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/module-module.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- class.cpp -->
+ <title>QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<div class="sidebar">
+<div class="toc">
+<h3 id="toc">Contents</h3>
+<ul>
+<li class="level1"><a href="#namespaces">Namespaces</a></li>
+<li class="level1"><a href="#classes">Classes</a></li>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h2 id="classes">Classes</h2>
+<div class="table"><table class="annotated">
+<tr class="odd topAlign"><td class="tblName" translate="no"><p><a href="class.html">Class</a></p></td></tr>
+</table></div>
+<!-- $$$Module-description -->
+<div class="descr" id="details">
+</div>
+<!-- @@@Module -->
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type-members.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type-members.html
new file mode 100644
index 000000000..3270d7158
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type-members.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- qmltype.qdoc -->
+ <title>List of All Members for Type | QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<li>Type</li>
+<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title" translate="no">List of All Members for Type</h1>
+<p>This is the complete list of members for <a href="qml-qmlmodule-type.html">Type</a>, including inherited members.</p>
+<ul>
+<li class="fn" translate="no"><b><a href="qml-qmlmodule-type.html#something-prop" translate="no">something</a></b> : enumeration</li>
+<li class="fn" translate="no"><b><a href="qml-qmlmodule-type.html#values-prop" translate="no">values</a></b> : enumeration</li>
+</ul>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type.html
new file mode 100644
index 000000000..509dd2431
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qml-qmlmodule-type.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- qmltype.qdoc -->
+ <title>Type QML Type | QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<li>Type</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" translate="no">Type QML Type</h1>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft rightAlign topAlign"> Import Statement:</td><td class="memItemRight bottomAlign"> import QmlModule</td></tr></table></div><ul>
+<li><a href="qml-qmlmodule-type-members.html">List of all members, including inherited members</a></li>
+</ul>
+<h2 id="properties">Properties</h2>
+<ul>
+<li class="fn" translate="no"><b><a href="qml-qmlmodule-type.html#something-prop" translate="no">something</a></b> : enumeration</li>
+<li class="fn" translate="no"><b><a href="qml-qmlmodule-type.html#values-prop" translate="no">values</a></b> : enumeration</li>
+</ul>
+<!-- $$$Type-description -->
+<h2 id="details">Detailed Description</h2>
+<!-- @@@Type -->
+<h2>Property Documentation</h2>
+<!-- $$$something -->
+<div class="qmlitem"><div class="qmlproto" translate="no">
+<div class="table"><table class="qmlname">
+<tr valign="top" class="odd" id="something-prop">
+<td class="tblQmlPropNode"><p>
+<span class="name">something</span> : <span class="type">enumeration</span></p></td></tr>
+</table></div></div>
+<div class="qmldoc"><div class="table"><table class="valuelist"><tr valign="top" class="odd"><th class="tblConst">Constant</th><th class="tbldscr">Description</th></tr>
+<tr><td class="topAlign"><code translate="no">SomeType.Something</code></td><td class="topAlign">something</td></tr>
+<tr><td class="topAlign"><code translate="no">SomeType.Else</code></td><td class="topAlign">entirely</td></tr>
+</table></div>
+</div></div><!-- @@@something -->
+<br/>
+<!-- $$$values -->
+<div class="qmlitem"><div class="qmlproto" translate="no">
+<div class="table"><table class="qmlname">
+<tr valign="top" class="odd" id="values-prop">
+<td class="tblQmlPropNode"><p>
+<span class="name">values</span> : <span class="type">enumeration</span></p></td></tr>
+</table></div></div>
+<div class="qmldoc"><p>You can even use these values in QML.</p>
+<div class="table"><table class="valuelist"><tr valign="top" class="odd"><th class="tblConst">Constant</th><th class="tbldscr">Description</th></tr>
+<tr><td class="topAlign"><code translate="no">Type.One</code></td><td class="topAlign">One value</td></tr>
+<tr><td class="topAlign"><code translate="no">Type.Two</code></td><td class="topAlign">2nd value</td></tr>
+<tr><td class="topAlign"><code translate="no">Type.Three</code></td><td class="topAlign">3rd value</td></tr>
+</table></div>
+</div></div><!-- @@@values -->
+<br/>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlenumvaluesfromcpp.index b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlenumvaluesfromcpp.index
new file mode 100644
index 000000000..3d9e172a1
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlenumvaluesfromcpp.index
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QDOCINDEX>
+<INDEX url="" title="QmlEnumValuesFromCpp Reference Documentation" version="" project="QmlEnumValuesFromCpp">
+ <namespace name="" status="active" access="public" module="qmlenumvaluesfromcpp">
+ <class name="Class" href="class.html" status="active" access="public" location="class.h" documented="true" module="Module">
+ <enum name="MoreValues" fullname="Class::MoreValues" href="class.html#MoreValues-enum" status="active" access="public" location="class.h" documented="true" scoped="true">
+ <value name="Something" value="0"/>
+ <value name="Else" value="1"/>
+ </enum>
+ <enum name="Values" fullname="Class::Values" href="class.html#Values-enum" status="active" access="public" location="class.h" documented="true">
+ <value name="One" value="0"/>
+ <value name="Two" value="1"/>
+ <value name="Three" value="2"/>
+ </enum>
+ </class>
+ <qmlclass name="Type" qml-module-name="QmlModule" fullname="QmlModule.Type" href="qml-qmlmodule-type.html" status="active" access="public" location="qmltype.qdoc" documented="true" title="Type" fulltitle="Type" subtitle="">
+ <qmlproperty name="something" fullname="QmlModule.Type.something" href="qml-qmlmodule-type.html#something-prop" status="active" access="public" location="qmltype.qdoc" documented="true" type="enumeration" attached="false" writable="true"/>
+ <qmlproperty name="values" fullname="QmlModule.Type.values" href="qml-qmlmodule-type.html#values-prop" status="active" access="public" location="qmltype.qdoc" documented="true" type="enumeration" attached="false" writable="true"/>
+ </qmlclass>
+ <module name="Module" href="module-module.html" status="active" documented="true" seen="true" title=""/>
+ <qmlmodule name="QmlModule" qml-module-name="QmlModule" href="qmlmodule-qmlmodule.html" status="active" location="qmltype.qdoc" documented="true" seen="true" title=""/>
+ </namespace>
+</INDEX>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlmodule-qmlmodule.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlmodule-qmlmodule.html
new file mode 100644
index 000000000..9cbff451f
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/html/qmlmodule-qmlmodule.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- qmltype.qdoc -->
+ <title>QmlEnumValuesFromCpp</title>
+</head>
+<body>
+<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
+<!-- $$$QmlModule-description -->
+<div class="descr" id="details">
+</div>
+<!-- @@@QmlModule -->
+<div class="table"><table class="annotated">
+<tr class="odd topAlign"><td class="tblName" translate="no"><p><a href="qml-qmlmodule-type.html">Type</a></p></td></tr>
+</table></div>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/class.webxml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/class.webxml
new file mode 100644
index 000000000..d6b062fa7
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/class.webxml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<WebXML>
+ <document>
+ <class name="Class" href="class.html" status="active" access="public" location="class.h" documented="true" module="Module">
+ <description/>
+ <enum name="MoreValues" fullname="Class::MoreValues" href="class.html#MoreValues-enum" status="active" access="public" location="class.h" documented="true" scoped="true">
+ <value name="Something" value="0"/>
+ <value name="Else" value="1"/>
+ <description>
+ <list type="enum">
+ <definition>
+ <term>Class::MoreValues::Something</term>Something</definition>
+ <item>
+ <para>something</para>
+ </item>
+ <definition>
+ <term>Class::MoreValues::Else</term>Else</definition>
+ <item>
+ <para>entirely</para>
+ </item>
+ </list>
+ </description>
+ </enum>
+ <enum name="Values" fullname="Class::Values" href="class.html#Values-enum" status="active" access="public" location="class.h" documented="true">
+ <value name="One" value="0"/>
+ <value name="Two" value="1"/>
+ <value name="Three" value="2"/>
+ <description>
+ <para>Try now these exciting values in your C++ code:</para>
+ <list type="enum">
+ <definition>
+ <term>Class::One</term>One</definition>
+ <item>
+ <para>One value</para>
+ </item>
+ </list>
+ <para>Wait, that's not all!</para>
+ <list type="enum">
+ <definition>
+ <term>Class::Two</term>Two</definition>
+ <item>
+ <para>2nd value</para>
+ </item>
+ <definition>
+ <term>Class::Three</term>Three</definition>
+ <item>
+ <para>3rd value</para>
+ </item>
+ </list>
+ </description>
+ </enum>
+ </class>
+ </document>
+</WebXML>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/module-module.webxml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/module-module.webxml
new file mode 100644
index 000000000..5d24b3077
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/module-module.webxml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<WebXML>
+ <document/>
+</WebXML>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlenumvaluesfromcpp.index b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlenumvaluesfromcpp.index
new file mode 100644
index 000000000..3d9e172a1
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlenumvaluesfromcpp.index
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QDOCINDEX>
+<INDEX url="" title="QmlEnumValuesFromCpp Reference Documentation" version="" project="QmlEnumValuesFromCpp">
+ <namespace name="" status="active" access="public" module="qmlenumvaluesfromcpp">
+ <class name="Class" href="class.html" status="active" access="public" location="class.h" documented="true" module="Module">
+ <enum name="MoreValues" fullname="Class::MoreValues" href="class.html#MoreValues-enum" status="active" access="public" location="class.h" documented="true" scoped="true">
+ <value name="Something" value="0"/>
+ <value name="Else" value="1"/>
+ </enum>
+ <enum name="Values" fullname="Class::Values" href="class.html#Values-enum" status="active" access="public" location="class.h" documented="true">
+ <value name="One" value="0"/>
+ <value name="Two" value="1"/>
+ <value name="Three" value="2"/>
+ </enum>
+ </class>
+ <qmlclass name="Type" qml-module-name="QmlModule" fullname="QmlModule.Type" href="qml-qmlmodule-type.html" status="active" access="public" location="qmltype.qdoc" documented="true" title="Type" fulltitle="Type" subtitle="">
+ <qmlproperty name="something" fullname="QmlModule.Type.something" href="qml-qmlmodule-type.html#something-prop" status="active" access="public" location="qmltype.qdoc" documented="true" type="enumeration" attached="false" writable="true"/>
+ <qmlproperty name="values" fullname="QmlModule.Type.values" href="qml-qmlmodule-type.html#values-prop" status="active" access="public" location="qmltype.qdoc" documented="true" type="enumeration" attached="false" writable="true"/>
+ </qmlclass>
+ <module name="Module" href="module-module.html" status="active" documented="true" seen="true" title=""/>
+ <qmlmodule name="QmlModule" qml-module-name="QmlModule" href="qmlmodule-qmlmodule.html" status="active" location="qmltype.qdoc" documented="true" seen="true" title=""/>
+ </namespace>
+</INDEX>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlmodule-qmlmodule.webxml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlmodule-qmlmodule.webxml
new file mode 100644
index 000000000..5d24b3077
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/expected/webxml/qmlmodule-qmlmodule.webxml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<WebXML>
+ <document/>
+</WebXML>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmlenumvaluesfromcpp.qdocconf b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmlenumvaluesfromcpp.qdocconf
new file mode 100644
index 000000000..56b0a3ecc
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmlenumvaluesfromcpp.qdocconf
@@ -0,0 +1,22 @@
+project = QmlEnumValuesFromCpp
+moduleheader = class.h
+includepaths = .
+
+{sourcedirs,headerdirs} = .
+
+# zero warning policy
+warninglimit = 0
+warninglimit.enabled = true
+
+# don't write host system-specific paths to index files
+locationinfo = false
+
+outputformats = HTML WebXML DocBook
+{HTML.nosubdirs,WebXML.nosubdirs,DocBook.nosubdirs} = true
+
+HTML.outputsubdir = html
+WebXML.outputsubdir = webxml
+DocBook.outputsubdir = docbook
+
+DocBook.its = true
+DocBook.usedocbookextensions = true
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmltype.qdoc b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmltype.qdoc
new file mode 100644
index 000000000..3cd739c29
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/qmlenumvaluesfromcpp/qmltype.qdoc
@@ -0,0 +1,23 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+/*!
+ \qmlmodule QmlModule
+*/
+
+/*!
+ \qmltype Type
+ \inqmlmodule QmlModule
+*/
+
+/*!
+ \qmlproperty enumeration Type::values
+ \qmlenumeratorsfrom Class::Values
+
+ You can even use these values in QML.
+*/
+
+/*!
+ \qmlproperty enumeration Type::something
+ \qmlenumeratorsfrom [SomeType] Class::MoreValues
+*/