aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp3
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h3
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp66
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h9
-rw-r--r--src/qml/qml/qqmlcompiler.cpp24
-rw-r--r--src/qml/qml/qqmlcompiler_p.h1
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp17
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h8
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp5
-rw-r--r--src/qml/types/qqmllistmodel.cpp164
-rw-r--r--src/qml/types/qqmllistmodel_p.h2
11 files changed, 252 insertions, 50 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 46bb07f8bc..629671399d 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1640,7 +1640,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (elementName.isEmpty())
continue;
QQmlCompiledData::TypeReference *tr = unit->resolvedTypes.value(obj->inheritedTypeNameIndex);
- if (tr && tr->type && tr->type->customParser())
+ QQmlCustomParser *customParser = (tr && tr->type) ? tr->type->customParser() : 0;
+ if (customParser && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
continue;
QQmlPropertyCache *cache = unit->propertyCaches.value(objectIndex);
Q_ASSERT(cache);
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index f1050f4476..0b70701515 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -173,7 +173,8 @@ struct Pragma
struct CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
- : disableAcceleratedLookups(false)
+ : node(0)
+ , disableAcceleratedLookups(false)
{}
CompiledFunctionOrExpression(AST::Node *n)
: node(n)
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index a684ebd959..00fc9c5925 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -201,7 +201,7 @@ bool QQmlTypeCompiler::compile()
}
// Sanity check property bindings
- QQmlPropertyValidator validator(this);
+ QQmlPropertyValidator validator(this, runtimeFunctionIndices);
if (!validator.validate())
return false;
@@ -295,6 +295,16 @@ MemoryPool *QQmlTypeCompiler::memoryPool()
return parsedQML->jsParserEngine.pool();
}
+const QList<CompiledFunctionOrExpression> &QQmlTypeCompiler::functions() const
+{
+ return parsedQML->functions;
+}
+
+void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
+{
+ compiledData->customParserBindings = bindings;
+}
+
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
@@ -1113,19 +1123,23 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices)
: QQmlCompilePass(typeCompiler)
, qmlUnit(typeCompiler->qmlUnit())
, resolvedTypes(*typeCompiler->resolvedTypes())
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, customParserData(typeCompiler->customParserData())
+ , runtimeFunctionIndices(runtimeFunctionIndices)
{
}
bool QQmlPropertyValidator::validate()
{
- return validateObject(qmlUnit->indexOfRootObject);
+ if (!validateObject(qmlUnit->indexOfRootObject))
+ return false;
+ compiler->setCustomParserBindings(customParserBindings);
+ return true;
}
const QQmlImports &QQmlPropertyValidator::imports() const
@@ -1133,6 +1147,22 @@ const QQmlImports &QQmlPropertyValidator::imports() const
return *compiler->imports();
}
+AST::Node *QQmlPropertyValidator::astForBinding(int scriptIndex) const
+{
+ // ####
+ int reverseIndex = runtimeFunctionIndices.indexOf(scriptIndex);
+ if (reverseIndex == -1)
+ return 0;
+ return compiler->functions().value(reverseIndex).node;
+}
+
+QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *)
+{
+ int id = customParserBindings.count();
+ customParserBindings.append(binding->value.compiledScriptIndex);
+ return id;
+}
+
bool QQmlPropertyValidator::validateObject(int objectIndex)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
@@ -1158,16 +1188,30 @@ bool QQmlPropertyValidator::validateObject(int objectIndex)
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && !customParser) {
- if (!validateObject(binding->value.objectIndex))
- return false;
- }
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
- || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
- if (customParser)
+ if (customParser) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
+ customBindings << binding;
+ continue;
+ }
+ } else if ((binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && (!customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
- continue;
+ continue;
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Object
+ || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ customBindings << binding;
+ continue;
+ }
+ }
+
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (!validateObject(binding->value.objectIndex))
+ return false;
+ // Nothing further to check for attached properties.
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ continue;
}
const QString name = stringAt(binding->propertyNameIndex);
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index e6a34fa376..4340279df8 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -92,6 +92,8 @@ struct QQmlTypeCompiler
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
QHash<int, QByteArray> *customParserData();
QQmlJS::MemoryPool *memoryPool();
+ const QList<CompiledFunctionOrExpression> &functions() const;
+ void setCustomParserBindings(const QVector<int> &bindings);
private:
QList<QQmlError> errors;
@@ -176,13 +178,14 @@ class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCom
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
+ QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices);
bool validate();
// Re-implemented for QQmlCustomParser
virtual const QQmlImports &imports() const;
-
+ virtual QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
+ virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
private:
bool validateObject(int objectIndex);
@@ -194,6 +197,8 @@ private:
const QVector<QQmlPropertyCache *> &propertyCaches;
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, QByteArray> *customParserData;
+ QVector<int> customParserBindings;
+ const QVector<int> &runtimeFunctionIndices;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 069345ecd3..a0c1bbcdda 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -2665,30 +2665,6 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
return true;
}
-int QQmlCompiler::bindingIdentifier(const QString &name, const Variant &value, const BindingContext &ctxt)
-{
- JSBindingReference *reference = pool->New<JSBindingReference>();
- reference->expression = value;
- reference->property = pool->New<Property>();
- reference->property->setName(name);
- reference->value = 0;
- reference->bindingContext = ctxt;
- reference->bindingContext.owner++;
- // Unfortunately this is required for example for PropertyChanges where the bindings
- // will be executed in the dynamic scope of the target, so we can't resolve any lookups
- // at run-time.
- reference->disableLookupAcceleration = true;
-
- const int id = output->customParserBindings.count();
- output->customParserBindings.append(0); // Filled in later.
- reference->customParserBindingsIndex = id;
-
- compileState->totalBindingsCount++;
- compileState->bindings.prepend(reference);
-
- return id;
-}
-
QQmlBinding::Identifier QQmlCompiler::bindingIdentifier(const Variant &value, const QString &name, QQmlCustomParser *customParser)
{
JSBindingReference *reference = pool->New<JSBindingReference>();
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 58943b206a..0feebed93d 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -349,7 +349,6 @@ public:
static bool isAttachedPropertyName(const QHashedStringRef &);
static bool isSignalPropertyName(const QHashedStringRef &);
- int bindingIdentifier(const QString &name, const QQmlScript::Variant& value, const QQmlCompilerTypes::BindingContext &ctxt); // for QQmlCustomParser::bindingIndex
virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&value, const QString&name, QQmlCustomParser *customParser);
virtual const QQmlImports &imports() const { return unit->imports(); }
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index ca23451774..90bd2fd875 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -230,13 +230,6 @@ void QQmlCustomParser::clearErrors()
exceptions.clear();
}
-QByteArray QQmlCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- Q_UNUSED(qmlUnit)
- Q_UNUSED(bindings)
- return QByteArray();
-}
-
/*!
Reports an error with the given \a description.
@@ -349,6 +342,16 @@ QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Va
return compiler->bindingIdentifier(value, name, this);
}
+QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding)
+{
+ return compiler->bindingIdentifier(binding, this);
+}
+
+AST::Node *QQmlCustomParser::astForBinding(int scriptIndex) const
+{
+ return compiler->astForBinding(scriptIndex);
+}
+
struct StaticQtMetaObject : public QObject
{
static const QMetaObject *get()
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 2f1a9ddec8..b4d716b240 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -117,6 +117,9 @@ struct QQmlCustomParserCompilerBackend
const QMetaObject *resolveType(const QString& name) const;
virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&, QQmlCustomParser *) { return QQmlBinding::Invalid; }
+ virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
+
+ virtual QQmlJS::AST::Node *astForBinding(int) const { return 0; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
@@ -137,7 +140,7 @@ public:
Flags flags() const { return m_flags; }
virtual QByteArray compile(const QList<QQmlCustomParserProperty> &)=0;
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); // ### make pure virtual
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0;
virtual void setCustomData(QObject *, const QByteArray &)=0;
QList<QQmlError> errors() const { return exceptions; }
@@ -154,6 +157,9 @@ protected:
const QMetaObject *resolveType(const QString&) const;
QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&);
+ QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
+
+ QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
private:
QList<QQmlError> exceptions;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index b1f4a8e1bf..2cacb0e546 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -997,8 +997,9 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
context->setIdProperty(idEntry.value(), instance);
if (customParser) {
- QByteArray data = compiledData->customParserData.value(index);
- customParser->setCustomData(instance, data);
+ QHash<int, QByteArray>::ConstIterator entry = compiledData->customParserData.find(index);
+ if (entry != compiledData->customParserData.constEnd())
+ customParser->setCustomData(instance, *entry);
}
if (isComponent)
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index eeb4aa0861..03dfb6690f 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2384,6 +2384,136 @@ bool QQmlListModelParser::compileProperty(const QQmlCustomParserProperty &prop,
return true;
}
+bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
+{
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
+ QString objName = qmlUnit->header.stringAt(target->inheritedTypeNameIndex);
+ if (objName != listElementTypeName) {
+ const QMetaObject *mo = resolveType(objName);
+ if (mo != &QQmlListElement::staticMetaObject) {
+ error(target, QQmlListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ listElementTypeName = objName; // cache right name for next time
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Push;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ if (!qmlUnit->header.stringAt(target->idIndex).isEmpty()) {
+ error(binding, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
+ return false;
+ }
+
+ const QV4::CompiledData::Binding *binding = target->bindingTable();
+ for (quint32 i = 0; i < target->nBindings; ++i, ++binding) {
+ QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
+ if (propName.isEmpty()) {
+ error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ ListInstruction li;
+ int ref = data.count();
+ data.append(propName.toUtf8());
+ data.append('\0');
+ li.type = ListInstruction::Set;
+ li.dataIdx = ref;
+ instr << li;
+
+ if (!compileProperty(qmlUnit, binding, instr, data))
+ return false;
+
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ } else {
+ int ref = data.count();
+
+ QByteArray d;
+
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ d += char(QQmlScript::Variant::String);
+ d += binding->valueAsString(&qmlUnit->header).toUtf8();
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ d += char(QQmlScript::Variant::Number);
+ d += QByteArray::number(binding->valueAsNumber(),'g',20);
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ d += char(QQmlScript::Variant::Boolean);
+ d += char(binding->valueAsBoolean());
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QString scriptStr = binding->valueAsScriptString(&qmlUnit->header);
+ if (definesEmptyList(scriptStr)) {
+ d[0] = char(QQmlScript::Variant::Invalid); // marks empty list
+ } else {
+ QByteArray script = scriptStr.toUtf8();
+ bool ok;
+ int v = evaluateEnum(script, &ok);
+ if (!ok) {
+ using namespace QQmlJS;
+ AST::Node *node = astForBinding(binding->value.compiledScriptIndex);
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node))
+ node = stmt->expression;
+ AST::StringLiteral *literal = 0;
+ if (AST::CallExpression *callExpr = AST::cast<AST::CallExpression *>(node)) {
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(callExpr->base)) {
+ if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) {
+ if (callExpr->arguments && !callExpr->arguments->next)
+ literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->expression);
+ if (!literal) {
+ error(binding, QQmlListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString()));
+ return false;
+ }
+ } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) {
+ if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next)
+ literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->next->expression);
+ if (!literal) {
+ error(binding, QQmlListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP"));
+ return false;
+ }
+ }
+ }
+ }
+
+ if (literal) {
+ d[0] = char(QQmlScript::Variant::String);
+ d += literal->value.toUtf8();
+ } else {
+ error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
+ return false;
+ }
+ } else {
+ d[0] = char(QQmlScript::Variant::Number);
+ d += QByteArray::number(v);
+ }
+ }
+ }
+
+ d.append('\0');
+ data.append(d);
+
+ ListInstruction li;
+ li.type = ListInstruction::Value;
+ li.dataIdx = ref;
+ instr << li;
+ }
+
+ return true;
+}
+
QByteArray QQmlListModelParser::compile(const QList<QQmlCustomParserProperty> &customProps)
{
QList<ListInstruction> instr;
@@ -2420,6 +2550,40 @@ QByteArray QQmlListModelParser::compile(const QList<QQmlCustomParserProperty> &c
return rv;
}
+QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+{
+ QList<ListInstruction> instr;
+ QByteArray data;
+ listElementTypeName = QString(); // unknown
+
+ foreach (const QV4::CompiledData::Binding *binding, bindings) {
+ QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
+ if (!propName.isEmpty()) { // isn't default property
+ error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
+ return QByteArray();
+ }
+ if (!compileProperty(qmlUnit, binding, instr, data))
+ return QByteArray();
+ }
+
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
+ data.count();
+
+ QByteArray rv;
+ rv.resize(size);
+
+ ListModelData *lmd = (ListModelData *)rv.data();
+ lmd->dataOffset = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction);
+ lmd->instrCount = instr.count();
+ for (int ii = 0; ii < instr.count(); ++ii)
+ lmd->instructions()[ii] = instr.at(ii);
+ ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
+
+ return rv;
+}
+
void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d)
{
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index a7487537c5..172d857687 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -160,6 +160,7 @@ class QQmlListModelParser : public QQmlCustomParser
public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
QByteArray compile(const QList<QQmlCustomParserProperty> &);
+ QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
void setCustomData(QObject *, const QByteArray &);
private:
@@ -175,6 +176,7 @@ private:
ListInstruction *instructions() const;
};
bool compileProperty(const QQmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data);
+ bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data);
bool definesEmptyList(const QString &);