summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-08-11 10:45:51 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2024-01-26 14:51:35 +0100
commitac001bef798b79f4932d7ca8f4fb812159ba75ca (patch)
tree1cf783aa9235c4cf72e64d3775957ee6d621870c /src/tools/moc
parent941afac108aded21ea50caeec0b72291fcad7d59 (diff)
moc/QMetaProperty: Remove limitation on non-own-class notify signals
The moc generated code does a sanity check that NOTIFY signals actually exist in the parent class when they cannot be found in the class moc currently runs on. The logic there was however too simplistic, and couldn't deal with signals taking a parameter. Fix this, and take the opportunity to use a proper static_assert instead of generating a "normal" compile error. We do not do any checks for the presence of QPrivateSignal, as the whole point of QPrivateSignal is that it should be private (and not e.g. protected). Moreover, we adjust QMetaProperty::notifySignalIndex to take single-argument notify methods into consideration as well when encontering an unresolved notify index. Fixes: QTBUG-115989 Pick-to: 6.7 Change-Id: I8a056a15777f3132691e207b4b9ab6c2c9b2126d Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/generator.cpp29
-rw-r--r--src/tools/moc/moc.cpp1
2 files changed, 24 insertions, 6 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 967d7236de..02e9ef178a 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -637,12 +637,29 @@ void Generator::generateCode()
// Generate function to make sure the non-class signals exist in the parent classes
//
if (!cdef->nonClassSignalList.isEmpty()) {
- fprintf(out, "// If you get a compile error in this function it can be because either\n");
- fprintf(out, "// a) You are using a NOTIFY signal that does not exist. Fix it.\n");
- fprintf(out, "// b) You are using a NOTIFY signal that does exist (in a parent class) but has a non-empty parameter list. This is a moc limitation.\n");
- fprintf(out, "[[maybe_unused]] static void checkNotifySignalValidity_%s(%s *t) {\n", qualifiedClassNameIdentifier.constData(), cdef->qualified.constData());
- for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList))
- fprintf(out, " t->%s();\n", nonClassSignal.constData());
+ fprintf(out, "namespace CheckNotifySignalValidity_%s {\n", qualifiedClassNameIdentifier.constData());
+ for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList)) {
+ const auto propertyIt = std::find_if(cdef->propertyList.constBegin(),
+ cdef->propertyList.constEnd(),
+ [&nonClassSignal](const PropertyDef &p) {
+ return nonClassSignal == p.notify;
+ });
+ // must find something, otherwise checkProperties wouldn't have inserted an entry into nonClassSignalList
+ Q_ASSERT(propertyIt != cdef->propertyList.constEnd());
+ fprintf(out, "template<typename T> using has_nullary_%s = decltype(std::declval<T>().%s());\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData());
+ const auto &propertyType = propertyIt->type;
+ fprintf(out, "template<typename T> using has_unary_%s = decltype(std::declval<T>().%s(std::declval<%s>()));\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData(),
+ propertyType.constData());
+ fprintf(out, "static_assert(qxp::is_detected_v<has_nullary_%s, %s> || qxp::is_detected_v<has_unary_%s, %s>,\n"
+ " \"NOTIFY signal %s does not exist in class (or is private in its parent)\");\n",
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData());
+ }
fprintf(out, "}\n");
}
}
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index e100ff4ba8..b471418a27 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -1167,6 +1167,7 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
fprintf(out, "\n#include <QtCore/qtmochelpers.h>\n");
fprintf(out, "\n#include <memory>\n\n"); // For std::addressof
+ fprintf(out, "\n#include <QtCore/qxptype_traits.h>\n"); // is_detected
fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
"#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());