QML: Allow conversion of symbols to QVariant
We produce their descriptiveString or simply a QVariant containing a QJSValue, depending on whether we're supposed to convert objects without equivalent C++ type or not. Pick-to: 6.6 6.5 6.2 Fixes: QTBUG-113854 Change-Id: I22b6038c936d860fdd8aa227f9dfe704e3265a77 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
e50b2069f9
commit
8c451bba7a
|
@ -163,10 +163,11 @@
|
|||
/*!
|
||||
\enum QJSValue::ObjectConversionBehavior
|
||||
|
||||
This enum is used to specify how JavaScript objects without an equivalent
|
||||
This enum is used to specify how JavaScript objects and symbols without an equivalent
|
||||
native Qt type should be treated when converting to QVariant.
|
||||
|
||||
\value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted.
|
||||
Symbols are converted to QString.
|
||||
|
||||
\value RetainJSObjects The value is retained as QJSValue wrapped in QVariant.
|
||||
*/
|
||||
|
|
|
@ -1478,7 +1478,9 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
|
|||
// Variant conversion code
|
||||
|
||||
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
|
||||
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
|
||||
static QVariant toVariant(
|
||||
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols,
|
||||
V4ObjectSet *visitedObjects);
|
||||
static QObject *qtObjectFromJS(const QV4::Value &value);
|
||||
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
|
||||
static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
|
||||
|
@ -1491,7 +1493,7 @@ static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &
|
|||
}
|
||||
|
||||
static QVariant toVariant(
|
||||
const QV4::Value &value, QMetaType metaType, bool createJSValueForObjects,
|
||||
const QV4::Value &value, QMetaType metaType, bool createJSValueForObjectsAndSymbols,
|
||||
V4ObjectSet *visitedObjects)
|
||||
{
|
||||
Q_ASSERT (!value.isEmpty());
|
||||
|
@ -1634,6 +1636,9 @@ static QVariant toVariant(
|
|||
return *ld->d()->locale;
|
||||
#endif
|
||||
if (const QV4::DateObject *d = value.as<DateObject>()) {
|
||||
// NOTE: since we convert QTime to JS Date,
|
||||
// round trip will change the variant type (to QDateTime)!
|
||||
|
||||
if (metaType == QMetaType::fromType<QDate>())
|
||||
return DateObject::dateTimeToDate(d->toQDateTime());
|
||||
|
||||
|
@ -1649,7 +1654,11 @@ static QVariant toVariant(
|
|||
return d->toQUrl();
|
||||
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
|
||||
return d->asByteArray();
|
||||
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
|
||||
if (const Symbol *symbol = value.as<Symbol>()) {
|
||||
return createJSValueForObjectsAndSymbols
|
||||
? QVariant::fromValue(QJSValuePrivate::fromReturnedValue(symbol->asReturnedValue()))
|
||||
: symbol->descriptiveString();
|
||||
}
|
||||
|
||||
const QV4::Object *object = value.as<QV4::Object>();
|
||||
Q_ASSERT(object);
|
||||
|
@ -1667,16 +1676,17 @@ static QVariant toVariant(
|
|||
return result;
|
||||
}
|
||||
|
||||
if (createJSValueForObjects)
|
||||
if (createJSValueForObjectsAndSymbols)
|
||||
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
|
||||
|
||||
return objectToVariant(o, visitedObjects);
|
||||
}
|
||||
|
||||
|
||||
QVariant ExecutionEngine::toVariant(const Value &value, QMetaType typeHint, bool createJSValueForObjects)
|
||||
QVariant ExecutionEngine::toVariant(
|
||||
const Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols)
|
||||
{
|
||||
return ::toVariant(value, typeHint, createJSValueForObjects, nullptr);
|
||||
return ::toVariant(value, typeHint, createJSValueForObjectsAndSymbols, nullptr);
|
||||
}
|
||||
|
||||
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects)
|
||||
|
@ -1707,7 +1717,8 @@ static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObject
|
|||
int length = a->getLength();
|
||||
for (int ii = 0; ii < length; ++ii) {
|
||||
v = a->get(ii);
|
||||
list << ::toVariant(v, QMetaType {}, /*createJSValueForObjects*/false, visitedObjects);
|
||||
list << ::toVariant(v, QMetaType {}, /*createJSValueForObjectsAndSymbols*/false,
|
||||
visitedObjects);
|
||||
}
|
||||
|
||||
result = list;
|
||||
|
@ -1725,7 +1736,7 @@ static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObject
|
|||
QString key = name->toQStringNoThrow();
|
||||
map.insert(key, ::toVariant(
|
||||
val, /*type hint*/ QMetaType {},
|
||||
/*createJSValueForObjects*/false, visitedObjects));
|
||||
/*createJSValueForObjectsAndSymbols*/false, visitedObjects));
|
||||
}
|
||||
|
||||
result = map;
|
||||
|
@ -2589,7 +2600,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
|||
const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
|
||||
if (a) {
|
||||
*reinterpret_cast<QVariantList *>(data) = ExecutionEngine::toVariant(
|
||||
*a, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false).toList();
|
||||
*a, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false)
|
||||
.toList();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -2605,7 +2617,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
|||
case QMetaType::QVariant:
|
||||
if (value.as<QV4::Managed>()) {
|
||||
*reinterpret_cast<QVariant*>(data) = ExecutionEngine::toVariant(
|
||||
value, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false);
|
||||
value, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false);
|
||||
} else if (value.isNull()) {
|
||||
*reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
|
||||
} else if (value.isUndefined()) {
|
||||
|
|
|
@ -663,7 +663,7 @@ public:
|
|||
|
||||
// variant conversions
|
||||
static QVariant toVariant(
|
||||
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects = true);
|
||||
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols = true);
|
||||
QV4::ReturnedValue fromVariant(const QVariant &);
|
||||
QV4::ReturnedValue fromVariant(
|
||||
const QVariant &variant, Heap::Object *parent, int property, uint flags);
|
||||
|
|
|
@ -304,6 +304,8 @@ private slots:
|
|||
void callWithSpreadOnElement();
|
||||
void spreadNoOverflow();
|
||||
|
||||
void symbolToVariant();
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QJSValue throwingCppMethod1();
|
||||
Q_INVOKABLE void throwingCppMethod2();
|
||||
|
@ -6083,6 +6085,19 @@ void tst_QJSEngine::spreadNoOverflow()
|
|||
QCOMPARE(result.errorType(), QJSValue::RangeError);
|
||||
}
|
||||
|
||||
void tst_QJSEngine::symbolToVariant()
|
||||
{
|
||||
QJSEngine engine;
|
||||
const QJSValue val = engine.newSymbol("asymbol");
|
||||
QCOMPARE(val.toVariant(), QStringLiteral("Symbol(asymbol)"));
|
||||
|
||||
const QVariant retained = val.toVariant(QJSValue::RetainJSObjects);
|
||||
QCOMPARE(retained.metaType(), QMetaType::fromType<QJSValue>());
|
||||
QVERIFY(retained.value<QJSValue>().strictlyEquals(val));
|
||||
|
||||
QCOMPARE(val.toVariant(QJSValue::ConvertJSObjects), QStringLiteral("Symbol(asymbol)"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QJSEngine)
|
||||
|
||||
#include "tst_qjsengine.moc"
|
||||
|
|
Loading…
Reference in New Issue