diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-02-06 17:01:45 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-02-13 20:04:59 +0100 |
commit | 03ac6a0990afeb0ea3294e22d6e553a4370f32eb (patch) | |
tree | ce409137447eb2ceca40174b0f518dcbee5c221b /src/qml/jsruntime | |
parent | e878b00efb84e8ea63015bd6727864228973b7b4 (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.cpp | 22 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 12 |
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) |