// // Check a CodeDirectory for basic integrity. This should ensure that the // version is understood by our code, and that the internal structure // (offsets etc.) is intact. In particular, it must make sure that no offsets // point outside the CodeDirectory. // Throws if the directory is corrupted or out of versioning bounds. // Returns if the version is usable (perhaps with degraded features due to // compatibility hacks). // // Note: There are some things we don't bother checking because they won't // cause crashes, and will just be flagged as nonsense later. For example, // a Bad Guy could overlap the identifier and hash fields, which is nonsense // but not dangerous. // void CodeDirectory::checkIntegrity() const { // check version for support if (!this->validateBlob()) MacOSError::throwMe(errSecCSSignatureInvalid); // busted if (version > compatibilityLimit) MacOSError::throwMe(errSecCSSignatureUnsupported); // too new - no clue if (version < earliestVersion) MacOSError::throwMe(errSecCSSignatureUnsupported); // too old - can't support if (version > currentVersion) secdebug("codedir", "%p version 0x%x newer than current 0x%x", this, uint32_t(version), currentVersion); // now check interior offsets for validity if (!stringAt(identOffset)) MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range if (version >= supportsTeamID && teamIDOffset != 0 && !stringAt(teamIDOffset)) MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range if (!contains(hashOffset - int64_t(hashSize) * nSpecialSlots, hashSize * (int64_t(nSpecialSlots) + nCodeSlots))) MacOSError::throwMe(errSecCSSignatureFailed); // hash array out of blob range if (const Scatter *scatter = this->scatterVector()) { // the optional scatter vector is terminated with an element having (count == 0) unsigned int pagesConsumed = 0; for (;; scatter++) { if (!contains(scatter, sizeof(Scatter))) MacOSError::throwMe(errSecCSSignatureFailed); if (scatter->count == 0) break; pagesConsumed += scatter->count; } if (!contains((*this)[pagesConsumed-1], hashSize)) // referenced too many main hash slots MacOSError::throwMe(errSecCSSignatureFailed); } }
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_D(Compiler); const QString &importUri = stringAt(import->uriIndex); const QString &importQualifier = stringAt(import->qualifierIndex); if (import->type == QV4::CompiledData::Import::ImportScript) { // TBD: qqmltypeloader.cpp:1320 QmlCompilation::ScriptReference scriptRef; scriptRef.location = import->location; scriptRef.qualifier = importQualifier; scriptRef.compilation = NULL; d->compilation->scripts.append(scriptRef); } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader; const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl); foreach (const QQmlDirParser::Script &script, qmldir->scripts()) { // TBD: qqmltypeloader.cpp:1343 qDebug() << "Library contains scripts"; QQmlError error; error.setDescription("Libraries with scripts not supported"); appendError(error); return false; } } } else {
bool PropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding) { const QmlIR::Object *obj = qmlObjects.at(objectIndex); QQmlPropertyCache *baseTypeCache = 0; QQmlPropertyData *instantiatingProperty = 0; if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { Q_ASSERT(referencingObjectIndex >= 0); QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); Q_ASSERT(parentCache); Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); bool notInRevision = false; instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); if (instantiatingProperty) { if (instantiatingProperty->isQObject()) { baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType); Q_ASSERT(baseTypeCache); } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) { baseTypeCache = enginePrivate->cache(vt->metaObject()); Q_ASSERT(baseTypeCache); } } } bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; if (!needVMEMetaObject) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { // On assignments are implemented using value interceptors, which require a VME meta object. needVMEMetaObject = true; // If the on assignment is inside a group property, we need to distinguish between QObject based // group properties and value type group properties. For the former the base type is derived from // the property that references us, for the latter we only need a meta-object on the referencing object // because interceptors can't go to the shared value type instances. if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) { needVMEMetaObject = false; if (!ensureMetaObject(referencingObjectIndex)) return false; } break; } } } if (obj->inheritedTypeNameIndex != 0) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType) { if (obj->propertyCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); return false; } if (obj->signalCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new signals.")); return false; } if (obj->functionCount() > 0) { compiler->recordError(obj->location, tr("Fully Dynamic types cannot declare new functions.")); return false; } } baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); Q_ASSERT(baseTypeCache); } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex); Q_ASSERT(typeRef); const QMetaObject *attachedMo = typeRef->type ? typeRef->type->attachedPropertiesType() : 0; if (!attachedMo) { compiler->recordError(instantiatingBinding->location, tr("Non-existent attached object")); return false; } baseTypeCache = enginePrivate->cache(attachedMo); Q_ASSERT(baseTypeCache); } if (needVMEMetaObject) { if (!createMetaObject(objectIndex, obj, baseTypeCache)) return false; } else if (baseTypeCache) { propertyCaches[objectIndex] = baseTypeCache; baseTypeCache->addref(); } if (propertyCaches.at(objectIndex)) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) if (binding->type >= QV4::CompiledData::Binding::Type_Object) { if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) return false; } } return true; }
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; }
bool QmcTypeUnitComponentAndAliasResolver::addAliases() { // add aliases //QmcUnitAlias al = {0, 0, 0, 8, 0, 0, 24}; //qmcTypeUnit->unit->aliases.append(al); // see QQmlComponentAndAliasResolver::resolve int effectiveAliasIndex = -1; int effectivePropertyIndex = -1; int effectiveSignalIndex = -1; int currentObjectIndex = -1; QQmlPropertyCache *propertyCache = NULL; foreach (const QmcUnitAlias &alias, qmcTypeUnit->unit->aliases) { if ((int)alias.objectIndex != currentObjectIndex) { currentObjectIndex = alias.objectIndex; effectiveAliasIndex = 0; propertyCache = qmcTypeUnit->propertyCaches.at(alias.objectIndex); effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); } Q_ASSERT(propertyCache); QQmlVMEMetaData::AliasData aliasData; aliasData.contextIdx = alias.contextIndex; aliasData.propertyIdx = alias.targetPropertyIndex; aliasData.propType = alias.propertyType; aliasData.flags = alias.flags; aliasData.notifySignal = alias.notifySignal; typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = qmcTypeUnit->vmeMetaObjects[alias.objectIndex]; Q_ASSERT(!dynamicData.isEmpty()); VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; Q_ASSERT(dynamicData.isDetached()); // TBD: propertyCache const QV4::CompiledData::Object *obj = qmcTypeUnit->compiledData->qmlUnit->objectAt(alias.objectIndex); Q_ASSERT(obj); Q_ASSERT(alias.propertyIndex < obj->nProperties); const QV4::CompiledData::Property *p = &obj->propertyTable()[alias.propertyIndex]; Q_ASSERT(p); QString propertyName = qmcTypeUnit->stringAt(p->nameIndex); const QString aliasPropertyValue = qmcTypeUnit->stringAt(p->aliasPropertyValueIndex); //const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = alias.targetObjectIndex; #if 0 const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); return false; } #endif QStringRef property; QStringRef subProperty; const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.')); if (propertySeparator != -1) { property = aliasPropertyValue.leftRef(propertySeparator); subProperty = aliasPropertyValue.midRef(propertySeparator + 1); } else property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); quint32 propertyFlags = QQmlPropertyData::IsAlias; int type = 0; bool writable = false; bool resettable = false; if (property.isEmpty()) { const QV4::CompiledData::Object *targetObject = qmcTypeUnit->compiledData->qmlUnit->objectAt(targetObjectIndex); QQmlCompiledData::TypeReference *typeRef = qmcTypeUnit->compiledData->resolvedTypes.value(targetObject->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->type) type = typeRef->type->typeId(); else type = typeRef->component->metaTypeId; //flags |= QML_ALIAS_FLAG_PTR; propertyFlags |= QQmlPropertyData::IsQObjectDerived; } else { QQmlPropertyCache *targetCache = qmcTypeUnit->propertyCaches.at(targetObjectIndex); Q_ASSERT(targetCache); QmlIR::PropertyResolver resolver(targetCache); QQmlPropertyData *targetProperty = resolver.property(property.toString()); if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { return false; } //propIdx = targetProperty->coreIndex; type = targetProperty->propType; writable = targetProperty->isWritable(); resettable = targetProperty->isResettable(); //notifySignal = targetProperty->notifyIndex; if (!subProperty.isEmpty()) { QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); if (!valueType) { return false; } //propType = type; int valueTypeIndex = valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { return false; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); //propIdx |= (valueTypeIndex << 16); if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) type = QVariant::Int; else type = valueType->metaObject()->property(valueTypeIndex).userType(); } else { if (targetProperty->isEnum()) { type = QVariant::Int; } else { // Copy type flags propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; if (targetProperty->isVarProperty()) propertyFlags |= QQmlPropertyData::IsQVariant; #if 0 if (targetProperty->isQObject()) flags |= QML_ALIAS_FLAG_PTR; #endif } } } if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) propertyFlags |= QQmlPropertyData::IsWritable; else propertyFlags &= ~QQmlPropertyData::IsWritable; if (resettable) propertyFlags |= QQmlPropertyData::IsResettable; else propertyFlags &= ~QQmlPropertyData::IsResettable; if ((int)alias.propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); } return true; }
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_D(Compiler); const QString &importUri = stringAt(import->uriIndex); const QString &importQualifier = stringAt(import->qualifierIndex); if (import->type == QV4::CompiledData::Import::ImportScript) { // TBD: qqmltypeloader.cpp:1320 QmlCompilation::ScriptReference scriptRef; scriptRef.location = import->location; scriptRef.qualifier = importQualifier; scriptRef.compilation = NULL; d->compilation->scripts.append(scriptRef); } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader; const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl); // File loading will import the dependency and takes care of // everything there. Adding a script reference here just seems // to add an unnecessary reference that might actually be a bug. // In case something is needed, see: qqmltypeloader.cpp:1343 } } else { // Is this a module? qDebug() << "Importing local module" << importUri; if (QQmlMetaType::isAnyModule(importUri)) { if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else { QQmlError error; error.setDescription("Unresolved import " + importUri); error.setLine(import->location.line); error.setColumn(import->location.column); error.setUrl(d->compilation->url); appendError(error); return false; // TBD: else add to unresolved imports qqmltypeloader.cpp:1356 } } } else { // qqmltypeloader.cpp:1383 Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile); QUrl qmldirUrl; if (importQualifier.isEmpty()) { qmldirUrl = compilation()->loadUrl.resolved(QUrl(importUri + QLatin1String("/qmldir"))); if (!QQmlImports::isLocal(qmldirUrl)) { qDebug() << "File import from network not supported"; QQmlError error; error.setDescription("File import from network not supported"); errors->append(error); return false; } } if (!compilation()->importCache->addFileImport(compilation()->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, /*incomplete*/ false, errors)) return false; } return true; }