Esempio n. 1
0
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());
    }
}
Esempio n. 2
0
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();
}
Esempio n. 4
0
/*
    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;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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"));
}
Esempio n. 10
0
/*!
    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);
    }
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
/*!
    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;
}
Esempio n. 17
0
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);
            }
        }
    }
}
Esempio n. 18
0
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"));
}
Esempio n. 19
0
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), &notInRevision);
        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;
}
Esempio n. 20
0
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);
}
Esempio n. 21
0
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());
    }
}
Esempio n. 22
0
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;
    }
}
Esempio n. 23
0
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;
}
Esempio n. 24
0
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;
}