aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-02-06 17:01:45 +0100
committerUlf Hermann <ulf.hermann@qt.io>2024-02-13 20:04:59 +0100
commit03ac6a0990afeb0ea3294e22d6e553a4370f32eb (patch)
treece409137447eb2ceca40174b0f518dcbee5c221b /src/qml/jsruntime
parente878b00efb84e8ea63015bd6727864228973b7b4 (diff)
QtQml: Re-allow manual calling of signal handlers
The fact that you could do this was due to a mistake in the implementation of QQmlPropertyCache. The cache entry for the signal handler looked like the signal itself. Make it possible to call QmlSignalHandler objects, and output a categorized warning when doing so. Also, align the call code between the interpreter and the JIT. Pick-to: 6.7 Fixes: QTBUG-120573 Change-Id: Ic76d37f587d21b68c55d77a08ac2d30950bec133 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Yifan Zhu <fanzhuyifan@gmail.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp22
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp13
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp12
4 files changed, 42 insertions, 7 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index e233b65f4e..89e09d6542 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -37,6 +37,7 @@
#include <private/qv4compileddata_p.h>
#include <private/qqmlpropertybinding_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
@@ -60,6 +61,7 @@ Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
Q_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
Q_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
Q_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
+Q_LOGGING_CATEGORY(lcSignalHandler, "qt.qml.signalhandler")
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
@@ -3179,6 +3181,26 @@ void Heap::QmlSignalHandler::init(QObject *object, int signalIndex)
DEFINE_OBJECT_VTABLE(QmlSignalHandler);
+ReturnedValue QmlSignalHandler::call(const Value *thisObject, const Value *argv, int argc) const
+{
+ const QString handlerName = QQmlSignalNames::signalNameToHandlerName(
+ object()->metaObject()->method(signalIndex()).name());
+ qCWarning(lcSignalHandler).noquote()
+ << QStringLiteral("Property '%1' of object %2 is a signal handler. You should "
+ "not call it directly. Make it a proper function and call "
+ "that or emit the signal.")
+ .arg(handlerName, thisObject->toQStringNoThrow());
+
+ Scope scope(engine());
+ Scoped<QObjectMethod> method(
+ scope, QObjectMethod::create(
+ scope.engine->rootContext(),
+ static_cast<Heap::QObjectWrapper *>(nullptr),
+ signalIndex()));
+
+ return method->call(thisObject, argv, argc);
+}
+
void QmlSignalHandler::initProto(ExecutionEngine *engine)
{
if (engine->signalHandlerPrototype()->d_unchecked())
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 7a2dbe7745..2cd2faedf8 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -411,6 +411,8 @@ struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
int signalIndex() const { return d()->signalIndex; }
QObject *object() const { return d()->object(); }
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const;
+
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 8b3f89414b..c51c94ffe4 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1503,10 +1503,17 @@ ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const V
// ok to have the value on the stack here
Value f = Value::fromReturnedValue(l->getter(l, engine, base));
- if (!f.isFunctionObject())
- return engine->throwTypeError();
+ if (Q_LIKELY(f.isFunctionObject()))
+ return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc));
+
+ if (QmlSignalHandler *handler = f.as<QmlSignalHandler>())
+ return checkedResult(engine, handler->call(&base, argv, argc));
- return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc));
+ const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[l->nameIndex]->toQString())
+ .arg(base.toQStringNoThrow());
+ return engine->throwTypeError(message);
}
ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 1ea0a569fb..696368fa3f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -794,15 +794,19 @@ QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *eng
// ok to have the value on the stack here
Value f = Value::fromReturnedValue(l->getter(l, engine, STACK_VALUE(base)));
- if (Q_UNLIKELY(!f.isFunctionObject())) {
- QString message = QStringLiteral("Property '%1' of object %2 is not a function")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
+ if (Q_LIKELY(f.isFunctionObject())) {
+ acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
+ } else if (QmlSignalHandler *handler = f.as<QmlSignalHandler>()) {
+ acc = handler->call(stack + base, stack + argv, argc);
+ } else {
+ const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[l->nameIndex]->toQString())
.arg(STACK_VALUE(base).toQStringNoThrow());
acc = engine->throwTypeError(message);
goto handleUnwind;
}
- acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallPropertyLookup)