Add a QJSManagedValue
A QJSManagedValue is a view on a QJSValue which always knows the engine the value belongs to. This allows us to implement the JavaScript semantics of the various QJSValue methods in a much more rigorous way. [ChangeLog][QtQml] The new QJSManagedValue should be used instead of QJSValue for manipulating properties and prototypes of JavaScript values, as well as for calling JavaScript functions. Change-Id: I9d445ffcf68dfa72dba9bae0818e83c80665ad66 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
d5ac54da62
commit
6f181768a3
|
@ -114,6 +114,7 @@ qt_internal_add_module(Qml
|
|||
debugger/qqmlprofiler_p.h
|
||||
inlinecomponentutils_p.h
|
||||
jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h
|
||||
jsapi/qjsmanagedvalue.cpp jsapi/qjsmanagedvalue.h
|
||||
jsapi/qjsprimitivevalue.cpp jsapi/qjsprimitivevalue.h
|
||||
jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h
|
||||
jsapi/qjsvalueiterator.cpp jsapi/qjsvalueiterator.h jsapi/qjsvalueiterator_p.h
|
||||
|
|
|
@ -115,6 +115,7 @@ qt_internal_add_module(Qml
|
|||
debugger/qqmlprofiler_p.h
|
||||
inlinecomponentutils_p.h
|
||||
jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h
|
||||
jsapi/qjsmanagedvalue.cpp jsapi/qjsmanagedvalue.h
|
||||
jsapi/qjsprimitivevalue.cpp jsapi/qjsprimitivevalue.h
|
||||
jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h
|
||||
jsapi/qjsvalueiterator.cpp jsapi/qjsvalueiterator.h jsapi/qjsvalueiterator_p.h
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
SOURCES += \
|
||||
$$PWD/qjsengine.cpp \
|
||||
$$PWD/qjsmanagedvalue.cpp \
|
||||
$$PWD/qjsprimitivevalue.cpp \
|
||||
$$PWD/qjsvalue.cpp \
|
||||
$$PWD/qjsvalueiterator.cpp \
|
||||
|
@ -7,6 +8,7 @@ SOURCES += \
|
|||
HEADERS += \
|
||||
$$PWD/qjsengine.h \
|
||||
$$PWD/qjsengine_p.h \
|
||||
$$PWD/qjsmanagedvalue.h \
|
||||
$$PWD/qjsprimitivevalue.h \
|
||||
$$PWD/qjsvalue.h \
|
||||
$$PWD/qjsvalue_p.h \
|
||||
|
|
|
@ -728,6 +728,13 @@ QJSValue QJSEngine::globalObject() const
|
|||
return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
|
||||
}
|
||||
|
||||
QJSManagedValue QJSEngine::createManaged(QMetaType type, const void *ptr)
|
||||
{
|
||||
QJSManagedValue result(m_v4Engine);
|
||||
*result.d = m_v4Engine->metaTypeToJS(type.id(), ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* used by QJSEngine::toScriptValue
|
||||
|
@ -739,6 +746,11 @@ QJSValue QJSEngine::create(int type, const void *ptr)
|
|||
return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
|
||||
}
|
||||
|
||||
bool QJSEngine::convertManaged(const QJSManagedValue &value, int type, void *ptr)
|
||||
{
|
||||
return QV4::ExecutionEngine::metaTypeFromJS(*value.d, type, ptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
convert \a value to \a type, store the result in \a ptr
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtQml/qjsvalue.h>
|
||||
|
||||
#include <QtQml/qjsmanagedvalue.h>
|
||||
#include <QtQml/qqmldebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
@ -92,12 +92,25 @@ public:
|
|||
{
|
||||
return create(qMetaTypeId<T>(), &value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QJSManagedValue toManagedValue(const T &value)
|
||||
{
|
||||
return createManaged(QMetaType::fromType<T>(), &value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T fromScriptValue(const QJSValue &value)
|
||||
{
|
||||
return qjsvalue_cast<T>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T fromManagedValue(const QJSManagedValue &value)
|
||||
{
|
||||
return qjsvalue_cast<T>(value);
|
||||
}
|
||||
|
||||
void collectGarbage();
|
||||
|
||||
enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
|
||||
|
@ -131,13 +144,18 @@ Q_SIGNALS:
|
|||
void uiLanguageChanged();
|
||||
|
||||
private:
|
||||
QJSManagedValue createManaged(QMetaType type, const void *ptr);
|
||||
QJSValue create(int type, const void *ptr);
|
||||
|
||||
static bool convertManaged(const QJSManagedValue &value, int type, void *ptr);
|
||||
static bool convertV2(const QJSValue &value, int type, void *ptr);
|
||||
|
||||
template<typename T>
|
||||
friend inline T qjsvalue_cast(const QJSValue &);
|
||||
|
||||
template<typename T>
|
||||
friend inline T qjsvalue_cast(const QJSManagedValue &);
|
||||
|
||||
protected:
|
||||
QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
|
||||
|
||||
|
@ -163,12 +181,30 @@ T qjsvalue_cast(const QJSValue &value)
|
|||
return T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T qjsvalue_cast(const QJSManagedValue &value)
|
||||
{
|
||||
{
|
||||
T t;
|
||||
if (QJSEngine::convertManaged(value, qMetaTypeId<T>(), &t))
|
||||
return t;
|
||||
}
|
||||
|
||||
return qvariant_cast<T>(value.toVariant());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
|
||||
{
|
||||
return value.toVariant();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value)
|
||||
{
|
||||
return value.toVariant();
|
||||
}
|
||||
|
||||
Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,158 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtQml module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSMANAGEDVALUE_H
|
||||
#define QJSMANAGEDVALUE_H
|
||||
|
||||
#include <QtQml/qtqmlglobal.h>
|
||||
#include <QtQml/qjsprimitivevalue.h>
|
||||
#include <QtQml/qjsvalue.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QV4 {
|
||||
struct Value;
|
||||
struct ExecutionEngine;
|
||||
}
|
||||
|
||||
class QJSEngine;
|
||||
class Q_QML_EXPORT QJSManagedValue
|
||||
{
|
||||
Q_DISABLE_COPY(QJSManagedValue)
|
||||
public:
|
||||
enum Type {
|
||||
Undefined,
|
||||
Boolean,
|
||||
Number,
|
||||
String,
|
||||
Object,
|
||||
Symbol
|
||||
};
|
||||
|
||||
QJSManagedValue() = default;
|
||||
QJSManagedValue(QJSValue value, QJSEngine *engine);
|
||||
QJSManagedValue(const QJSPrimitiveValue &value, QJSEngine *engine);
|
||||
QJSManagedValue(const QVariant &variant, QJSEngine *engine);
|
||||
QJSManagedValue(const QString &string, QJSEngine *engine);
|
||||
|
||||
~QJSManagedValue();
|
||||
QJSManagedValue(QJSManagedValue &&other);
|
||||
QJSManagedValue &operator=(QJSManagedValue &&other);
|
||||
|
||||
bool equals(const QJSManagedValue &other) const;
|
||||
bool strictlyEquals(const QJSManagedValue &other) const;
|
||||
|
||||
QJSEngine *engine() const;
|
||||
|
||||
QJSManagedValue prototype() const;
|
||||
void setPrototype(const QJSManagedValue &prototype);
|
||||
|
||||
Type type() const;
|
||||
|
||||
// Compatibility with QJSValue
|
||||
bool isUndefined() const { return type() == Undefined; }
|
||||
bool isBoolean() const { return type() == Boolean; }
|
||||
bool isNumber() const { return type() == Number; }
|
||||
bool isString() const { return type() == String; }
|
||||
bool isObject() const { return type() == Object; }
|
||||
bool isSymbol() const { return type() == Symbol; }
|
||||
|
||||
// Special case of Number
|
||||
bool isInteger() const;
|
||||
|
||||
// Selected special cases of Object
|
||||
bool isNull() const;
|
||||
bool isRegularExpression() const;
|
||||
bool isArray() const;
|
||||
bool isUrl() const;
|
||||
bool isVariant() const;
|
||||
bool isQObject() const;
|
||||
bool isQMetaObject() const;
|
||||
bool isDate() const;
|
||||
bool isError() const;
|
||||
bool isCallable() const;
|
||||
|
||||
// Native type transformations
|
||||
QString toString() const;
|
||||
double toNumber() const;
|
||||
bool toBoolean() const;
|
||||
|
||||
// Variant-like type transformations
|
||||
QJSPrimitiveValue toPrimitive() const;
|
||||
QJSValue toJSValue() const;
|
||||
QVariant toVariant() const;
|
||||
|
||||
// Special cases
|
||||
int toInteger() const;
|
||||
QRegularExpression toRegularExpression() const;
|
||||
QUrl toUrl() const;
|
||||
QObject *toQObject() const;
|
||||
const QMetaObject *toQMetaObject() const;
|
||||
QDateTime toDateTime() const;
|
||||
|
||||
// Properties of objects
|
||||
bool hasProperty(const QString &name) const;
|
||||
bool hasOwnProperty(const QString &name) const;
|
||||
QJSValue property(const QString &name) const;
|
||||
void setProperty(const QString &name, const QJSValue &value);
|
||||
bool deleteProperty(const QString &name);
|
||||
|
||||
// Array indexing
|
||||
bool hasProperty(quint32 arrayIndex) const;
|
||||
bool hasOwnProperty(quint32 arrayIndex) const;
|
||||
QJSValue property(quint32 arrayIndex) const;
|
||||
void setProperty(quint32 arrayIndex, const QJSValue &value);
|
||||
bool deleteProperty(quint32 arrayIndex);
|
||||
|
||||
// Calling functions
|
||||
QJSValue call(const QJSValueList &arguments = {}) const;
|
||||
QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &arguments = {}) const;
|
||||
QJSValue callAsConstructor(const QJSValueList &arguments = {}) const;
|
||||
|
||||
private:
|
||||
friend class QJSValue;
|
||||
friend class QJSEngine;
|
||||
|
||||
QJSManagedValue(QV4::ExecutionEngine *engine);
|
||||
QV4::Value *d = nullptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
|
@ -439,6 +439,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
friend class QJSManagedValue;
|
||||
friend class QJSValue;
|
||||
|
||||
constexpr bool asBoolean() const { return std::get<bool>(d); }
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "qjsengine.h"
|
||||
#include "qjsvalue.h"
|
||||
#include "qjsprimitivevalue.h"
|
||||
#include "qjsmanagedvalue.h"
|
||||
#include "qjsvalue_p.h"
|
||||
#include "qv4value_p.h"
|
||||
#include "qv4object_p.h"
|
||||
|
@ -884,6 +885,20 @@ QJSValue::QJSValue(QJSPrimitiveValue &&value)
|
|||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QJSValue::QJSValue(QJSManagedValue &&value)
|
||||
{
|
||||
if (!value.d) {
|
||||
d = QV4::Encode::undefined();
|
||||
} else if (value.d->isManaged()) {
|
||||
QJSValuePrivate::setRawValue(this, value.d);
|
||||
value.d = nullptr;
|
||||
} else {
|
||||
d = value.d->asReturnedValue();
|
||||
QV4::PersistentValueStorage::free(value.d);
|
||||
value.d = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool js_equal(const QString &string, const QV4::Value &value)
|
||||
{
|
||||
if (String *s = value.stringValue())
|
||||
|
|
|
@ -61,6 +61,9 @@ namespace QV4 {
|
|||
struct Value;
|
||||
}
|
||||
|
||||
class QJSPrimitiveValue;
|
||||
class QJSManagedValue;
|
||||
|
||||
class Q_QML_EXPORT QJSValue
|
||||
{
|
||||
public:
|
||||
|
@ -109,6 +112,7 @@ public:
|
|||
QJSValue &operator=(const QJSValue &other);
|
||||
|
||||
explicit QJSValue(QJSPrimitiveValue &&value);
|
||||
explicit QJSValue(QJSManagedValue &&value);
|
||||
|
||||
bool isBool() const;
|
||||
bool isNumber() const;
|
||||
|
|
|
@ -83,6 +83,12 @@ class Q_AUTOTEST_EXPORT QJSValuePrivate
|
|||
return (m & IsString) ? nullptr : reinterpret_cast<QV4::Value *>(m);
|
||||
}
|
||||
|
||||
static QV4::Value *managedValue(QV4::Value &v)
|
||||
{
|
||||
quintptr m = quintptr(v.m());
|
||||
return (m & IsString) ? nullptr : reinterpret_cast<QV4::Value *>(m);
|
||||
}
|
||||
|
||||
static const QString *qstring(const QV4::Value &v)
|
||||
{
|
||||
const quintptr m = quintptr(v.m());
|
||||
|
@ -108,14 +114,13 @@ class Q_AUTOTEST_EXPORT QJSValuePrivate
|
|||
return QV4::Value::fromHeapObject(reinterpret_cast<QV4::Heap::Base *>(m)).asReturnedValue();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Only for the test. You're not supposed to subclass QJSValuePrivate otherwise.
|
||||
public:
|
||||
|
||||
static void setRawValue(QJSValue *jsval, QV4::Value *m)
|
||||
{
|
||||
jsval->d = encodeRawValue(quintptr(m));
|
||||
}
|
||||
|
||||
public:
|
||||
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
|
||||
{
|
||||
QJSValue result;
|
||||
|
@ -134,6 +139,19 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// This is a move operation and transfers ownership.
|
||||
static QV4::Value *takeManagedValue(QJSValue *jsval)
|
||||
{
|
||||
QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
|
||||
if (!v.isManaged())
|
||||
return nullptr;
|
||||
if (QV4::Value *value = managedValue(v)) {
|
||||
setValue(jsval, QV4::Encode::undefined());
|
||||
return value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QV4::ReturnedValue asPrimitiveType(const QJSValue *jsval)
|
||||
{
|
||||
const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
|
||||
|
@ -170,6 +188,11 @@ public:
|
|||
jsval->d = v.isManaged() ? encode(v) : v.asReturnedValue();
|
||||
}
|
||||
|
||||
static void adoptValue(QJSValue *jsval, QV4::Value *v)
|
||||
{
|
||||
jsval->d = v->isManaged() ? encodeRawValue(quintptr(v)) : v->asReturnedValue();
|
||||
}
|
||||
|
||||
// Moves any QString onto the V4 heap, changing the value to reflect that.
|
||||
static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
|
||||
{
|
||||
|
|
|
@ -122,100 +122,125 @@ double Value::toNumberImpl(Value val)
|
|||
}
|
||||
}
|
||||
|
||||
QString Value::toQStringNoThrow() const
|
||||
static QString primitiveToQString(const Value *value)
|
||||
{
|
||||
switch (type()) {
|
||||
switch (value->type()) {
|
||||
case Value::Empty_Type:
|
||||
Q_ASSERT(!"empty Value encountered");
|
||||
Q_UNREACHABLE();
|
||||
return QString();
|
||||
case Value::Undefined_Type:
|
||||
return QStringLiteral("undefined");
|
||||
case Value::Null_Type:
|
||||
return QStringLiteral("null");
|
||||
case Value::Boolean_Type:
|
||||
if (booleanValue())
|
||||
if (value->booleanValue())
|
||||
return QStringLiteral("true");
|
||||
else
|
||||
return QStringLiteral("false");
|
||||
case Value::Managed_Type:
|
||||
Q_UNREACHABLE();
|
||||
return QString();
|
||||
case Value::Integer_Type: {
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, (double)value->int_32(), 10);
|
||||
return str;
|
||||
}
|
||||
case Value::Double_Type: {
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, value->doubleValue(), 10);
|
||||
return str;
|
||||
}
|
||||
} // switch
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QString Value::toQStringNoThrow() const
|
||||
{
|
||||
if (isManaged()) {
|
||||
if (String *s = stringValue())
|
||||
return s->toQString();
|
||||
if (Symbol *s = symbolValue())
|
||||
return s->descriptiveString();
|
||||
{
|
||||
Q_ASSERT(isObject());
|
||||
Scope scope(objectValue()->engine());
|
||||
ScopedValue ex(scope);
|
||||
bool caughtException = false;
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
|
||||
|
||||
Q_ASSERT(isObject());
|
||||
Scope scope(objectValue()->engine());
|
||||
ScopedValue ex(scope);
|
||||
bool caughtException = false;
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
|
||||
if (scope.hasException()) {
|
||||
ex = scope.engine->catchException();
|
||||
caughtException = true;
|
||||
} else if (prim->isPrimitive()) {
|
||||
return prim->toQStringNoThrow();
|
||||
}
|
||||
|
||||
// Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
|
||||
if (caughtException) {
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT));
|
||||
if (scope.hasException()) {
|
||||
ex = scope.engine->catchException();
|
||||
caughtException = true;
|
||||
} else if (prim->isPrimitive()) {
|
||||
return prim->toQStringNoThrow();
|
||||
return prim->toQStringNoThrow();
|
||||
}
|
||||
// Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
|
||||
if (caughtException) {
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT));
|
||||
if (scope.hasException()) {
|
||||
ex = scope.engine->catchException();
|
||||
} else if (prim->isPrimitive()) {
|
||||
return prim->toQStringNoThrow();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
case Value::Integer_Type: {
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
|
||||
return str;
|
||||
|
||||
return QString();
|
||||
}
|
||||
default: { // double
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, doubleValue(), 10);
|
||||
return str;
|
||||
}
|
||||
} // switch
|
||||
|
||||
return primitiveToQString(this);
|
||||
}
|
||||
|
||||
QString Value::toQString() const
|
||||
{
|
||||
switch (type()) {
|
||||
case Value::Empty_Type:
|
||||
Q_ASSERT(!"empty Value encountered");
|
||||
Q_UNREACHABLE();
|
||||
case Value::Undefined_Type:
|
||||
return QStringLiteral("undefined");
|
||||
case Value::Null_Type:
|
||||
return QStringLiteral("null");
|
||||
case Value::Boolean_Type:
|
||||
if (booleanValue())
|
||||
return QStringLiteral("true");
|
||||
else
|
||||
return QStringLiteral("false");
|
||||
case Value::Managed_Type:
|
||||
if (String *s = stringValue()) {
|
||||
if (isManaged()) {
|
||||
if (String *s = stringValue())
|
||||
return s->toQString();
|
||||
} else if (isSymbol()) {
|
||||
|
||||
if (isSymbol()) {
|
||||
static_cast<const Managed *>(this)->engine()->throwTypeError();
|
||||
return QString();
|
||||
} else {
|
||||
Q_ASSERT(isObject());
|
||||
Scope scope(objectValue()->engine());
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
|
||||
return prim->toQString();
|
||||
}
|
||||
case Value::Integer_Type: {
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
|
||||
return str;
|
||||
|
||||
Q_ASSERT(isObject());
|
||||
Scope scope(objectValue()->engine());
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
|
||||
return prim->toQString();
|
||||
}
|
||||
default: { // double
|
||||
QString str;
|
||||
RuntimeHelpers::numberToString(&str, doubleValue(), 10);
|
||||
return str;
|
||||
|
||||
return primitiveToQString(this);
|
||||
}
|
||||
|
||||
QString Value::toQString(bool *ok) const
|
||||
{
|
||||
if (isManaged()) {
|
||||
if (String *s = stringValue()) {
|
||||
*ok = true;
|
||||
return s->toQString();
|
||||
}
|
||||
|
||||
if (isSymbol()) {
|
||||
static_cast<const Managed *>(this)->engine()->throwTypeError();
|
||||
*ok = false;
|
||||
return QString();
|
||||
}
|
||||
|
||||
Q_ASSERT(isObject());
|
||||
Scope scope(objectValue()->engine());
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
|
||||
|
||||
if (scope.hasException()) {
|
||||
*ok = false;
|
||||
return QString();
|
||||
}
|
||||
|
||||
return prim->toQString(ok);
|
||||
}
|
||||
} // switch
|
||||
|
||||
return primitiveToQString(this);
|
||||
}
|
||||
|
||||
QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
|
||||
|
|
|
@ -190,8 +190,11 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
|
|||
inline double toNumber() const;
|
||||
static double toNumberImpl(Value v);
|
||||
double toNumberImpl() const { return toNumberImpl(*this); }
|
||||
|
||||
QString toQStringNoThrow() const;
|
||||
QString toQString() const;
|
||||
QString toQString(bool *ok) const;
|
||||
|
||||
Heap::String *toString(ExecutionEngine *e) const {
|
||||
if (isString())
|
||||
return reinterpret_cast<Heap::String *>(m());
|
||||
|
|
|
@ -34,6 +34,7 @@ add_subdirectory(qqmlmetatype)
|
|||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(qjsengine)
|
||||
add_subdirectory(qjsvalue)
|
||||
add_subdirectory(qjsmanagedvalue)
|
||||
endif()
|
||||
if(QT_FEATURE_process AND QT_FEATURE_qml_debug)
|
||||
add_subdirectory(debugger)
|
||||
|
|
|
@ -34,6 +34,7 @@ add_subdirectory(qqmlmetatype)
|
|||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(qjsengine)
|
||||
add_subdirectory(qjsvalue)
|
||||
add_subdirectory(qjsmanagedvalue)
|
||||
endif()
|
||||
if(QT_FEATURE_process AND QT_FEATURE_qml_debug)
|
||||
add_subdirectory(debugger)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Generated from qjsvalue.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qjsvalue Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qjsvalue
|
||||
SOURCES
|
||||
tst_qjsvalue.cpp tst_qjsvalue.h
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
Qt::Qml
|
||||
Qt::QmlPrivate
|
||||
Qt::Widgets
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
|
@ -0,0 +1,16 @@
|
|||
# Generated from qjsmanagedvalue.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qjsmanagedvalue Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qjsmanagedvalue
|
||||
SOURCES
|
||||
tst_qjsmanagedvalue.cpp tst_qjsmanagedvalue.h
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Qml
|
||||
Qt::QmlPrivate
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
|
@ -0,0 +1,6 @@
|
|||
CONFIG += testcase
|
||||
TARGET = tst_qjsmanagedvalue
|
||||
macos:CONFIG -= app_bundle
|
||||
QT += qml testlib qml-private
|
||||
SOURCES += tst_qjsmanagedvalue.cpp
|
||||
HEADERS += tst_qjsmanagedvalue.h
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,116 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TST_QJSMANAGEDVALUE_H
|
||||
#define TST_QJSMANAGEDVALUE_H
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtQml/qjsengine.h>
|
||||
|
||||
class tst_QJSManagedValue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void ctor_invalid();
|
||||
void ctor_undefinedWithEngine();
|
||||
void ctor_nullWithEngine();
|
||||
void ctor_boolWithEngine();
|
||||
void ctor_intWithEngine();
|
||||
void ctor_uintWithEngine();
|
||||
void ctor_floatWithEngine();
|
||||
void ctor_stringWithEngine();
|
||||
void ctor_copyAndAssignWithEngine();
|
||||
|
||||
void toString();
|
||||
void toNumber();
|
||||
void toBoolean();
|
||||
void toVariant();
|
||||
|
||||
void equals();
|
||||
void strictlyEquals();
|
||||
|
||||
void hasProperty_basic();
|
||||
void hasProperty_globalObject();
|
||||
void hasProperty_changePrototype();
|
||||
void hasProperty_QTBUG56830_data();
|
||||
void hasProperty_QTBUG56830();
|
||||
|
||||
void deleteProperty_basic();
|
||||
void deleteProperty_globalObject();
|
||||
void deleteProperty_inPrototype();
|
||||
|
||||
void getSetPrototype_cyclicPrototype();
|
||||
void getSetPrototype_evalCyclicPrototype();
|
||||
void getSetPrototype_eval();
|
||||
void getSetPrototype_invalidPrototype();
|
||||
void getSetPrototype_twoEngines();
|
||||
void getSetPrototype_null();
|
||||
void getSetPrototype_notObjectOrNull();
|
||||
void getSetPrototype();
|
||||
void getSetProperty_propertyRemoval();
|
||||
void getSetProperty_resolveMode();
|
||||
void getSetProperty_twoEngines();
|
||||
void getSetProperty_gettersAndSettersThrowErrorJS();
|
||||
void getSetProperty_array();
|
||||
void getSetProperty();
|
||||
|
||||
void call_function();
|
||||
void call_object();
|
||||
void call_newObjects();
|
||||
void call_this();
|
||||
void call_arguments();
|
||||
void call();
|
||||
void call_twoEngines();
|
||||
void call_nonFunction_data();
|
||||
void call_nonFunction();
|
||||
void construct_nonFunction_data();
|
||||
void construct_nonFunction();
|
||||
void construct_simple();
|
||||
void construct_newObjectJS();
|
||||
void construct_arg();
|
||||
void construct_proto();
|
||||
void construct_returnInt();
|
||||
void construct_throw();
|
||||
void construct_twoEngines();
|
||||
void construct_constructorThrowsPrimitive();
|
||||
void castToPointer();
|
||||
void engineDeleted();
|
||||
void valueOfWithClosure();
|
||||
|
||||
void jsvalueArrayToSequenceType();
|
||||
|
||||
void stringAndUrl();
|
||||
void jsFunctionInVariant();
|
||||
|
||||
private:
|
||||
void newEngine() { engine.reset(new QJSEngine()); }
|
||||
QScopedPointer<QJSEngine> engine;
|
||||
};
|
||||
|
||||
#endif // TST_QJSMANAGEDVALUE
|
|
@ -82,6 +82,7 @@ qtHaveModule(widgets) {
|
|||
SUBDIRS += \
|
||||
qjsengine \
|
||||
qjsvalue \
|
||||
qjsmanagedvalue \
|
||||
# qwidgetsinqml
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue