void tst_qmldiskcache::registerImportForImplicitComponent() { QQmlEngine engine; TestCompiler testCompiler(&engine); QVERIFY(testCompiler.tempDir.isValid()); const QByteArray contents = QByteArrayLiteral("import QtQuick 2.0\n" "Loader {\n" " sourceComponent: Item {}\n" "}"); QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); { const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); QCOMPARE(quint32(testUnit->nImports), quint32(2)); QCOMPARE(testUnit->stringAt(testUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick")); QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->uriIndex), QString(componentType.module())); QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals")); QCOMPARE(quint32(testUnit->nObjects), quint32(3)); const QV4::CompiledData::Object *obj = testUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(1)); QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object)); const QV4::CompiledData::Object *implicitComponent = testUnit->objectAt(obj->bindingTable()->value.objectIndex); QCOMPARE(testUnit->stringAt(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType.elementName()); } }
int registerInterface(const QQmlPrivate::RegisterInterface &interface) { if (interface.version > 0) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); QWriteLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); int index = data->types.count(); QQmlType *type = new QQmlType(index, interface); data->types.append(type); data->idToType.insert(type->typeId(), type); data->idToType.insert(type->qListTypeId(), type); // XXX No insertMulti, so no multi-version interfaces? if (!type->elementName().isEmpty()) data->nameToType.insert(type->elementName(), type); if (data->interfaces.size() <= interface.typeId) data->interfaces.resize(interface.typeId + 16); if (data->lists.size() <= interface.listId) data->lists.resize(interface.listId + 16); data->interfaces.setBit(interface.typeId, true); data->lists.setBit(interface.listId, true); return index; }
const QMetaObject *QQmlCustomParserCompilerBackend::resolveType(const QString &name) const { QQmlType *qmltype = 0; if (!imports().resolveType(name, &qmltype, 0, 0, 0)) return 0; if (!qmltype) return 0; return qmltype->metaObject(); }
/* Returns the item type for a list of type \a id. */ int QQmlMetaType::listType(int id) { QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QQmlType *type = data->idToType.value(id); if (type && type->qListTypeId() == id) return type->typeId(); else return 0; }
/*! Returns the type (if any) that corresponds to the QVariant::Type \a userType. Returns null if no type is registered. */ QQmlType *QQmlMetaType::qmlType(int userType) { QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QQmlType *type = data->idToType.value(userType); if (type && type->typeId() == userType) return type; else return 0; }
const char *QQmlMetaType::interfaceIId(int userType) { QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QQmlType *type = data->idToType.value(userType); lock.unlock(); if (type && type->isInterface() && type->typeId() == userType) return type->interfaceIId(); else return 0; }
int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo) { QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QQmlType *type = data->metaObjectToType.value(mo); if (type && type->attachedPropertiesFunction()) return type->attachedPropertiesId(); else return -1; }
QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const { QReadLocker lock(metaTypeDataLock()); QList<QQmlType *> retn; for (int ii = 0; ii < d->types.count(); ++ii) { QQmlType *curr = d->types.at(ii); if (curr->isSingleton() && curr->minorVersion() <= minor) retn.append(curr); } return retn; }
void tst_qqmlmetatype::compositeType() { QQmlEngine engine; //Loading the test file also loads all composite types it imports QQmlComponent c(&engine, testFileUrl("testImplicitComposite.qml")); QObject* obj = c.create(); QVERIFY(obj); QQmlType *type = QQmlMetaType::qmlType(QString("ImplicitType"), QString(""), 1, 0); QVERIFY(type); QVERIFY(type->module() == QLatin1String("")); QVERIFY(type->elementName() == QLatin1String("ImplicitType")); QCOMPARE(type->qmlTypeName(), QLatin1String("ImplicitType")); QCOMPARE(type->sourceUrl(), testFileUrl("ImplicitType.qml")); }
/*! Returns the type (if any) that corresponds to the \a metaObject in version specified by \a version_major and \a version_minor in module specified by \a uri. Returns null if no type is registered. */ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); QReadLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject); while (it != data->metaObjectToType.end() && it.key() == metaObject) { QQmlType *t = *it; if (version_major < 0 || t->availableInVersion(module, version_major,version_minor)) return t; ++it; } return 0; }
static void addTypeInfo(QQuickItem *object, TasObject* objectInfo) { QString typeName; QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } else { typeName = QString::fromUtf8(object->metaObject()->className()); int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); if (marker != -1) typeName = typeName.left(marker); marker = typeName.indexOf(QLatin1String("_QML_")); if (marker != -1) { typeName = typeName.left(marker); typeName += QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } } } if (!typeName.isEmpty()) { objectInfo->setType(typeName); } objectInfo->addAttribute("QML_NATIVE_TYPE", typeName); QQmlData *ddata = QQmlData::get(object, false); if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { objectInfo->addAttribute("QML_DEFINED_IN_URL", ddata->outerContext->url.toString()); objectInfo->addAttribute("QML_DEFINED_IN_LINE", ddata->lineNumber); objectInfo->addAttribute("QML_DEFINED_IN_COLUMN", ddata->columnNumber); } }
int EnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const { Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer"); *ok = false; if (scope != QLatin1String("Qt")) { QQmlType *type = 0; imports->resolveType(scope, &type, 0, 0, 0); return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); while (i--) { int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); if (*ok) return v; } return -1; }
void tst_qqmlmetatype::registrationType() { QQmlType *type = QQmlMetaType::qmlType(QString("TestType"), QString("Test"), 1, 0); QVERIFY(type); QVERIFY(!type->isInterface()); QVERIFY(!type->isSingleton()); QVERIFY(!type->isComposite()); type = QQmlMetaType::qmlType(QString("TestTypeSingleton"), QString("Test"), 1, 0); QVERIFY(type); QVERIFY(!type->isInterface()); QVERIFY(type->isSingleton()); QVERIFY(!type->isComposite()); type = QQmlMetaType::qmlType(QString("TestTypeComposite"), QString("Test"), 1, 0); QVERIFY(type); QVERIFY(!type->isInterface()); QVERIFY(!type->isSingleton()); QVERIFY(type->isComposite()); }
bool ServerNodeInstance::isSubclassOf(QObject *object, const QByteArray &superTypeName) { if (object == 0) return false; const QMetaObject *metaObject = object->metaObject(); while (metaObject) { QQmlType *qmlType = QQmlMetaType::qmlType(metaObject); if (qmlType && qmlType->qmlTypeName() == superTypeName) // ignore version numbers return true; if (metaObject->className() == superTypeName) return true; metaObject = metaObject->superClass(); } return false; }
int registerType(const QQmlPrivate::RegisterType &type) { QWriteLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QString elementName = QString::fromUtf8(type.elementName); if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName)) return -1; int index = data->types.count(); QQmlType *dtype = new QQmlType(index, elementName, type); data->types.append(dtype); data->idToType.insert(dtype->typeId(), dtype); if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype); if (!dtype->elementName().isEmpty()) data->nameToType.insertMulti(dtype->elementName(), dtype); data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype); if (data->objects.size() <= type.typeId) data->objects.resize(type.typeId + 16); if (data->lists.size() <= type.listId) data->lists.resize(type.listId + 16); data->objects.setBit(type.typeId, true); if (type.listId) data->lists.setBit(type.listId, true); if (!dtype->module().isEmpty()) { const QHashedString &mod = dtype->module(); QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor); QQmlTypeModule *module = data->uriToModule.value(versionedUri); if (!module) { module = new QQmlTypeModule; module->d->uri = versionedUri; data->uriToModule.insert(versionedUri, module); } module->d->add(dtype); } return index; }
/*! If \a script is a simple enumeration expression (eg. Text.AlignLeft), returns the integer equivalent (eg. 1), and sets \a ok to true. Otherwise sets \a ok to false. A valid \a ok must be provided, or the function will assert. */ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const { Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer"); *ok = false; int dot = script.indexOf('.'); if (dot == -1) return -1; QString scope = QString::fromUtf8(script.left(dot)); QByteArray enumValue = script.mid(dot+1); if (scope != QLatin1String("Qt")) { if (imports.isNull()) return -1; QQmlType *type = 0; if (imports.isT1()) { imports.asT1()->resolveType(scope, &type, 0, 0, 0); } else { QQmlTypeNameCache::Result result = imports.asT2()->query(scope); if (result.isValid()) type = result.type; } return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); while (i--) { int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); if (*ok) return v; } return -1; }
void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QmlTypeWrapper>()); QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); if (v4->hasException) return; QV4::Scope scope(v4); QQmlContextData *context = v4->v8Engine->callingContext(); QQmlType *type = w->d()->type; if (type && !type->isSingleton() && w->d()->object) { QObject *object = w->d()->object; QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (type && type->isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (!siinfo->scriptApi(e).isUndefined()) { QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); if (!apiprivate) { QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); v4->throwError(error); return; } else { apiprivate->put(name, value); } } } }
void tst_qqmlmetatype::qmlType() { QQmlType *type = QQmlMetaType::qmlType(QString("ParserStatusTestType"), QString("Test"), 1, 0); QVERIFY(type); QVERIFY(type->module() == QLatin1String("Test")); QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType")); QCOMPARE(type->qmlTypeName(), QLatin1String("Test/ParserStatusTestType")); type = QQmlMetaType::qmlType("Test/ParserStatusTestType", 1, 0); QVERIFY(type); QVERIFY(type->module() == QLatin1String("Test")); QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType")); QCOMPARE(type->qmlTypeName(), QLatin1String("Test/ParserStatusTestType")); }
bool PropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache) { QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate), obj->propertyCount(), obj->functionCount() + obj->propertyCount() + obj->signalCount(), obj->signalCount() + obj->propertyCount()); propertyCaches[objectIndex] = cache; struct TypeData { QV4::CompiledData::Property::Type dtype; int metaType; } builtinTypes[] = { { QV4::CompiledData::Property::Var, qMetaTypeId<QJSValue>() }, { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, { QV4::CompiledData::Property::Int, QMetaType::Int }, { QV4::CompiledData::Property::Bool, QMetaType::Bool }, { QV4::CompiledData::Property::Real, QMetaType::Double }, { QV4::CompiledData::Property::String, QMetaType::QString }, { QV4::CompiledData::Property::Url, QMetaType::QUrl }, { QV4::CompiledData::Property::Color, QMetaType::QColor }, { QV4::CompiledData::Property::Font, QMetaType::QFont }, { QV4::CompiledData::Property::Time, QMetaType::QTime }, { QV4::CompiledData::Property::Date, QMetaType::QDate }, { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, { QV4::CompiledData::Property::Point, QMetaType::QPointF }, { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } }; static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); QByteArray newClassName; if (objectIndex == compiler->rootObjectIndex()) { QString path = compiler->data()->url.path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); } } if (newClassName.isEmpty()) { newClassName = QQmlMetaObject(baseTypeCache).className(); newClassName.append("_QML_"); newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); } cache->_dynamicClassName = newClassName; int aliasCount = 0; int varPropCount = 0; QmlIR::PropertyResolver resolver(baseTypeCache); for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { if (p->type == QV4::CompiledData::Property::Alias) aliasCount++; else if (p->type == QV4::CompiledData::Property::Var) varPropCount++; // No point doing this for both the alias and non alias cases bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) { compiler->recordError(p->location, tr("Cannot override FINAL property")); return false; } } typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) + obj->propertyCount() * sizeof(VMD::PropertyData) + obj->functionCount() * sizeof(VMD::MethodData) + aliasCount * sizeof(VMD::AliasData), 0); int effectivePropertyIndex = cache->propertyIndexCacheStart; int effectiveMethodIndex = cache->methodIndexCacheStart; // For property change signal override detection. // We prepopulate a set of signal names which already exist in the object, // and throw an error if there is a signal/method defined as an override. QSet<QString> seenSignals; seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); QQmlPropertyCache *parentCache = cache; while ((parentCache = parentCache->parent())) { if (int pSigCount = parentCache->signalCount()) { int pSigOffset = parentCache->signalOffset(); for (int i = pSigOffset; i < pSigCount; ++i) { QQmlPropertyData *currPSig = parentCache->signal(i); // XXX TODO: find a better way to get signal name from the property data :-/ for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); iter != parentCache->stringCache.end(); ++iter) { if (currPSig == (*iter).second) { seenSignals.insert(iter.key()); break; } } } } } // First set up notify signals for properties - first normal, then var, then alias enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias if (ii == NSS_Var && varPropCount == 0) continue; else if (ii == NSS_Alias && aliasCount == 0) continue; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var)) || ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias))) continue; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); seenSignals.insert(changedSigName); cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } } // Dynamic signals for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) { const int paramCount = s->parameters->count; QList<QByteArray> names; QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); if (paramCount) { paramTypes[0] = paramCount; QmlIR::SignalParameter *param = s->parameters->first; for (int i = 0; i < paramCount; ++i, param = param->next) { names.append(stringAt(param->nameIndex).toUtf8()); if (param->type < builtinTypeCount) { // built-in type paramTypes[i + 1] = builtinTypes[param->type].metaType; } else { // lazily resolved type Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); const QString customTypeName = stringAt(param->customTypeNameIndex); QQmlType *qmltype = 0; if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0)) { compiler->recordError(s->location, tr("Invalid signal parameter type: %1").arg(customTypeName)); return false; } if (qmltype->isComposite()) { // Composite type usage qDebug() << "Composite type usage2" << qmltype->sourceUrl() << "Line" << param->location.line << "Col" << param->location.column; QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(param->customTypeNameIndex); Q_ASSERT(typeRef->component->compiledData != NULL); paramTypes[i + 1] = typeRef->component->compiledData->metaTypeId; } else { paramTypes[i + 1] = qmltype->typeId(); } } } } ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; if (paramCount) flags |= QQmlPropertyData::HasArguments; QString signalName = stringAt(s->nameIndex); if (seenSignals.contains(signalName)) { compiler->recordError(s->location, tr("Duplicate signal name: invalid override of property change signal or superclass signal")); return false; } seenSignals.insert(signalName); cache->appendSignal(signalName, flags, effectiveMethodIndex++, paramCount?paramTypes.constData():0, names); } // Dynamic slots for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; if (astFunction->formals) flags |= QQmlPropertyData::HasArguments; QString slotName = astFunction->name.toString(); if (seenSignals.contains(slotName)) { compiler->recordError(s->location, tr("Duplicate method name: invalid override of property change signal or superclass signal")); return false; } // Note: we don't append slotName to the seenSignals list, since we don't // protect against overriding change signals or methods with properties. QList<QByteArray> parameterNames; QQmlJS::AST::FormalParameterList *param = astFunction->formals; while (param) { parameterNames << param->name.toUtf8(); param = param->next; } cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); } // Dynamic properties (except var and aliases) int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; int propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { if (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var) continue; int propertyType = 0; int vmePropertyType = 0; quint32 propertyFlags = 0; if (p->type < builtinTypeCount) { propertyType = builtinTypes[p->type].metaType; vmePropertyType = propertyType; if (p->type == QV4::CompiledData::Property::Variant) propertyFlags |= QQmlPropertyData::IsQVariant; } else { Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || p->type == QV4::CompiledData::Property::Custom); QQmlType *qmltype = 0; if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) { compiler->recordError(p->location, tr("Invalid property type")); return false; } Q_ASSERT(qmltype); if (qmltype->isComposite()) { // Composite type usage QmlCompilation::TypeReference *typeRef = compiler->findTypeRef(p->customTypeNameIndex); Q_ASSERT(typeRef->component->compiledData != NULL); QQmlCompiledData *data = typeRef->component->compiledData; if (p->type == QV4::CompiledData::Property::Custom) { propertyType = data->metaTypeId; vmePropertyType = QMetaType::QObjectStar; } else { propertyType = data->listMetaTypeId; vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } } else { if (p->type == QV4::CompiledData::Property::Custom) { propertyType = qmltype->typeId(); vmePropertyType = QMetaType::QObjectStar; } else { propertyType = qmltype->qListTypeId(); vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } } if (p->type == QV4::CompiledData::Property::Custom) propertyFlags |= QQmlPropertyData::IsQObjectDerived; else propertyFlags |= QQmlPropertyData::IsQList; } if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) propertyFlags |= QQmlPropertyData::IsWritable; QString propertyName = stringAt(p->nameIndex); if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, effectiveSignalIndex); effectiveSignalIndex++; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; vmd->propertyCount++; } // Now do var properties propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { if (p->type != QV4::CompiledData::Property::Var) continue; quint32 propertyFlags = QQmlPropertyData::IsVarProperty; if (!p->flags & QV4::CompiledData::Property::IsReadOnly) propertyFlags |= QQmlPropertyData::IsWritable; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; vmd->propertyCount++; ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; QString propertyName = stringAt(p->nameIndex); if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, QMetaType::QVariant, effectiveSignalIndex); effectiveSignalIndex++; } // Alias property count. Actual data is setup in buildDynamicMetaAliases ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; // Dynamic slot data - comes after the property data for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; int formalsCount = 0; QQmlJS::AST::FormalParameterList *param = astFunction->formals; while (param) { formalsCount++; param = param->next; } VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### formalsCount, /* s->location.start.line */0 }; // ### VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); vmd->methodCount++; md = methodData; } return true; }
ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlTypeWrapper>()); QV4::ExecutionEngine *v4 = static_cast<QmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); Scoped<QmlTypeWrapper> w(scope, static_cast<QmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; QQmlContextData *context = v4->v8Engine->callingContext(); QObject *object = w->d()->object; if (w->d()->type) { QQmlType *type = w->d()->type; // singleton types are handled differently to other types. if (type->isSingleton()) { QQmlEngine *e = v4->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { // check for enum value if (name->startsWithUpper()) { if (w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums) { // ### Optimize QByteArray enumName = name->toQString().toUtf8(); const QMetaObject *metaObject = qobjectSingleton->metaObject(); for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); bool ok; int value = e.keyToValue(enumName.constData(), &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); } } } // check for property. return QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); } else if (!siinfo->scriptApi(e).isUndefined()) { // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); if (!!o) return o->get(name); } // Fall through to base implementation } else { if (name->startsWithUpper()) { bool ok = false; int value = type->enumValue(name, &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); // Fall through to base implementation } else if (w->d()->object) { QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); // Fall through to base implementation } // Fall through to base implementation } // Fall through to base implementation } else if (w->d()->typeNamespace) { Q_ASSERT(w->d()->importNamespace); QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace); if (r.isValid()) { if (r.type) { return create(scope.engine, object, r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); return scripts->getIndexed(r.scriptIndex); } else if (r.importNamespace) { return create(scope.engine, object, context->imports, r.importNamespace); } return QV4::Encode::undefined(); } // Fall through to base implementation } else { Q_ASSERT(!"Unreachable"); } if (hasProperty) *hasProperty = false; return Object::get(m, name, hasProperty); }
void tst_QQmlEngineDebugService::recursiveObjectTest( QObject *o, const QmlDebugObjectReference &oref, bool recursive) const { const QMetaObject *meta = o->metaObject(); QQmlType *type = QQmlMetaType::qmlType(meta); QString className = type ? QString(type->qmlTypeName()) : QString(meta->className()); className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1); QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o)); QCOMPARE(oref.name, o->objectName()); QCOMPARE(oref.className, className); QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject( qmlContext(o))); const QObjectList &children = o->children(); for (int i=0; i<children.count(); i++) { QObject *child = children[i]; if (!qmlContext(child)) continue; int debugId = QQmlDebugService::idForObject(child); QVERIFY(debugId >= 0); QmlDebugObjectReference cref; foreach (const QmlDebugObjectReference &ref, oref.children) { if (ref.debugId == debugId) { cref = ref; break; } } QVERIFY(cref.debugId >= 0); if (recursive) recursiveObjectTest(child, cref, true); } foreach (const QmlDebugPropertyReference &p, oref.properties) { QCOMPARE(p.objectDebugId, QQmlDebugService::idForObject(o)); // signal properties are fake - they are generated from QQmlAbstractBoundSignal children if (p.name.startsWith("on") && p.name.length() > 2 && p.name[2].isUpper()) { QString signal = p.value.toString(); QQmlBoundSignalExpression *expr = QQmlPropertyPrivate::signalExpression(QQmlProperty(o, p.name)); QVERIFY(expr && expr->expression() == signal); QVERIFY(p.valueTypeName.isEmpty()); QVERIFY(p.binding.isEmpty()); QVERIFY(!p.hasNotifySignal); continue; } QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name.toUtf8().constData())); QCOMPARE(p.name, QString::fromUtf8(pmeta.name())); if (pmeta.type() < QVariant::UserType && pmeta.userType() != QMetaType::QVariant) // TODO test complex types QCOMPARE(p.value , pmeta.read(o)); if (p.name == "parent") QVERIFY(p.valueTypeName == "QGraphicsObject*" || p.valueTypeName == "QQuickItem*"); else QCOMPARE(p.valueTypeName, QString::fromUtf8(pmeta.typeName())); QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding( QQmlProperty(o, p.name)); if (binding) QCOMPARE(binding->expression(), p.binding); QCOMPARE(p.hasNotifySignal, pmeta.hasNotifySignal()); QVERIFY(pmeta.isValid()); } }
QQmlInfo::~QQmlInfo() { if (0 == --d->ref) { QList<QQmlError> errors = d->errors; QQmlEngine *engine = 0; if (!d->buffer.isEmpty()) { QQmlError error; QObject *object = const_cast<QObject *>(d->object); if (object) { engine = qmlEngine(d->object); QString typeName; QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } else { typeName = QString::fromUtf8(object->metaObject()->className()); int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); if (marker != -1) typeName = typeName.left(marker); marker = typeName.indexOf(QLatin1String("_QML_")); if (marker != -1) { typeName = typeName.left(marker); typeName += QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } } } d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": ")); QQmlData *ddata = QQmlData::get(object, false); if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { error.setUrl(ddata->outerContext->url); error.setLine(ddata->lineNumber); error.setColumn(ddata->columnNumber); } } error.setDescription(d->buffer); errors.prepend(error); } QQmlEnginePrivate::warning(engine, errors); delete d; } }
bool EnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding) { bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum(); if (!prop->isEnum() && !isIntProp) return true; if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)) { compiler->recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(compiler->stringAt(binding->propertyNameIndex))); return false; } Q_ASSERT(binding->type = QV4::CompiledData::Binding::Type_Script); const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); if (!string.constData()->isUpper()) return true; int dot = string.indexOf(QLatin1Char('.')); if (dot == -1 || dot == string.length()-1) return true; if (string.indexOf(QLatin1Char('.'), dot+1) != -1) return true; QHashedStringRef typeName(string.constData(), dot); QString enumValue = string.mid(dot+1); if (isIntProp) { // Allow enum assignment to ints. bool ok; int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok); if (ok) { binding->type = QV4::CompiledData::Binding::Type_Number; binding->value.d = (double)enumval; binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; } return true; } QQmlType *type = 0; imports->resolveType(typeName, &type, 0, 0, 0); if (!type && typeName != QLatin1String("Qt")) return true; if (type && type->isComposite()) //No enums on composite (or composite singleton) types return true; int value = 0; bool ok = false; QQmlCompiledData::TypeReference *tr = resolvedTypes->value(obj->inheritedTypeNameIndex); if (type && tr && tr->type == type) { QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex); // When these two match, we can short cut the search if (mprop.isFlagType()) { value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); } else { value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); } } else { // Otherwise we have to search the whole type if (type) { value = type->enumValue(QHashedStringRef(enumValue), &ok); } else { QByteArray enumName = enumValue.toUtf8(); const QMetaObject *metaObject = StaticQtMetaObject::get(); for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); value = e.keyToValue(enumName.constData(), &ok); } } } if (!ok) return true; binding->type = QV4::CompiledData::Binding::Type_Number; binding->value.d = (double)value; binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; return true; }
bool QmcTypeCompiler::createTypeMap() { // qqmltypecompiler.cpp:81 const QHash<int, QmlCompilation::TypeReference> &resolvedTypes = compilation->typeReferences; for (QHash<int, QmlCompilation::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference); QQmlType *qmlType = resolvedType->type; if (resolvedType.value().composite) { // qqmltypecompiler.cpp:87 if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { QQmlError error; QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName()); error.setDescription(reason); error.setColumn(resolvedType->location.column); error.setLine(resolvedType->location.line); recordError(error); return false; } // qqmltypecompiler.cpp:96 Q_ASSERT(resolvedType->component); Q_ASSERT(resolvedType->component->compiledData); ref->component = resolvedType->component->compiledData; ref->component->addref(); } else if (qmlType) { ref->type = qmlType; Q_ASSERT(ref->type); if (resolvedType->needsCreation && !ref->type->isCreatable()) { QQmlError error; QString reason = ref->type->noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); error.setDescription(reason); error.setColumn(resolvedType->location.column); error.setLine(resolvedType->location.line); error.setUrl(compilation->url); recordError(error); return false; } if (ref->type->containsRevisionedAttributes()) { QQmlError cacheError; ref->typePropertyCache = QQmlEnginePrivate::get(compilation->engine)->cache( ref->type, resolvedType->minorVersion, cacheError); if (!ref->typePropertyCache) { cacheError.setColumn(resolvedType->location.column); cacheError.setLine(resolvedType->location.line); recordError(cacheError); return false; } ref->typePropertyCache->addref(); } } ref->majorVersion = resolvedType->majorVersion; ref->minorVersion = resolvedType->minorVersion; ref->doDynamicTypeCheck(); compiledData->resolvedTypes.insert(resolvedType.key(), ref.take()); } return true; }