Skip to content

Commit 8c451bb

Browse files
committed
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 <[email protected]>
1 parent e50b206 commit 8c451bb

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

src/qml/jsapi/qjsvalue.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,11 @@
163163
/*!
164164
\enum QJSValue::ObjectConversionBehavior
165165
166-
This enum is used to specify how JavaScript objects without an equivalent
166+
This enum is used to specify how JavaScript objects and symbols without an equivalent
167167
native Qt type should be treated when converting to QVariant.
168168
169169
\value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted.
170+
Symbols are converted to QString.
170171
171172
\value RetainJSObjects The value is retained as QJSValue wrapped in QVariant.
172173
*/

src/qml/jsruntime/qv4engine.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,9 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
14781478
// Variant conversion code
14791479

14801480
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
1481-
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
1481+
static QVariant toVariant(
1482+
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols,
1483+
V4ObjectSet *visitedObjects);
14821484
static QObject *qtObjectFromJS(const QV4::Value &value);
14831485
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
14841486
static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
@@ -1491,7 +1493,7 @@ static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &
14911493
}
14921494

14931495
static QVariant toVariant(
1494-
const QV4::Value &value, QMetaType metaType, bool createJSValueForObjects,
1496+
const QV4::Value &value, QMetaType metaType, bool createJSValueForObjectsAndSymbols,
14951497
V4ObjectSet *visitedObjects)
14961498
{
14971499
Q_ASSERT (!value.isEmpty());
@@ -1634,6 +1636,9 @@ static QVariant toVariant(
16341636
return *ld->d()->locale;
16351637
#endif
16361638
if (const QV4::DateObject *d = value.as<DateObject>()) {
1639+
// NOTE: since we convert QTime to JS Date,
1640+
// round trip will change the variant type (to QDateTime)!
1641+
16371642
if (metaType == QMetaType::fromType<QDate>())
16381643
return DateObject::dateTimeToDate(d->toQDateTime());
16391644

@@ -1649,7 +1654,11 @@ static QVariant toVariant(
16491654
return d->toQUrl();
16501655
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
16511656
return d->asByteArray();
1652-
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
1657+
if (const Symbol *symbol = value.as<Symbol>()) {
1658+
return createJSValueForObjectsAndSymbols
1659+
? QVariant::fromValue(QJSValuePrivate::fromReturnedValue(symbol->asReturnedValue()))
1660+
: symbol->descriptiveString();
1661+
}
16531662

16541663
const QV4::Object *object = value.as<QV4::Object>();
16551664
Q_ASSERT(object);
@@ -1667,16 +1676,17 @@ static QVariant toVariant(
16671676
return result;
16681677
}
16691678

1670-
if (createJSValueForObjects)
1679+
if (createJSValueForObjectsAndSymbols)
16711680
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
16721681

16731682
return objectToVariant(o, visitedObjects);
16741683
}
16751684

16761685

1677-
QVariant ExecutionEngine::toVariant(const Value &value, QMetaType typeHint, bool createJSValueForObjects)
1686+
QVariant ExecutionEngine::toVariant(
1687+
const Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols)
16781688
{
1679-
return ::toVariant(value, typeHint, createJSValueForObjects, nullptr);
1689+
return ::toVariant(value, typeHint, createJSValueForObjectsAndSymbols, nullptr);
16801690
}
16811691

16821692
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects)
@@ -1707,7 +1717,8 @@ static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObject
17071717
int length = a->getLength();
17081718
for (int ii = 0; ii < length; ++ii) {
17091719
v = a->get(ii);
1710-
list << ::toVariant(v, QMetaType {}, /*createJSValueForObjects*/false, visitedObjects);
1720+
list << ::toVariant(v, QMetaType {}, /*createJSValueForObjectsAndSymbols*/false,
1721+
visitedObjects);
17111722
}
17121723

17131724
result = list;
@@ -1725,7 +1736,7 @@ static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObject
17251736
QString key = name->toQStringNoThrow();
17261737
map.insert(key, ::toVariant(
17271738
val, /*type hint*/ QMetaType {},
1728-
/*createJSValueForObjects*/false, visitedObjects));
1739+
/*createJSValueForObjectsAndSymbols*/false, visitedObjects));
17291740
}
17301741

17311742
result = map;
@@ -2589,7 +2600,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
25892600
const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
25902601
if (a) {
25912602
*reinterpret_cast<QVariantList *>(data) = ExecutionEngine::toVariant(
2592-
*a, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false).toList();
2603+
*a, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false)
2604+
.toList();
25932605
return true;
25942606
}
25952607
break;
@@ -2605,7 +2617,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
26052617
case QMetaType::QVariant:
26062618
if (value.as<QV4::Managed>()) {
26072619
*reinterpret_cast<QVariant*>(data) = ExecutionEngine::toVariant(
2608-
value, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false);
2620+
value, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false);
26092621
} else if (value.isNull()) {
26102622
*reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
26112623
} else if (value.isUndefined()) {

src/qml/jsruntime/qv4engine_p.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ struct Q_QML_EXPORT ExecutionEngine : public EngineBase
663663

664664
// variant conversions
665665
static QVariant toVariant(
666-
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects = true);
666+
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols = true);
667667
QV4::ReturnedValue fromVariant(const QVariant &);
668668
QV4::ReturnedValue fromVariant(
669669
const QVariant &variant, Heap::Object *parent, int property, uint flags);

tests/auto/qml/qjsengine/tst_qjsengine.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ private slots:
304304
void callWithSpreadOnElement();
305305
void spreadNoOverflow();
306306

307+
void symbolToVariant();
308+
307309
public:
308310
Q_INVOKABLE QJSValue throwingCppMethod1();
309311
Q_INVOKABLE void throwingCppMethod2();
@@ -6083,6 +6085,19 @@ void tst_QJSEngine::spreadNoOverflow()
60836085
QCOMPARE(result.errorType(), QJSValue::RangeError);
60846086
}
60856087

6088+
void tst_QJSEngine::symbolToVariant()
6089+
{
6090+
QJSEngine engine;
6091+
const QJSValue val = engine.newSymbol("asymbol");
6092+
QCOMPARE(val.toVariant(), QStringLiteral("Symbol(asymbol)"));
6093+
6094+
const QVariant retained = val.toVariant(QJSValue::RetainJSObjects);
6095+
QCOMPARE(retained.metaType(), QMetaType::fromType<QJSValue>());
6096+
QVERIFY(retained.value<QJSValue>().strictlyEquals(val));
6097+
6098+
QCOMPARE(val.toVariant(QJSValue::ConvertJSObjects), QStringLiteral("Symbol(asymbol)"));
6099+
}
6100+
60866101
QTEST_MAIN(tst_QJSEngine)
60876102

60886103
#include "tst_qjsengine.moc"

0 commit comments

Comments
 (0)