diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-06-11 01:01:10 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-06-11 11:28:44 +0200 |
commit | 10e3b24c02cd1c22c7df0f350f229625e13faeae (patch) | |
tree | e9f02181e47156e9c8652e0c5dba15bbdcb97e5a /src/qml | |
parent | 8733a8762c2db473d3a39d1f01c09156c04e3772 (diff) | |
parent | ac402fa6d99eeb519a9cc23b028358dfb6df4d82 (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
src/qml/jsruntime/qv4value_p.h
src/qml/qml/qqmlmetatype.cpp
src/qml/qml/qqmltypewrapper.cpp
src/quick/items/qquicktableview.cpp
Change-Id: I684f8e01a711580512848bf1253f39b39fcbf4c7
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 19 | ||||
-rw-r--r-- | src/qml/doc/snippets/qml/componentCreation.js | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 17 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 49 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlapplicationengine.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 43 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper_p.h | 2 | ||||
-rw-r--r-- | src/qml/qmldirparser/qqmldirparser_p.h | 24 |
17 files changed, 168 insertions, 36 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index b7e3e20fd0..04e6efb1e9 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1073,6 +1073,7 @@ bool Codegen::visit(Expression *ast) TailCallBlocker blockTailCalls(this); statement(ast->left); blockTailCalls.unblock(); + clearExprResultName(); // The name only holds for the left part accept(ast->right); return false; } @@ -2537,7 +2538,7 @@ bool Codegen::visit(ObjectPattern *ast) { RegisterScope innerScope(this); - Reference value = expression(p->initializer); + Reference value = expression(p->initializer, name); if (hasError) return false; value.loadInAccumulator(); @@ -2979,7 +2980,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, // already defined return leaveContext(); - _context->name = name; + _context->name = name.isEmpty() ? currentExpr().result().name : name; _module->functions.append(_context); _context->functionIndex = _module->functions.count() - 1; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 6d5f8c0951..65dc4b97b5 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -199,8 +199,9 @@ public: codegen = cg; } - Reference() : + Reference(const QString &name = QString()) : constant(0), + name(name), isArgOrEval(false), isReadonly(false), isReferenceToConst(false), @@ -418,6 +419,11 @@ protected: bool _trueBlockFollowsCondition = false; public: + explicit Result(const QString &name) + : _result(name) + , _requested(ex) + {} + explicit Result(const Reference &lrvalue) : _result(lrvalue) , _requested(ex) @@ -476,6 +482,10 @@ protected: void setResult(Reference &&result) { _result = std::move(result); } + + void clearResultName() { + _result.name.clear(); + } }; void enterContext(AST::Node *node); @@ -523,12 +533,12 @@ protected: const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition); - inline Reference expression(AST::ExpressionNode *ast) + inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString()) { if (!ast || hasError) return Reference(); - pushExpr(); + pushExpr(name); ast->accept(this); return popResult(); } @@ -716,6 +726,7 @@ protected: inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); } inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); } inline Reference exprResult() const { return m_expressions.back().result(); } + inline void clearExprResultName() { m_expressions.back().clearResultName(); } inline bool exprAccept(Format f) { return m_expressions.back().accept(f); } @@ -723,7 +734,7 @@ protected: inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); } inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); } - inline void pushExpr() { m_expressions.emplace_back(); } + inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); } inline Result popExpr() { diff --git a/src/qml/doc/snippets/qml/componentCreation.js b/src/qml/doc/snippets/qml/componentCreation.js index 7364139d3d..ea45f18c37 100644 --- a/src/qml/doc/snippets/qml/componentCreation.js +++ b/src/qml/doc/snippets/qml/componentCreation.js @@ -17,7 +17,7 @@ function createSpriteObjects() { //![local] component = Qt.createComponent("Sprite.qml"); - sprite = component.createObject(appWindow, {"x": 100, "y": 100}); + sprite = component.createObject(appWindow, {x: 100, y: 100}); if (sprite == null) { // Error Handling @@ -32,7 +32,7 @@ function createSpriteObjects() { //![finishCreation] function finishCreation() { if (component.status == Component.Ready) { - sprite = component.createObject(appWindow, {"x": 100, "y": 100}); + sprite = component.createObject(appWindow, {x: 100, y: 100}); if (sprite == null) { // Error Handling console.log("Error creating object"); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 99f425293e..0cda6b864a 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -77,8 +77,13 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu primitiveLookup.type = object.type(); switch (primitiveLookup.type) { case Value::Undefined_Type: - case Value::Null_Type: - return engine->throwTypeError(); + case Value::Null_Type: { + Scope scope(engine); + ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); + const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()) + .arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null")); + return engine->throwTypeError(message); + } case Value::Boolean_Type: primitiveLookup.proto = engine->booleanPrototype()->d(); break; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 94bf1a98ae..7578de4d14 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup { } indexedLookup; struct { Heap::InternalClass *ic; - Heap::QObjectWrapper *staticQObject; + Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper QQmlPropertyCache *propertyCache; QQmlPropertyData *propertyData; } qobjectLookup; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index f3351f6da0..7b885a9e9e 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -292,7 +292,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; @@ -325,7 +324,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8b7de89d5b..8a4adfe69a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -872,7 +872,6 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E } lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 795bf241f2..ac9cad2bdb 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -231,8 +231,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE if (!o || o->internalClass != lookup->qobjectLookup.ic) return revertLookup(); - const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : - static_cast<const Heap::QObjectWrapper *>(o); + const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o); QObject *qobj = This->object(); if (QQmlData::wasDeleted(qobj)) return QV4::Encode::undefined(); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index a9c8ac66bd..4e901721cb 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -87,12 +87,29 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const { HeapBasePtr b; +#ifdef __ia64 +// Restore bits 49-47 to bits 63-61, undoing the workaround explained in +// setM below. + quint64 _tmp; + + _tmp = _val & (7L << 47); // 0x3800000000000 + _tmp = (_tmp << 14) | (_val ^ _tmp); + memcpy(&b, &_tmp, 8); +#else memcpy(&b, &_val, 8); +#endif return b; } QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b) { memcpy(&_val, &b, 8); +#ifdef __ia64 +// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region +// number. Since this implementation is not 64-bit clean, we move bits 63-61 +// to bits 49-47 and hope for the best. This is undone in *m(), above. + _val |= ((_val & (7L << 61)) >> 14); + _val &= ((1L << 50)-1); +#endif } #elif QT_POINTER_SIZE == 4 QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 0c947b541b..4ad9057ced 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1110,6 +1110,23 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T } break; ./ +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON; +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON; +/. + case $rule_number: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->typeModifier = stringRef(3); + node->propertyToken = loc(2); + node->typeModifierToken = loc(3); + node->typeToken = loc(5); + node->identifierToken = loc(7); + node->semicolonToken = loc(8); + sym(1).Node = node; + } break; +./ + UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON; UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON; /. @@ -1221,6 +1238,34 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T } break; ./ +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET; +/. + case $rule_number: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->typeModifier = stringRef(3); + node->propertyToken = loc(2); + node->typeModifierToken = loc(3); + node->typeToken = loc(5); + node->identifierToken = loc(7); + node->semicolonToken = loc(8); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7)); + propertyName->identifierToken = loc(7); + propertyName->next = 0; + + AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish()); + binding->colonToken = loc(8); + binding->lbracketToken = loc(9); + binding->rbracketToken = loc(11); + + node->binding = binding; + + sym(1).Node = node; + } break; +./ + UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer; /. case $rule_number: { @@ -1773,10 +1818,6 @@ PropertyDefinition: PropertyName T_COLON AssignmentExpression_In; /. case $rule_number: { AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression); - if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) { - if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) - f->name = driver->newStringRef(sym(1).PropertyName->asString()); - } if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) { if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) c->name = driver->newStringRef(sym(1).PropertyName->asString()); diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 7b3f89e943..f84a1b2109 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -608,9 +608,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { - QObject *mutableObj = const_cast<QObject *>(obj); - return qmlAttachedPropertiesObject( - mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create); + // We don't need a concrete object to resolve the function. As T is a C++ type, it and all its + // super types should be registered as CppType (or not at all). We only need the object and its + // QML engine to resolve composite types. Therefore, the function is actually a static property + // of the C++ type system and we can cache it here for improved performance on further lookups. + static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject); + return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); } inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 1b7a433a84..facd79d211 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -76,7 +76,7 @@ void QQmlApplicationEnginePrivate::init() &QCoreApplication::exit, Qt::QueuedConnection); #if QT_CONFIG(translation) QTranslator* qtTranslator = new QTranslator; - if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm"))) QCoreApplication::installTranslator(qtTranslator); translators << qtTranslator; #endif @@ -90,10 +90,10 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc")) return; - QFileInfo fi(rootFile.toLocalFile()); + QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile)); QTranslator *translator = new QTranslator; - if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) { + if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) { QCoreApplication::installTranslator(translator); translators << translator; } else { @@ -180,6 +180,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) \list \li Connecting Qt.quit() to QCoreApplication::quit() \li Automatically loads translation files from an i18n directory adjacent to the main QML file. + \list + \li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm. + \endlist \li Automatically sets an incubation controller if the scene contains a QQuickWindow. \li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all QML files and assets. diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 04debc0615..89b632f87b 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1206,7 +1206,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) \js var component = Qt.createComponent("Button.qml"); if (component.status == Component.Ready) - component.createObject(parent, {"x": 100, "y": 100}); + component.createObject(parent, {x: 100, y: 100}); \endjs Dynamically created instances can be deleted with the \c destroy() method. diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index a5b92d14f7..c6858780a1 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1193,7 +1193,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe void QQmlMetaType::unregisterType(int typeIndex) { QQmlMetaTypeDataPtr data; - if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) { + const QQmlType type = data->types.value(typeIndex); + if (const QQmlTypePrivate *d = type.priv()) { removeQQmlTypePrivate(data->idToType, d); removeQQmlTypePrivate(data->nameToType, d); removeQQmlTypePrivate(data->urlToType, d); @@ -1203,6 +1204,7 @@ void QQmlMetaType::unregisterType(int typeIndex) module->remove(d); data->clearPropertyCachesForMinorVersion(typeIndex); data->types[typeIndex] = QQmlType(); + data->undeletableTypes.remove(type); } } diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 9db089c330..57c4eec879 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -454,16 +454,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (!includeEnums || !name->startsWithUpper()) { QQmlData *ddata = QQmlData::get(qobjectSingleton, false); if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + lookup->qobjectLookup.qmlTypeIc = This->internalClass(); + lookup->qobjectLookup.ic = val->objectValue()->internalClass(); lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; + return lookup->getter(lookup, engine, *object); } // Fall through to base implementation } @@ -485,6 +485,39 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine return Object::virtualResolveLookupSetter(object, engine, lookup, value); } +ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [l, engine, &object]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(l, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc) + return revertLookup(); + + Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o); + + QQmlType type = This->type(); + if (!type.isValid()) + return revertLookup(); + + if (!type.isQObjectSingleton() && !type.isCompositeSingleton()) + return revertLookup(); + + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine()); + QObject *qobjectSingleton = e->singletonInstance<QObject *>(type); + Q_ASSERT(qobjectSingleton); + + Scope scope(engine); + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + void Heap::QQmlScopedEnumWrapper::destroy() { QQmlType::derefHandle(typePrivate); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c797a4ac10..6b51f421b3 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h index cff9cb11a4..f7a91c8b81 100644 --- a/src/qml/qmldirparser/qqmldirparser_p.h +++ b/src/qml/qmldirparser/qqmldirparser_p.h @@ -76,12 +76,24 @@ public: QString typeNamespace() const; void setTypeNamespace(const QString &s); + static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName) + { + if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) { + qWarning() << item << typeName + << "is specified with non-relative URL" << fileName << "in a qmldir file." + << "URLs in qmldir files should be relative to the qmldir file's directory."; + } + } + struct Plugin { Plugin() {} Plugin(const QString &name, const QString &path) - : name(name), path(path) {} + : name(name), path(path) + { + checkNonRelative("Plugin", name, path); + } QString name; QString path; @@ -93,7 +105,10 @@ public: Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion) : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion), - internal(false), singleton(false) {} + internal(false), singleton(false) + { + checkNonRelative("Component", typeName, fileName); + } QString typeName; QString fileName; @@ -108,7 +123,10 @@ public: Script() {} Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) - : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) + { + checkNonRelative("Script", nameSpace, fileName); + } QString nameSpace; QString fileName; |