diff options
55 files changed, 561 insertions, 141 deletions
diff --git a/dist/changes-5.14.1 b/dist/changes-5.14.1 new file mode 100644 index 0000000000..f4a2ab226a --- /dev/null +++ b/dist/changes-5.14.1 @@ -0,0 +1,89 @@ +Qt 5.14.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.14.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QtQml * +**************************************************************************** + - [QTBUG-81109] Don't crash when iterating invalid Proxy objects + - [QTBUG-81108] Don't crash when sorting arrays with non-stringifyable entries + - [QTBUG-81105] Support printing arrays with circular references + - [QTBUG-81104] Array.includes now works even with large arrays. + - [QTBUG-81037] Fixed oob access on Array.concat. + - [QTBUG-81093] Emit QQmlEngine::warnings when load fails instead of + simply qWarning. + - [QTBUG-81055] XMLHttpRequest works correctly in a QML WorkerThread. + - [QTBUG-80963] Fixed a crash in QQmlAdaptorModel. + - [QTBUG-80609] Fixed a crash related to the use of QSequentialIterable + as a JS container type. + - [QTBUG-80511] The compiler now supports larger stack slots to avoid + crashing when passing long lists or vectors. + - [QTBUG-30467] QQmlTypeLoader no longer parses qmldir content multiple times. + It can be told to forget the qmldir contents via QQmlTypeLoader::clearCache(), + as before. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - [QTBUG-71193] Fixed two crashes and a memory leak in ItemParticle. + - [QTBUG-34779] Fixed a crash in QQuickWindow that was discovered during + fuzz testing. + - [QTBUG-80505] TableView now resets its content size to empty if the + model becomes empty. + - [QTBUG-80505][QTBUG-71374] Fixed crashes in TableView when deleting or + setting the model to null. + - [QTBUG-80534] TableView behaves better when both a delegate and an + ObjectModel or DelegateModel are declared. + - [QTBUG-67986] ObjectModel items are now re-rendered when moved between models. + - [QTBUG-78297] DelegateModel and DelegateChoice now work together better. + - [QTBUG-79163] If a MouseArea has its preventStealing flag set, + a Pointer Handler that is a child is not allowed to steal the grab. + - [QTBUG-77624] MouseArea now reacts to touch ungrab, so that it will + know the interaction has been cancelled if the user begins dragging + after the press, and a DragHandler takes over. + - [QTBUG-68232] ListView now emits currentIndexChanged (to indicate a + value of -1) if an empty model is assigned. + - [QTBUG-66163] If the populate animation runs as a result of model assignment, + the viewport should not move. + - [QTBUG-79592] PathView now continues animating to the nearest + detent, as usual, when ungrabMouse() is called. + - [QTBUG-76954] Multiple TapHandlers (again) are able to react to + multiple touchpoints simultaneously, without losing the active state + when one of the points is stationary. + - [QTBUG-64138] Particle effects can now run continuously over longer + periods of time. + - [QTBUG-80190] We no longer emit TextInput.inputMaskChanged when you are + setting the same input mask again. + - [QTBUG-80070] When an animation is set on an Item which is loaded by a + Loader, it will no longer crash when the animation is deleted. + - [QTBUG-80364] Attempting to call QSGTexture::bind() outside the direct + OpenGL rendering path now generates a warning. + - [QTBUG-80297] QRhi now follows non-integer scaling fixes for native text. + - [QTBUG-75750] MultiPointTouchArea no longer ignores Qt-synthesized mouse + events. It's now possible to use a stylus with Qt Virtual Keyboard + because MPTA will react to the synth-mouse event that occurs after the + QTabletEvent was not handled. In the case that a touch event is sent, + MPTA will accept it; so a synth-mouse event is not expected afterwards. + If Flickable has pressDelay set, and intercepts a touch press, it will + send the delayed press in the form of a mouse press, and MPTA will now + react, which is useful in case MPTA is used in an item view delegate. + But it will also receive a touch release after the synthetic delayed press, + so now it checks whether the touchpoint ID is the same as the synth-mouse + touch ID, to verify that the touch release corresponds with the synth-mouse + press that arrived earlier, and react to it. diff --git a/examples/quick/shapes/content/item18.qml b/examples/quick/shapes/content/item18.qml index 3774d19bc5..192438408d 100644 --- a/examples/quick/shapes/content/item18.qml +++ b/examples/quick/shapes/content/item18.qml @@ -65,7 +65,7 @@ Rectangle { strokeWidth: 1 fillColor: "black" - PathText { x: 0; y: 100; font.family: "Arial"; font.pixelSize: 150; text: "Qt!" } + PathText { x: 0; y: 0; font.family: "Arial"; font.pixelSize: 150; text: "Qt!" } } } } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index a3d19841cf..d435e82390 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -94,9 +94,12 @@ qint64 NullDevice::writeData(const char *data, qint64 len) // (otherwise we assert in QVariant::operator<< when actually saving it) static bool isSaveable(const QVariant &value) { + const int valType = static_cast<int>(value.userType()); + if (valType >= QMetaType::User) + return false; NullDevice nullDevice; QDataStream fakeStream(&nullDevice); - return QMetaType::save(fakeStream, static_cast<int>(value.userType()), value.constData()); + return QMetaType::save(fakeStream, valType, value.constData()); } QQmlEngineDebugServiceImpl::QQmlEngineDebugServiceImpl(QObject *parent) : diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 6c51b4cbcb..df9f117d04 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -362,7 +362,7 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con ScopedString string(scope, scope.engine->newString(QStringLiteral("join"))); ScopedFunctionObject f(scope, that->get(string)); if (f) - return f->call(that, argv, argc); + return checkedResult(scope.engine, f->call(that, argv, argc)); return ObjectPrototype::method_toString(builtin, that, argv, argc); } @@ -1209,6 +1209,7 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value arguments[1] = Value::fromDouble(k); arguments[2] = instance; r = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); ok = r->toBoolean(); } return Encode(ok); @@ -1276,6 +1277,7 @@ ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value * arguments[1] = Value::fromDouble(k); arguments[2] = instance; result = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (result->toBoolean()) return Encode(true); } @@ -1345,6 +1347,7 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t arguments[1] = Value::fromDouble(k); arguments[2] = instance; mapped = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); a->arraySet(k, mapped); } return a.asReturnedValue(); @@ -1380,6 +1383,7 @@ ReturnedValue ArrayPrototype::method_filter(const FunctionObject *b, const Value arguments[1] = Value::fromDouble(k); arguments[2] = instance; selected = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (selected->toBoolean()) { a->arraySet(to, arguments[0]); ++to; @@ -1430,6 +1434,7 @@ ReturnedValue ArrayPrototype::method_reduce(const FunctionObject *b, const Value arguments[2] = Value::fromDouble(k); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } ++k; } @@ -1483,6 +1488,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const arguments[2] = Value::fromDouble(k - 1); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } --k; } diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index cc89947cec..c2f48ffeac 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -1561,7 +1561,7 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value if (!toIso) return v4->throwTypeError(); - return toIso->call(O, nullptr, 0); + return checkedResult(v4, toIso->call(O, nullptr, 0)); } ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index dfef52583e..cdb3b8942b 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -358,7 +358,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons return v4->throwTypeError(); thisObject = argc ? argv : nullptr; if (argc < 2 || argv[1].isNullOrUndefined()) - return f->call(thisObject, argv, 0); + return checkedResult(v4, f->call(thisObject, argv, 0)); Object *arr = argv[1].objectValue(); if (!arr) @@ -398,13 +398,14 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons } } - return f->call(thisObject, arguments, len); + return checkedResult(v4, f->call(thisObject, arguments, len)); } ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + QV4::ExecutionEngine *v4 = b->engine(); if (!thisObject->isFunctionObject()) - return b->engine()->throwTypeError(); + return v4->throwTypeError(); const FunctionObject *f = static_cast<const FunctionObject *>(thisObject); @@ -413,7 +414,7 @@ ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const ++argv; --argc; } - return f->call(thisObject, argv, argc); + return checkedResult(v4, f->call(thisObject, argv, argc)); } ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) @@ -713,12 +714,12 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc) { - const BoundFunction *f = static_cast<const BoundFunction *>(fo); - Scope scope(f->engine()); - - if (scope.hasException()) + QV4::ExecutionEngine *v4 = fo->engine(); + if (v4->hasException) return Encode::undefined(); + const BoundFunction *f = static_cast<const BoundFunction *>(fo); + Scope scope(v4); Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedFunctionObject target(scope, f->target()); JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc); @@ -729,7 +730,7 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value * argp += boundArgs->size(); } memcpy(argp, argv, argc*sizeof(Value)); - return target->call(jsCallData); + return checkedResult(v4, target->call(jsCallData)); } ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index c99cad8e33..78be58c60a 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -328,6 +328,10 @@ inline bool FunctionObject::isBoundFunction() const return d()->vtable() == BoundFunction::staticVTable(); } +inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result) +{ + return v4->hasException ? QV4::Encode::undefined() : result; +} } diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 936c032fad..ce759111f4 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -703,6 +703,8 @@ QString Stringify::Str(const QString &key, const Value &v) *jsCallData->thisObject = value; jsCallData->args[0] = v4->newString(key); value = toJSON->call(jsCallData); + if (v4->hasException) + return QString(); } } @@ -714,6 +716,8 @@ QString Stringify::Str(const QString &key, const Value &v) jsCallData->args[1] = value; *jsCallData->thisObject = holder; value = replacerFunction->call(jsCallData); + if (v4->hasException) + return QString(); } o = value->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 0cda6b864a..d3ea50867a 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -309,7 +309,8 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterFallback; @@ -326,7 +327,8 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } return getterTwoClasses(l, engine, object); } @@ -346,7 +348,8 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine * if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterFallback; @@ -391,7 +394,8 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterGeneric; @@ -429,7 +433,8 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(engine->globalObject, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + engine->globalObject, nullptr, 0)); } l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 89161433ed..b723141caa 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -105,7 +105,7 @@ ReturnedValue Object::getValueAccessor(const Value *thisObject, const Value &v, JSCallData jsCallData(scope); if (thisObject) *jsCallData->thisObject = *thisObject; - return f->call(jsCallData); + return checkedResult(scope.engine, f->call(jsCallData)); } bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value) diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 7d910a1cbc..0c8cc192fc 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -667,7 +667,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, co if (!f) THROW_TYPE_ERROR(); - return f->call(thisObject, argv, argc); + return checkedResult(scope.engine, f->call(thisObject, argv, argc)); } ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int) diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index 17d218a6eb..ecaff72b22 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -618,7 +618,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this } ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1))); - if (!nextPromise || scope.hasException()) { + if (scope.hasException() || !nextPromise) { ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); @@ -764,7 +764,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi } ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1))); - if (!nextPromise || scope.hasException()) { + if (scope.hasException() || !nextPromise) { ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index 51f96b9003..24676ffd00 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -96,6 +96,8 @@ ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Va cdata.args[2] = *receiver; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return Encode::undefined(); ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); if (attributes != Attr_Invalid && !attributes.isConfigurable()) { @@ -136,7 +138,7 @@ bool ProxyObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val cdata.args[3] = *receiver; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - if (!trapResult->toBoolean()) + if (scope.engine->hasException || !trapResult->toBoolean()) return false; ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); @@ -176,7 +178,7 @@ bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id) cdata.args[2] = o->d(); // ### fix receiver handling ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - if (!trapResult->toBoolean()) + if (scope.engine->hasException || !trapResult->toBoolean()) return false; ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); @@ -211,6 +213,8 @@ bool ProxyObject::virtualHasProperty(const Managed *m, PropertyKey id) cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (!result) { ScopedProperty targetDesc(scope); @@ -251,6 +255,8 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return Attr_Invalid; if (!trapResult->isObject() && !trapResult->isUndefined()) { scope.engine->throwTypeError(); return Attr_Invalid; @@ -323,7 +329,7 @@ bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Pro cdata.args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - bool result = trapResult->toBoolean(); + bool result = !scope.engine->hasException && trapResult->toBoolean(); if (!result) return false; @@ -373,6 +379,8 @@ bool ProxyObject::virtualIsExtensible(const Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (result != target->isExtensible()) { scope.engine->throwTypeError(); @@ -404,6 +412,8 @@ bool ProxyObject::virtualPreventExtensions(Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (result && target->isExtensible()) { scope.engine->throwTypeError(); @@ -439,6 +449,8 @@ Heap::Object *ProxyObject::virtualGetPrototypeOf(const Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return nullptr; if (!trapResult->isNull() && !trapResult->isObject()) { scope.engine->throwTypeError(); return nullptr; @@ -482,7 +494,7 @@ bool ProxyObject::virtualSetPrototypeOf(Managed *m, const Object *p) cdata.args[1] = p ? p->asReturnedValue() : Encode::null(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - bool result = trapResult->toBoolean(); + bool result = !scope.engine->hasException && trapResult->toBoolean(); if (!result) return false; if (!target->isExtensible()) { @@ -573,6 +585,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val JSCallData cdata(scope, 1, nullptr, handler); cdata.args[0] = target; ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return nullptr; if (!trapResult) { scope.engine->throwTypeError(); return nullptr; @@ -699,7 +713,7 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va if (scope.hasException()) return Encode::undefined(); if (trap->isNullOrUndefined()) - return target->call(thisObject, argv, argc); + return checkedResult(scope.engine, target->call(thisObject, argv, argc)); if (!trap->isFunctionObject()) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp index 0772770d63..2a6c61f044 100644 --- a/src/qml/jsruntime/qv4reflect.cpp +++ b/src/qml/jsruntime/qv4reflect.cpp @@ -98,7 +98,8 @@ ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, cons if (scope.hasException()) return Encode::undefined(); - return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc); + return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call( + &argv[1], arguments.argv, arguments.argc)); } ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f1375e4ca4..a8a37cda37 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -481,6 +481,8 @@ ReturnedValue RegExpPrototype::exec(ExecutionEngine *engine, const Object *o, co ScopedFunctionObject exec(scope, o->get(key)); if (exec) { ScopedValue result(scope, exec->call(o, s, 1)); + if (scope.hasException()) + RETURN_UNDEFINED(); if (!result->isNull() && !result->isObject()) return scope.engine->throwTypeError(); return result->asReturnedValue(); @@ -737,6 +739,8 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val cData->args[nCaptures + 1] = Encode(position); cData->args[nCaptures + 2] = s; ScopedValue replValue(scope, replaceFunction->call(cData)); + if (scope.hasException()) + return Encode::undefined(); replacement = replValue->toQString(); } else { replacement = RegExp::getSubstitution(matchString->toQString(), s->toQString(), position, cData.args, nCaptures, replaceValue->toQString()); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index e47a7a0b46..5fc94b9ddd 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -390,7 +390,7 @@ QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Valu return engine->throwTypeError(); ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1)); - return Encode(result->toBoolean()); + return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean()); } QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right) @@ -515,6 +515,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const ScopedValue conv(scope, object->get(meth1)); if (FunctionObject *o = conv->as<FunctionObject>()) { result = o->call(object, nullptr, 0); + if (engine->hasException) + return Encode::undefined(); if (result->isPrimitive()) return result->asReturnedValue(); } @@ -525,6 +527,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const conv = object->get(meth2); if (FunctionObject *o = conv->as<FunctionObject>()) { result = o->call(object, nullptr, 0); + if (engine->hasException) + return Encode::undefined(); if (result->isPrimitive()) return result->asReturnedValue(); } @@ -800,6 +804,8 @@ ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &i return engine->throwTypeError(); JSCallData cData(scope, 0, nullptr, o); ScopedObject it(scope, f->call(cData)); + if (engine->hasException) + return Encode::undefined(); if (!it) return engine->throwTypeError(); return it->asReturnedValue(); @@ -1341,7 +1347,8 @@ ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint inde engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); } - return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(function).call( + &thisObject, argv, argc)); } ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index, @@ -1356,7 +1363,8 @@ ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engin engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); } - return static_cast<FunctionObject &>(function).call(thisObject, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(function).call( + thisObject, argv, argc)); } ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc) @@ -1375,7 +1383,7 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val if (function->d() == engine->evalFunction()->d()) return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true); - return function->call(thisObject, argv, argc); + return checkedResult(engine, function->call(thisObject, argv, argc)); } ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc) @@ -1395,7 +1403,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va ->runtimeStrings[nameIndex]->toQString()); } - return f->call(thisObject, argv, argc); + return checkedResult(engine, f->call(thisObject, argv, argc)); } ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc) @@ -1437,7 +1445,7 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value & return engine->throwTypeError(error); } - return f->call(base, argv, argc); + return checkedResult(engine, f->call(base, argv, argc)); } ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc) @@ -1449,7 +1457,7 @@ ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const V if (!f.isFunctionObject()) return engine->throwTypeError(); - return static_cast<FunctionObject &>(f).call(&base, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc)); } ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc) @@ -1467,7 +1475,7 @@ ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &b if (!f) return engine->throwTypeError(); - return f->call(base, argv, argc); + return checkedResult(engine, f->call(base, argv, argc)); } ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc) @@ -1475,7 +1483,8 @@ ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &fun if (!func.isFunctionObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); Value undef = Value::undefinedValue(); - return static_cast<const FunctionObject &>(func).call(&undef, argv, argc); + return checkedResult(engine, static_cast<const FunctionObject &>(func).call( + &undef, argv, argc)); } ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func, @@ -1483,7 +1492,8 @@ ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Val { if (!func.isFunctionObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); - return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc); + return checkedResult(engine, static_cast<const FunctionObject &>(func).call( + &thisObject, argv, argc)); } struct CallArgs { @@ -1537,7 +1547,8 @@ ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value if (engine->hasException) return Encode::undefined(); - return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); + return checkedResult(engine, static_cast<const FunctionObject &>(function).call( + &thisObject, arguments.argv, arguments.argc)); } ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) @@ -1580,7 +1591,7 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger() || unsigned(argc) > fo.formalParameterCount()) { // Cannot tailcall, do a normal call: - return fo.call(&thisObject, argv, argc); + return checkedResult(engine, fo.call(&thisObject, argv, argc)); } memcpy(frame->jsFrame->args, argv, argc * sizeof(Value)); diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 9b4a2d575e..209a1b4e76 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -591,7 +591,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value ScopedFunctionObject match(scope, that->get(scope.engine->symbol_match())); if (!match) return scope.engine->throwTypeError(); - return match->call(that, s, 1); + return checkedResult(scope.engine, match->call(that, s, 1)); } ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 40a434d301..f425c6c87f 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -763,6 +763,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b arguments[1] = Value::fromDouble(k); arguments[2] = v; r = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); ok = r->toBoolean(); } return Encode(ok); @@ -862,6 +863,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject * arguments[1] = Value::fromDouble(k); arguments[2] = instance; selected = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (selected->toBoolean()) { ++arguments; scope.alloc(1); @@ -1194,6 +1196,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b, arguments[1] = Value::fromDouble(k); arguments[2] = instance; mapped = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); a->put(k, mapped); } return a->asReturnedValue(); @@ -1243,6 +1246,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject * arguments[2] = Value::fromDouble(k); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } ++k; } @@ -1298,6 +1302,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj arguments[2] = Value::fromDouble(k - 1); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } --k; } @@ -1359,6 +1364,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b, arguments[1] = Value::fromDouble(k); arguments[2] = instance; result = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (result->toBoolean()) return Encode(true); } diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 397c0b51a5..2b00caf378 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1247,6 +1247,31 @@ UiObjectMember: T_DEFAULT UiObjectMemberListPropertyNoInitialiser; } break; ./ +UiObjectMember: T_DEFAULT T_REQUIRED UiObjectMemberPropertyNoInitialiser; +/. + case $rule_number: { + AST::UiPublicMember *node = sym(3).UiPublicMember; + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->isRequired = true; + node->requiredToken = loc(2); + sym(1).Node = node; + } break; +./ + + +UiObjectMember: T_REQUIRED T_DEFAULT UiObjectMemberPropertyNoInitialiser; +/. + case $rule_number: { + AST::UiPublicMember *node = sym(3).UiPublicMember; + node->isDefaultMember = true; + node->defaultToken = loc(2); + node->isRequired = true; + node->requiredToken = loc(1); + sym(1).Node = node; + } break; +./ + OptionalSemicolon: | Semicolon; /. /* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 198ce98f2d..a26cdba53a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1515,6 +1515,14 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * } } + for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) { + QQmlPropertyData *propertyData = _propertyCache->property(i); + if (propertyData && propertyData->isRequired()) { + sharedState->hadRequiredProperties = true; + sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {propertyData->name(_qobject), compilationUnit->finalUrl(), _compiledObject->location, {}}); + } + } + if (_compiledObject->nFunctions > 0) setupFunctions(); setupBindings(); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index c4afbbd598..73b68a763b 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -75,6 +75,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) flags.setIsWritable(p.isWritable()); flags.setIsResettable(p.isResettable()); flags.setIsFinal(p.isFinal()); + flags.setIsRequired(p.isRequired()); if (p.isEnumType()) flags.type = QQmlPropertyData::Flags::EnumType; diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h index 2d9091edcd..7f70c34854 100644 --- a/src/qml/qml/qqmlpropertydata_p.h +++ b/src/qml/qml/qqmlpropertydata_p.h @@ -109,7 +109,7 @@ public: unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args unsigned isSignalHandler : 1; // Function is a signal handler unsigned isOverload : 1; // Function is an overload of another function - unsigned isCloned : 1; // The function was marked as cloned + unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned unsigned isConstructor : 1; // The function was marked is a constructor unsigned isDirect : 1; // Exists on a C++ QMetaObject unsigned isOverridden : 1; // Is overridden by a extension property @@ -159,6 +159,11 @@ public: isDirect = b; } + void setIsRequired(bool b) { + Q_ASSERT(type != FunctionType); + isRequiredORisCloned = b; + } + void setIsVMEFunction(bool b) { Q_ASSERT(type == FunctionType); isConstantORisVMEFunction = b; @@ -193,7 +198,7 @@ public: void setIsCloned(bool b) { Q_ASSERT(type == FunctionType); - isCloned = b; + isRequiredORisCloned = b; } void setIsConstructor(bool b) { @@ -224,6 +229,7 @@ public: bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; } bool isOverridden() const { return m_flags.isOverridden; } bool isDirect() const { return m_flags.isOverload; } + bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; } bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } bool isFunction() const { return m_flags.type == Flags::FunctionType; } bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; } @@ -241,7 +247,7 @@ public: bool isSignalHandler() const { return m_flags.isSignalHandler; } bool isOverload() const { return m_flags.isOverload; } void setOverload(bool onoff) { m_flags.isOverload = onoff; } - bool isCloned() const { return isFunction() && m_flags.isCloned; } + bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; } bool isConstructor() const { return m_flags.isConstructor; } bool hasOverride() const { return overrideIndex() >= 0; } @@ -438,7 +444,7 @@ QQmlPropertyData::Flags::Flags() , isFinalORisV4Function(false) , isSignalHandler(false) , isOverload(false) - , isCloned(false) + , isRequiredORisCloned(false) , isConstructor(false) , isOverridden(false) , type(OtherType) @@ -455,7 +461,7 @@ bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) c isFinalORisV4Function == other.isFinalORisV4Function && isOverridden == other.isOverridden && isSignalHandler == other.isSignalHandler && - isCloned == other.isCloned && + isRequiredORisCloned == other.isRequiredORisCloned && type == other.type && isConstructor == other.isConstructor && notFullyResolved == other.notFullyResolved && diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp index fbb85327a7..1f437a08c7 100644 --- a/src/qmlmodels/qqmladaptormodel.cpp +++ b/src/qmlmodels/qqmladaptormodel.cpp @@ -93,7 +93,7 @@ class QQmlDMCachedModelData : public QQmlDelegateModelItem { public: QQmlDMCachedModelData( - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, VDMModelDelegateDataType *dataType, int index, int row, int column); @@ -255,7 +255,9 @@ public: bool hasModelData; }; -QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index, int row, int column) +QQmlDMCachedModelData::QQmlDMCachedModelData( + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, + VDMModelDelegateDataType *dataType, int index, int row, int column) : QQmlDelegateModelItem(metaType, dataType, index, row, column) , type(dataType) { @@ -390,7 +392,7 @@ class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData public: QQmlDMAbstractItemModelData( - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, VDMModelDelegateDataType *dataType, int index, int row, int column) : QQmlDMCachedModelData(metaType, dataType, index, row, column) @@ -512,7 +514,7 @@ public: QQmlDelegateModelItem *createItem( QQmlAdaptorModel &model, - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, int index, int row, int column) const override { VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this); @@ -560,7 +562,7 @@ class QQmlDMListAccessorData : public QQmlDelegateModelItem Q_OBJECT Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged) public: - QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType, + QQmlDMListAccessorData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, QQmlAdaptorModel::Accessors *accessor, int index, int row, int column, const QVariant &value) : QQmlDelegateModelItem(metaType, accessor, index, row, column) @@ -676,7 +678,7 @@ public: QQmlDelegateModelItem *createItem( QQmlAdaptorModel &model, - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, int index, int row, int column) const override { VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this); @@ -719,7 +721,7 @@ class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelPr Q_INTERFACES(QQmlAdaptorModelProxyInterface) public: QQmlDMObjectData( - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, VDMObjectDelegateDataType *dataType, int index, int row, int column, QObject *object); @@ -790,7 +792,7 @@ public: QQmlDelegateModelItem *createItem( QQmlAdaptorModel &model, - QQmlDelegateModelItemMetaType *metaType, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, int index, int row, int column) const override { VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this); @@ -930,7 +932,7 @@ public: VDMObjectDelegateDataType *m_type; }; -QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType, +QQmlDMObjectData::QQmlDMObjectData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, VDMObjectDelegateDataType *dataType, int index, int row, int column, QObject *object) diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h index a4549127af..ee4862f3b4 100644 --- a/src/qmlmodels/qqmladaptormodel_p.h +++ b/src/qmlmodels/qqmladaptormodel_p.h @@ -87,7 +87,7 @@ public: virtual QQmlDelegateModelItem *createItem( QQmlAdaptorModel &, - QQmlDelegateModelItemMetaType *, + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &, int, int, int) const { return nullptr; } virtual bool notify( @@ -140,8 +140,11 @@ public: inline QVariant value(int index, const QString &role) const { return accessors->value(*this, index, role); } - inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) { - return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); } + inline QQmlDelegateModelItem *createItem( + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, int index) + { + return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); + } inline bool hasProxyObject() const { return list.type() == QQmlListAccessor::Instance || list.type() == QQmlListAccessor::ListProperty; } diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 3a3903965c..ee407538f1 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -2267,9 +2267,10 @@ void QV4::Heap::QQmlDelegateModelItemObject::destroy() } -QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, - QQmlAdaptorModel::Accessors *accessor, - int modelIndex, int row, int column) +QQmlDelegateModelItem::QQmlDelegateModelItem( + const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, + QQmlAdaptorModel::Accessors *accessor, + int modelIndex, int row, int column) : v4(metaType->v4Engine) , metaType(metaType) , contextData(nullptr) @@ -2285,8 +2286,6 @@ QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *meta , row(row) , column(column) { - metaType->addref(); - if (accessor->propertyCache) { // The property cache in the accessor is common for all the model // items in the model it wraps. It describes available model roles, @@ -2315,9 +2314,6 @@ QQmlDelegateModelItem::~QQmlDelegateModelItem() else delete incubationTask; } - - metaType->release(); - } void QQmlDelegateModelItem::Dispose() diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h index a1c4555d01..40c6bcdb21 100644 --- a/src/qmlmodels/qqmldelegatemodel_p_p.h +++ b/src/qmlmodels/qqmldelegatemodel_p_p.h @@ -104,7 +104,7 @@ class QQmlDelegateModelItem : public QObject Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12) Q_PROPERTY(QObject *model READ modelObject CONSTANT) public: - QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, + QQmlDelegateModelItem(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, QQmlAdaptorModel::Accessors *accessor, int modelIndex, int row, int column); ~QQmlDelegateModelItem(); @@ -148,7 +148,7 @@ public: static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg); QV4::ExecutionEngine *v4; - QQmlDelegateModelItemMetaType * const metaType; + QQmlRefPointer<QQmlDelegateModelItemMetaType> const metaType; QQmlContextDataRef contextData; QPointer<QObject> object; QPointer<QQmlDelegateModelAttached> attached; diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index 2c05b04429..e58fc19178 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -2786,10 +2786,12 @@ bool QQmlListModelParser::applyProperty( QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr)); QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id])); - QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0); - QJSValue v; - QJSValuePrivate::setValue(&v, v4, result); + QV4::ScopedValue result(scope, function->call(v4->globalObject, nullptr, 0)); + if (v4->hasException) + v4->catchException(); + else + QJSValuePrivate::setValue(&v, v4, result->asReturnedValue()); value.setValue<QJSValue>(v); } else { QByteArray script = scriptStr.toUtf8(); diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp index b4d1e61e31..29c307a47a 100644 --- a/src/qmlmodels/qqmltableinstancemodel.cpp +++ b/src/qmlmodels/qqmltableinstancemodel.cpp @@ -78,7 +78,8 @@ void QQmlTableInstanceModel::deleteModelItemLater(QQmlDelegateModelItem *modelIt QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent) : QQmlInstanceModel(*(new QObjectPrivate()), parent) , m_qmlContext(qmlContext) - , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList())) + , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList()), + QQmlRefPointer<QQmlDelegateModelItemMetaType>::Adopt) { } diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h index d924455918..661ea3a3aa 100644 --- a/src/qmlmodels/qqmltableinstancemodel_p.h +++ b/src/qmlmodels/qqmltableinstancemodel_p.h @@ -133,7 +133,7 @@ private: QQmlAbstractDelegateComponent *m_delegateChooser = nullptr; QQmlComponent *m_delegate = nullptr; QPointer<QQmlContext> m_qmlContext; - QQmlDelegateModelItemMetaType *m_metaType; + QQmlRefPointer<QQmlDelegateModelItemMetaType> m_metaType; QHash<int, QQmlDelegateModelItem *> m_modelItems; QQmlReusableDelegateModelItemsPool m_reusableItemsPool; diff --git a/src/quick/doc/snippets/qml/xmlrole.xml b/src/quick/doc/snippets/qml/xmlrole.xml deleted file mode 100644 index 70280e067d..0000000000 --- a/src/quick/doc/snippets/qml/xmlrole.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> -<catalog> - <book type="Online" wanted="true"> - <title>Qt 5 Cadaques</title> - <year>2014</year> - <author>Juergen Bocklage-Ryannel</author> - <author>Johan Thelin</author> - </book> - <book type="Hardcover"> - <title>C++ GUI Programming with Qt 4</title> - <year>2006</year> - <author>Jasmin Blanchette</author> - <author>Mark Summerfield</author> - </book> - <book type="Paperback"> - <title>Programming with Qt</title> - <year>2002</year> - <author>Matthias Kalle Dalheimer</author> - </book> - </catalog> diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 0d30606ef7..7fb392233e 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -197,8 +197,10 @@ void QQuickItemView::setModel(const QVariant &m) disconnect(d->model, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*))); disconnect(d->model, SIGNAL(createdItem(int,QObject*)), this, SLOT(createdItem(int,QObject*))); disconnect(d->model, SIGNAL(destroyingItem(QObject*)), this, SLOT(destroyingItem(QObject*))); - disconnect(d->model, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *))); - disconnect(d->model, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *))); + if (QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(d->model)) { + disconnect(delegateModel, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *))); + disconnect(delegateModel, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *))); + } } QQmlInstanceModel *oldModel = d->model; @@ -234,8 +236,10 @@ void QQuickItemView::setModel(const QVariant &m) connect(d->model, SIGNAL(createdItem(int,QObject*)), this, SLOT(createdItem(int,QObject*))); connect(d->model, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*))); connect(d->model, SIGNAL(destroyingItem(QObject*)), this, SLOT(destroyingItem(QObject*))); - connect(d->model, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *))); - connect(d->model, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *))); + if (QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(d->model)) { + connect(delegateModel, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *))); + connect(delegateModel, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *))); + } if (isComponentComplete()) { d->updateSectionCriteria(); d->refill(); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 1f6f24e419..b204cb3417 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -4694,6 +4694,18 @@ void QQuickTextInput::clear() These properties hold the padding around the content. This space is reserved in addition to the contentWidth and contentHeight. + + The individual padding properties assume the value of the \c padding + property unless they are set explicitly. For example, if \c padding is + set to \c 4 and \c leftPadding to \c 8, \c 8 will be used as the left + padding. + + \note If an explicit width or height is given to a TextInput, care must be + taken to ensure it is large enough to accommodate the relevant padding + values. For example: if \c topPadding and \c bottomPadding are set to + \c 10, but the height of the TextInput is only set to \c 20, the text will + not have enough vertical space in which to be rendered, and will appear + clipped. */ qreal QQuickTextInput::padding() const { diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 2eee98a738..3bb6c19dce 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4513,7 +4513,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText } - +#if QT_DEPRECATED_SINCE(5, 15) /*! Creates a new QSGTexture object from an existing OpenGL texture \a id and \a size. @@ -4535,6 +4535,8 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText \note This function has no effect when running on the RHI graphics abstraction. Use createTextureFromNativeObject() instead. + \obsolete + \sa sceneGraphInitialized(), QSGTexture */ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const @@ -4561,6 +4563,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create #endif return nullptr; } +#endif /*! \enum QQuickWindow::NativeObjectType diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 56d50cec2a..d22bba4512 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -157,7 +157,12 @@ public: // Scene graph specific functions QSGTexture *createTextureFromImage(const QImage &image) const; QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const; + +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X("Use createTextureFromNativeObject() instead") QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; +#endif + QSGTexture *createTextureFromNativeObject(NativeObjectType type, const void *nativeObjectPtr, int nativeLayout, diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 375d0265e8..74ee52b1d3 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2827,11 +2827,11 @@ void QQuickPathText::updatePath() const if (!_path.isEmpty()) return; - _path.addText(_x, _y, _font, _text); + _path.addText(0.0, 0.0, _font, _text); // Account for distance from baseline to top, since addText() takes baseline position QRectF brect = _path.boundingRect(); - _path.translate(0.0, -brect.y()); + _path.translate(_x, _y - brect.y()); } void QQuickPathText::addToPath(QPainterPath &path) diff --git a/tests/auto/qml/ecmascripttests/BLACKLIST b/tests/auto/qml/ecmascripttests/BLACKLIST deleted file mode 100644 index 1ed255e9e2..0000000000 --- a/tests/auto/qml/ecmascripttests/BLACKLIST +++ /dev/null @@ -1,4 +0,0 @@ -[runInterpreted] -macos ci -[runJitted] -macos diff --git a/tests/auto/qml/qqmlcomponent/data/RequiredDefault.qml b/tests/auto/qml/qqmlcomponent/data/RequiredDefault.qml new file mode 100644 index 0000000000..7e8f225a52 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/RequiredDefault.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + required default property Text requiredDefault +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredDefault.1.qml b/tests/auto/qml/qqmlcomponent/data/requiredDefault.1.qml new file mode 100644 index 0000000000..68dff22f33 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredDefault.1.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +RequiredDefault { + Text {text: "Hello, world!"} +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredDefault.2.qml b/tests/auto/qml/qqmlcomponent/data/requiredDefault.2.qml new file mode 100644 index 0000000000..a6c4e8ea3f --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredDefault.2.qml @@ -0,0 +1,3 @@ +import QtQuick 2.15 + +RequiredDefault { } diff --git a/tests/auto/qml/qqmlcomponent/data/requiredDefault.3.qml b/tests/auto/qml/qqmlcomponent/data/requiredDefault.3.qml new file mode 100644 index 0000000000..19b3271858 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredDefault.3.qml @@ -0,0 +1,6 @@ +import QtQuick 2.15 +import qt.test 1.0 + +RequiredDefaultCpp { + Text {text: "Hello, world!"} +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredDefault.4.qml b/tests/auto/qml/qqmlcomponent/data/requiredDefault.4.qml new file mode 100644 index 0000000000..acd56db328 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredDefault.4.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import qt.test 1.0 + +RequiredDefaultCpp { } diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 2acc62ca28..43cbd93396 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -671,8 +671,20 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault() QVERIFY(!c); } +class RequiredDefaultCpp : public QObject +{ + Q_OBJECT +public: + Q_PROPERTY(QQuickItem *defaultProperty MEMBER m_defaultProperty NOTIFY defaultPropertyChanged REQUIRED) + Q_SIGNAL void defaultPropertyChanged(); + Q_CLASSINFO("DefaultProperty", "defaultProperty") +private: + QQuickItem *m_defaultProperty = nullptr; +}; + void tst_qqmlcomponent::testRequiredProperties_data() { + qmlRegisterType<RequiredDefaultCpp>("qt.test", 1, 0, "RequiredDefaultCpp"); QTest::addColumn<QUrl>("testFile"); QTest::addColumn<bool>("shouldSucceed"); QTest::addColumn<QString>("errorMsg"); @@ -687,6 +699,10 @@ void tst_qqmlcomponent::testRequiredProperties_data() QTest::addRow("setLater") << testFileUrl("requiredSetLater.qml") << true << ""; QTest::addRow("setViaAliasToSubcomponent") << testFileUrl("setViaAliasToSubcomponent.qml") << true << ""; QTest::addRow("aliasToSubcomponentNotSet") << testFileUrl("aliasToSubcomponentNotSet.qml") << false << "It can be set via the alias property i_alias"; + QTest::addRow("required default set") << testFileUrl("requiredDefault.1.qml") << true << ""; + QTest::addRow("required default not set") << testFileUrl("requiredDefault.2.qml") << false << "Required property requiredDefault was not initialized"; + QTest::addRow("required default set (C++)") << testFileUrl("requiredDefault.3.qml") << true << ""; + QTest::addRow("required default not set (C++)") << testFileUrl("requiredDefault.4.qml") << false << "Required property defaultProperty was not initialized"; } diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index ab4c083b65..cfbbd2a94c 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -997,6 +997,11 @@ public: SomeQObjectClass() : QObject(nullptr){} }; +class Dayfly : public QObject +{ + Q_OBJECT +}; + void tst_qqmlengine::singletonInstance() { QQmlEngine engine; @@ -1115,7 +1120,7 @@ void tst_qqmlengine::singletonInstance() { // deleted object - auto dayfly = new QObject{}; + auto dayfly = new Dayfly{}; auto id = qmlRegisterSingletonInstance("Vanity", 1, 0, "Dayfly", dayfly); delete dayfly; QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: The registered singleton has already been deleted. Ensure that it outlives the engine."); diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml new file mode 100644 index 0000000000..76673f6409 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +MyClass {test: 42} diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml new file mode 100644 index 0000000000..d4c059581c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +Child2 {test: test2; test2: 18} diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml new file mode 100644 index 0000000000..082e22dc3f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +Child2 { test: 13 } diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml new file mode 100644 index 0000000000..6602684542 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +Child {test: 42} diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml new file mode 100644 index 0000000000..5971b0c263 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +Child {} diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml new file mode 100644 index 0000000000..dab48a3d71 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 +import example.org 1.0 + +MyClass {} diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml deleted file mode 100644 index 534322215f..0000000000 --- a/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml +++ /dev/null @@ -1,4 +0,0 @@ -import QtQuick 2.13 -Item { - default required property int test // cannot have required default property -} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4d2f773dbf..5027c0825f 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -133,6 +133,8 @@ private slots: void autoComponentCreationInGroupProperty(); void propertyValueSource(); void requiredProperty(); + void requiredPropertyFromCpp_data(); + void requiredPropertyFromCpp(); void attachedProperties(); void dynamicObjects(); void customVariantTypes(); @@ -1673,9 +1675,74 @@ void tst_qqmllanguage::requiredProperty() QQmlComponent component(&engine, testFileUrl("requiredProperties.2.qml")); QVERIFY(!component.errors().empty()); } +} + +class MyClassWithRequiredProperty : public QObject +{ +public: + Q_OBJECT + Q_PROPERTY(int test MEMBER m_test REQUIRED NOTIFY testChanged) + Q_SIGNAL void testChanged(); +private: + int m_test; +}; + +class ChildClassWithoutOwnRequired : public MyClassWithRequiredProperty +{ +public: + Q_OBJECT + Q_PROPERTY(int test2 MEMBER m_test2 NOTIFY test2Changed) + Q_SIGNAL void test2Changed(); +private: + int m_test2; +}; + +class ChildClassWithOwnRequired : public MyClassWithRequiredProperty +{ +public: + Q_OBJECT + Q_PROPERTY(int test2 MEMBER m_test2 REQUIRED NOTIFY test2Changed) + Q_SIGNAL void test2Changed(); +private: + int m_test2; +}; + +void tst_qqmllanguage::requiredPropertyFromCpp_data() +{ + qmlRegisterType<MyClassWithRequiredProperty>("example.org", 1, 0, "MyClass"); + qmlRegisterType<ChildClassWithoutOwnRequired>("example.org", 1, 0, "Child"); + qmlRegisterType<ChildClassWithOwnRequired>("example.org", 1, 0, "Child2"); + + + QTest::addColumn<QUrl>("setFile"); + QTest::addColumn<QUrl>("notSetFile"); + QTest::addColumn<QString>("errorMessage"); + QTest::addColumn<int>("expectedValue"); + + QTest::addRow("direct") << testFileUrl("cppRequiredProperty.qml") << testFileUrl("cppRequiredPropertyNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42; + QTest::addRow("in parent") << testFileUrl("cppRequiredPropertyInParent.qml") << testFileUrl("cppRequiredPropertyInParentNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42; + QTest::addRow("in child and parent") << testFileUrl("cppRequiredPropertyInChildAndParent.qml") << testFileUrl("cppRequiredPropertyInChildAndParentNotSet.qml") << QString(":4 Required property test2 was not initialized\n") << 18; +} + +void tst_qqmllanguage::requiredPropertyFromCpp() +{ + QQmlEngine engine; + QFETCH(QUrl, setFile); + QFETCH(QUrl, notSetFile); + QFETCH(QString, errorMessage); + QFETCH(int, expectedValue); { - QQmlComponent component(&engine, testFileUrl("requiredProperties.3.qml")); - QVERIFY(!component.errors().empty()); + QQmlComponent comp(&engine, notSetFile); + QScopedPointer<QObject> o { comp.create() }; + QVERIFY(o.isNull()); + QVERIFY(comp.isError()); + QCOMPARE(comp.errorString(), notSetFile.toString() + errorMessage); + } + { + QQmlComponent comp(&engine, setFile); + QScopedPointer<QObject> o { comp.create() }; + QVERIFY(!o.isNull()); + QCOMPARE(o->property("test").toInt(), expectedValue); } } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index f039ccc110..83e173f379 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -1224,10 +1224,10 @@ void tst_qqmlproperty::read() } { QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml")); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QQmlProperty p(object, "test", &engine); + QQmlProperty p(object.data(), "test", &engine); QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); QVERIFY(p.propertyType() != QMetaType::QObjectStar); @@ -1239,10 +1239,10 @@ void tst_qqmlproperty::read() } { // static QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml")); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QVariant v = QQmlProperty::read(object, "test", &engine); + QVariant v = QQmlProperty::read(object.data(), "test", &engine); QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); QCOMPARE(qvariant_cast<QObject *>(v)->property("a").toInt(), 10); QCOMPARE(qvariant_cast<QObject *>(v)->property("b").toInt(), 19); @@ -1252,41 +1252,38 @@ void tst_qqmlproperty::read() { QQmlComponent component(&engine); component.setData("import Test 1.0\nMyContainer { }", QUrl()); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QQmlProperty p(object, "MyContainer.foo", qmlContext(object)); + QQmlProperty p(object.data(), "MyContainer.foo", qmlContext(object.data())); QCOMPARE(p.read(), QVariant(13)); - delete object; } { QQmlComponent component(&engine); component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl()); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QQmlProperty p(object, "MyContainer.foo", qmlContext(object)); + QQmlProperty p(object.data(), "MyContainer.foo", qmlContext(object.data())); QCOMPARE(p.read(), QVariant(10)); - delete object; } { QQmlComponent component(&engine); component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QQmlProperty p(object, "Foo.MyContainer.foo", qmlContext(object)); + QQmlProperty p(object.data(), "Foo.MyContainer.foo", qmlContext(object.data())); QCOMPARE(p.read(), QVariant(10)); - delete object; } { // static QQmlComponent component(&engine); component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QCOMPARE(QQmlProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10)); - delete object; + QCOMPARE(QQmlProperty::read(object.data(), "Foo.MyContainer.foo", + qmlContext(object.data())), QVariant(10)); } } @@ -1447,11 +1444,12 @@ void tst_qqmlproperty::write() { // QChar -> QString QQmlComponent component(&engine); component.setData("import Test 1.0\nPropertyObject { stringProperty: constQChar }", QUrl()); - PropertyObject *obj = qobject_cast<PropertyObject*>(component.create()); - QVERIFY(obj != nullptr); - if (obj) { - QQmlProperty stringProperty(obj, "stringProperty"); - QCOMPARE(stringProperty.read(), QVariant(QString(obj->constQChar()))); + QScopedPointer<QObject> object(component.create()); + PropertyObject *propertyObject = qobject_cast<PropertyObject*>(object.data()); + QVERIFY(propertyObject != nullptr); + if (propertyObject) { + QQmlProperty stringProperty(propertyObject, "stringProperty"); + QCOMPARE(stringProperty.read(), QVariant(QString(propertyObject->constQChar()))); } } @@ -1628,29 +1626,32 @@ void tst_qqmlproperty::writeObjectToList() { QQmlComponent containerComponent(&engine); containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl()); - MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create()); + QScopedPointer<QObject> object(containerComponent.create()); + MyContainer *container = qobject_cast<MyContainer*>(object.data()); QVERIFY(container != nullptr); QQmlListReference list(container, "children"); QCOMPARE(list.count(), 1); - MyQmlObject *object = new MyQmlObject; + QScopedPointer<MyQmlObject> childObject(new MyQmlObject); QQmlProperty prop(container, "children"); - prop.write(QVariant::fromValue(object)); + prop.write(QVariant::fromValue(childObject.data())); QCOMPARE(list.count(), 1); - QCOMPARE(list.at(0), qobject_cast<QObject*>(object)); + QCOMPARE(list.at(0), qobject_cast<QObject*>(childObject.data())); } void tst_qqmlproperty::writeListToList() { QQmlComponent containerComponent(&engine); containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl()); - MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create()); + QScopedPointer<QObject> object(containerComponent.create()); + MyContainer *container = qobject_cast<MyContainer*>(object.data()); QVERIFY(container != nullptr); QQmlListReference list(container, "children"); QCOMPARE(list.count(), 1); QList<QObject*> objList; - objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject(); + objList << new MyQmlObject(this) << new MyQmlObject(this) + << new MyQmlObject(this) << new MyQmlObject(this); QQmlProperty prop(container, "children"); prop.write(QVariant::fromValue(objList)); QCOMPARE(list.count(), 4); @@ -1828,10 +1829,11 @@ void tst_qqmlproperty::crashOnValueProperty() QQmlComponent component(engine); component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }", QUrl()); - PropertyObject *obj = qobject_cast<PropertyObject*>(component.create()); - QVERIFY(obj != nullptr); + QScopedPointer<QObject> object(component.create()); + PropertyObject *propertyObject = qobject_cast<PropertyObject*>(object.data()); + QVERIFY(propertyObject != nullptr); - QQmlProperty p(obj, "wrectProperty.x", qmlContext(obj)); + QQmlProperty p(propertyObject, "wrectProperty.x", qmlContext(propertyObject)); QCOMPARE(p.name(), QString("wrectProperty.x")); QCOMPARE(p.read(), QVariant(10)); diff --git a/tests/auto/qml/qqmlvaluetypes/testtypes.h b/tests/auto/qml/qqmlvaluetypes/testtypes.h index e11d831236..78797f06b1 100644 --- a/tests/auto/qml/qqmlvaluetypes/testtypes.h +++ b/tests/auto/qml/qqmlvaluetypes/testtypes.h @@ -48,6 +48,8 @@ #include <private/qqmlproperty_p.h> #include <private/qqmlpropertyvalueinterceptor_p.h> +Q_DECLARE_METATYPE(QQmlProperty) + class MyTypeObject : public QObject { Q_OBJECT diff --git a/tests/auto/quickwidgets/qquickwidget/BLACKLIST b/tests/auto/quickwidgets/qquickwidget/BLACKLIST index 18ea65bb72..095e9ee484 100644 --- a/tests/auto/quickwidgets/qquickwidget/BLACKLIST +++ b/tests/auto/quickwidgets/qquickwidget/BLACKLIST @@ -1,3 +1,5 @@ [tabKey] opensuse-42.3 opensuse-leap +[enterLeave] +macos diff --git a/tests/manual/scenegraph_lancelot/data/shape/shape_text.qml b/tests/manual/scenegraph_lancelot/data/shape/shape_text.qml new file mode 100644 index 0000000000..37367054b5 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/shape/shape_text.qml @@ -0,0 +1,91 @@ +import QtQuick 2.15 +import QtQuick.Shapes 1.0 + +Item { + width: 320 + height: 480 + + Column { + Item { + width: 200 + height: 160 + + Shape { + anchors.fill: parent + vendorExtensionsEnabled: false + + ShapePath { + fillColor: "transparent" + strokeColor: "blue" + strokeStyle: ShapePath.DashLine + strokeWidth: 4 + + PathText { + x: 96 + y: 10 + font.pixelSize: 120 + text: "Qt" + } + } + } + } + + Item { + width: 200 + height: 160 + + Rectangle { + anchors.fill: parent + color: "blue" + } + + Shape { + anchors.fill: parent + vendorExtensionsEnabled: false + + ShapePath { + fillColor: "red" + strokeColor: "blue" + strokeStyle: ShapePath.DashLine + capStyle: ShapePath.RoundCap + strokeWidth: 8 + + PathText { + x: 96; y: 10 + font.pixelSize: 150 + text: "Qt" + } + } + } + } + + Item { + width: 200 + height: 160 + + Shape { + anchors.fill: parent + vendorExtensionsEnabled: false + + ShapePath { + fillGradient: LinearGradient { + x1: 0; x2: 200; y1: 0; y2: 160 + spread: ShapeGradient.PadSpread + GradientStop { position: 0.0; color: "red"; } + GradientStop { position: 1.0; color: "green"; } + } + strokeColor: "blue" + strokeStyle: ShapePath.DashLine + joinStyle: ShapePath.RoundJoin + strokeWidth: 4 + + PathText { + x: 96; y: 10 + font.pixelSize: 150 + text: "Qt" + } + } + } + } + } +} |