aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qqmltypecompiler.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-05-20 17:05:50 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-05-31 15:18:55 +0200
commit6c76ee30ce1662ca8f8368de5ebd1e6bcfdf0d9e (patch)
treebea1db48da70a74565afab07801f20f143f8067d /src/qml/compiler/qqmltypecompiler.cpp
parent2f24150b03a8141b3e64442bcfcc08448b9a79e5 (diff)
Eliminate qmldevtools_build
Move the relevant files into more fitting locations and build the devtools from only parser, compiler and qmldirparser. Change-Id: Ibf37a1187f36d02983f9f43c6622acb243785b7b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/compiler/qqmltypecompiler.cpp')
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1429
1 files changed, 0 insertions, 1429 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
deleted file mode 100644
index 66320b8db9..0000000000
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ /dev/null
@@ -1,1429 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltypecompiler_p.h"
-
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlobjectcreator_p.h>
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlcomponent_p.h>
-#include <private/qqmlpropertyresolver_p.h>
-
-#define COMPILE_EXCEPTION(token, desc) \
- { \
- recordError((token)->location, desc); \
- return false; \
- }
-
-QT_BEGIN_NAMESPACE
-
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
- : resolvedTypes(resolvedTypeCache)
- , engine(engine)
- , typeData(typeData)
- , dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
- , document(parsedQML)
-{
-}
-
-QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
-{
- // Build property caches and VME meta object data
-
- for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
- it != end; ++it) {
- QQmlCustomParser *customParser = (*it)->type.customParser();
- if (customParser)
- customParsers.insert(it.key(), customParser);
- }
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
-
- {
- QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
- QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
- if (error.isSet()) {
- recordError(error);
- return nullptr;
- }
- }
-
- {
- QQmlDefaultPropertyMerger merger(this);
- merger.mergeDefaultProperties();
- }
-
- {
- SignalHandlerConverter converter(this);
- if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
- return nullptr;
- }
-
- {
- QQmlEnumTypeResolver enumResolver(this);
- if (!enumResolver.resolveEnumBindings())
- return nullptr;
- }
-
- {
- QQmlCustomParserScriptIndexer cpi(this);
- cpi.annotateBindingsWithScriptStrings();
- }
-
- {
- QQmlAliasAnnotator annotator(this);
- annotator.annotateBindingsToAliases();
- }
-
- // Resolve component boundaries and aliases
-
- {
- // Scan for components, determine their scopes and resolve aliases within the scope.
- QQmlComponentAndAliasResolver resolver(this);
- if (!resolver.resolve())
- return nullptr;
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches);
- }
-
- {
- QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
- if (!deferredAndCustomParserBindingScanner.scanObject())
- return nullptr;
- }
-
- if (!document->javaScriptCompilationUnit.unitData()) {
- // Compile JS binding expressions and signal handlers if necessary
- {
- // We can compile script strings ahead of time, but they must be compiled
- // without type optimizations as their scope is always entirely dynamic.
- QQmlScriptStringScanner sss(this);
- sss.scan();
- }
-
- document->jsModule.fileName = typeData->urlString();
- document->jsModule.finalUrl = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, &document->jsGenerator.stringTable, engine->v4engine()->illegalNames());
- QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
- if (!jsCodeGen.generateCodeForComponents())
- return nullptr;
-
- document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
- }
-
- // Generate QML compiled type data structures
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(*document, dependencyHasher);
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
- = QV4::ExecutableCompilationUnit::create(std::move(
- document->javaScriptCompilationUnit));
- compilationUnit->typeNameCache = typeNameCache;
- compilationUnit->resolvedTypes = *resolvedTypes;
- compilationUnit->propertyCaches = std::move(m_propertyCaches);
- Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
-
- if (errors.isEmpty())
- return compilationUnit;
- else
- return nullptr;
-}
-
-void QQmlTypeCompiler::recordError(QQmlError error)
-{
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
-{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
-{
- recordError(error.location, error.description);
-}
-
-QString QQmlTypeCompiler::stringAt(int idx) const
-{
- return document->stringAt(idx);
-}
-
-int QQmlTypeCompiler::registerString(const QString &str)
-{
- return document->jsGenerator.registerString(str);
-}
-
-int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
-{
- return document->jsGenerator.registerConstant(v);
-}
-
-const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
-{
- return document->javaScriptCompilationUnit.unitData();
-}
-
-const QQmlImports *QQmlTypeCompiler::imports() const
-{
- return &typeData->imports();
-}
-
-QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
-{
- return &document->objects;
-}
-
-void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
-{
- m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() > 0);
-}
-
-const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
-{
- return &m_propertyCaches;
-}
-
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
-QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
-{
- return document->jsParserEngine.pool();
-}
-
-QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
-{
- return document->jsParserEngine.newStringRef(string);
-}
-
-const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
-{
- return &document->jsGenerator.stringTable;
-}
-
-QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
-{
- return object->bindingAsString(document, scriptIndex);
-}
-
-void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
-{
- const quint32 moduleIdx = registerString(module);
- const quint32 qualifierIdx = registerString(qualifier);
-
- for (int i = 0, count = document->imports.count(); i < count; ++i) {
- const QV4::CompiledData::Import *existingImport = document->imports.at(i);
- if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
- && existingImport->uriIndex == moduleIdx
- && existingImport->qualifierIndex == qualifierIdx)
- return;
- }
- auto pool = memoryPool();
- QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
- import->type = QV4::CompiledData::Import::ImportLibrary;
- import->majorVersion = majorVersion;
- import->minorVersion = minorVersion;
- import->uriIndex = moduleIdx;
- import->qualifierIndex = qualifierIdx;
- document->imports.append(import);
-}
-
-QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
- : compiler(typeCompiler)
-{
-}
-
-
-
-SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlObjects(*typeCompiler->qmlObjects())
- , imports(typeCompiler->imports())
- , customParsers(typeCompiler->customParserCache())
- , illegalNames(typeCompiler->enginePrivate()->v4engine()->illegalNames())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
-{
- for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
- if (!cache)
- continue;
- if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
- if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
- continue;
- }
- const QString elementName = stringAt(obj->inheritedTypeNameIndex);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
- return false;
- }
- return true;
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
-{
- // map from signal name defined in qml itself to list of parameters
- QHash<QString, QStringList> customSignals;
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QString propertyName = stringAt(binding->propertyNameIndex);
- // Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
- auto *typeRef = resolvedType(binding->propertyNameIndex);
- QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid()) {
- if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
- if (type.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
-
- const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
- if (!attachedType)
- COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
- QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
- return false;
- continue;
- }
-
- if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
- continue;
-
- QQmlPropertyResolver resolver(propertyCache);
-
- Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
- propertyName.remove(0, 2);
-
- // Note that the property name could start with any alpha or '_' or '$' character,
- // so we need to do the lower-casing of the first alpha character.
- for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
- if (propertyName.at(firstAlphaIndex).isUpper()) {
- propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
- break;
- }
- }
-
- QList<QString> parameters;
-
- bool notInRevision = false;
- QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
- if (signal) {
- int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
- sigIndex = propertyCache->originalClone(sigIndex);
-
- bool unnamedParameter = false;
-
- QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
- for (int i = 0; i < parameterNames.count(); ++i) {
- const QString param = QString::fromUtf8(parameterNames.at(i));
- if (param.isEmpty())
- unnamedParameter = true;
- else if (unnamedParameter) {
- COMPILE_EXCEPTION(binding, tr("Signal uses unnamed parameter followed by named parameter."));
- } else if (illegalNames.contains(param)) {
- COMPILE_EXCEPTION(binding, tr("Signal parameter \"%1\" hides global variable.").arg(param));
- }
- parameters += param;
- }
- } else {
- if (notInRevision) {
- // Try assinging it as a property later
- if (resolver.property(propertyName, /*notInRevision ptr*/nullptr))
- continue;
-
- const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
-
- auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
- const QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (type.isValid()) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion()));
- } else {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
- }
- }
-
- // Try to look up the signal parameter names in the object itself
-
- // build cache if necessary
- if (customSignals.isEmpty()) {
- for (const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
- const QString &signalName = stringAt(signal->nameIndex);
- customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
- }
-
- for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
- const QString propName = stringAt(property->nameIndex);
- customSignals.insert(propName, QStringList());
- }
- }
-
- QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName);
- if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
- entry = customSignals.constFind(alternateName);
- }
-
- if (entry == customSignals.constEnd()) {
- // Can't find even a custom signal, then just don't do anything and try
- // keeping the binding as a regular property assignment.
- continue;
- }
-
- parameters = entry.value();
- }
-
- // Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
- continue;
- }
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
- }
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
-
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- for (const QString &param : qAsConst(parameters)) {
- QStringRef paramNameRef = compiler->newStringRef(param);
-
- QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
- }
-
- if (paramList)
- paramList = paramList->finish(pool);
-
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- QQmlJS::AST::FunctionDeclaration *functionDeclaration = nullptr;
- if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) {
- if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) {
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body);
- functionDeclaration->functionToken = fe->functionToken;
- functionDeclaration->identifierToken = fe->identifierToken;
- functionDeclaration->lparenToken = fe->lparenToken;
- functionDeclaration->rparenToken = fe->rparenToken;
- functionDeclaration->lbraceToken = fe->lbraceToken;
- functionDeclaration->rbraceToken = fe->rbraceToken;
- }
- }
- if (!functionDeclaration) {
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
- body = body->finish();
-
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
- functionDeclaration->lbraceToken = functionDeclaration->functionToken
- = foe->node->firstSourceLocation();
- functionDeclaration->rbraceToken = foe->node->lastSourceLocation();
- }
- foe->node = functionDeclaration;
- binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
- }
- return true;
-}
-
-QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , imports(typeCompiler->imports())
-{
-}
-
-bool QQmlEnumTypeResolver::resolveEnumBindings()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
-
- const QString propertyName = stringAt(binding->propertyNameIndex);
- bool notInRevision = false;
- QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
- if (!pd)
- continue;
-
- if (!pd->isEnum() && pd->propType() != QMetaType::Int)
- continue;
-
- if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
- return false;
- }
- }
-
- return true;
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
-{
- if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
- }
- binding->type = QV4::CompiledData::Binding::Type_Number;
- binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
-// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
- return true;
-}
-
-bool QQmlEnumTypeResolver::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))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
-
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
- const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- if (!string.constData()->isUpper())
- return true;
-
- // we support one or two '.' in the enum phrase:
- // * <TypeName>.<EnumValue>
- // * <TypeName>.<ScopedEnumName>.<EnumValue>
-
- int dot = string.indexOf(QLatin1Char('.'));
- if (dot == -1 || dot == string.length()-1)
- return true;
-
- int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
- if (dot2 != -1 && dot2 != string.length()-1) {
- if (!string.at(dot+1).isUpper())
- return true;
- if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
- return true;
- }
-
- QHashedStringRef typeName(string.constData(), dot);
- const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
- // ### consider supporting scoped enums in Qt namespace
- const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
-
- if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
- // Allow enum assignment to ints.
- bool ok;
- int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
- if (ok) {
- if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
- return false;
- }
- return true;
- }
- QQmlType type;
- imports->resolveType(typeName, &type, nullptr, nullptr, nullptr);
-
- if (!type.isValid() && !isQtObject)
- return true;
-
- int value = 0;
- bool ok = false;
-
- auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
- QByteArray enumName = enumValue.toUtf8();
- if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
- return true;
-
- if (mprop.isFlagType()) {
- value = menum.keysToValue(enumName.constData(), &ok);
- } else {
- value = menum.keyToValue(enumName.constData(), &ok);
- }
- } else {
- // Otherwise we have to search the whole type
- if (type.isValid()) {
- if (!scopedEnumName.isEmpty())
- value = type.scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
- else
- value = type.enumValue(compiler->enginePrivate(), 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;
-
- return assignEnumToBinding(binding, enumValue, value, isQtObject);
-}
-
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &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;
- imports->resolveType(scope, &type, nullptr, nullptr, nullptr);
- if (!type.isValid())
- return -1;
- if (!enumName.isEmpty())
- return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
- return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
- }
-
- const QMetaObject *mo = StaticQtMetaObject::get();
- int i = mo->enumeratorCount();
- const QByteArray ba = enumValue.toUtf8();
- while (i--) {
- int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
- if (*ok)
- return v;
- }
- return -1;
-}
-
-QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , customParsers(typeCompiler->customParserCache())
-{
-}
-
-void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
-{
- scanObjectRecursively(/*root object*/0);
-}
-
-void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
-{
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- if (!annotateScriptBindings)
- annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
-}
-
-QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-void QQmlAliasAnnotator::annotateBindingsToAliases()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (!binding->isValueBinding())
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
- }
- }
-}
-
-QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlScriptStringScanner::scan()
-{
- const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (!pd || pd->propType() != scriptStringMetaType)
- continue;
-
- QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
- }
-}
-
-QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , pool(typeCompiler->memoryPool())
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
-{
-}
-
-static bool isUsableComponent(const QMetaObject *metaObject)
-{
- // The metaObject is a component we're interested in if it either is a QQmlComponent itself
- // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
- // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
-
- if (metaObject == &QQmlComponent::staticMetaObject)
- return true;
-
- for (; metaObject; metaObject = metaObject->superClass()) {
- if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
- return true;
- }
-
- return false;
-}
-
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
-{
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- auto *tr = resolvedType(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(tr);
-
- const QMetaObject *firstMetaObject = nullptr;
- if (tr->type.isValid())
- firstMetaObject = tr->type.metaObject();
- else if (tr->compilationUnit)
- firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- if (isUsableComponent(firstMetaObject))
- continue;
- // if here, not a QQmlComponent, so needs wrapping
-
- QQmlPropertyData *pd = nullptr;
- if (binding->propertyNameIndex != quint32(0)) {
- bool notInRevision = false;
- pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
- } else {
- pd = defaultProperty;
- }
- if (!pd || !pd->isQObject())
- continue;
-
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion());
- const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
- while (mo) {
- if (mo == &QQmlComponent::staticMetaObject)
- break;
- mo = mo->superClass();
- }
-
- if (!mo)
- continue;
-
- // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
- QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- Q_ASSERT(componentType.isValid());
- const QString qualifier = QStringLiteral("QmlInternals");
-
- compiler->addImport(componentType.module(), qualifier, componentType.majorVersion(), componentType.minorVersion());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString()));
- syntheticComponent->location = binding->valueLocation;
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::ResolvedTypeReference;
- typeRef->type = componentType;
- typeRef->majorVersion = componentType.majorVersion();
- typeRef->minorVersion = componentType.minorVersion();
- insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef);
- }
-
- qmlObjects->append(syntheticComponent);
- const int componentIndex = qmlObjects->count() - 1;
- // Keep property caches symmetric
- QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- propertyCaches.append(componentCache);
-
- QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
- *syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
- Q_ASSERT(error.isEmpty());
- Q_UNUSED(error);
-
- binding->value.objectIndex = componentIndex;
-
- componentRoots.append(componentIndex);
- }
-}
-
-bool QQmlComponentAndAliasResolver::resolve()
-{
- // Detect real Component {} objects as well as implicitly defined components, such as
- // someItemDelegate: Item {}
- // In the implicit case Item is surrounded by a synthetic Component {} because the property
- // on the left hand side is of QQmlComponent type.
- const int objCountWithoutSynthesizedComponents = qmlObjects->count();
- for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- QmlIR::Object *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
-
- bool isExplicitComponent = false;
-
- if (obj->inheritedTypeNameIndex) {
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(tref);
- if (tref->type.metaObject() == &QQmlComponent::staticMetaObject)
- isExplicitComponent = true;
- }
- if (!isExplicitComponent) {
- if (cache)
- findAndRegisterImplicitComponents(obj, cache);
- continue;
- }
-
- obj->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (obj->functionCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->signalCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
-
- if (obj->bindingCount() == 0)
- COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
-
- const QmlIR::Binding *rootBinding = obj->firstBinding();
-
- for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
- if (b->propertyNameIndex != 0)
- COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
- }
-
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
- COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
-
- // For the root object, we are going to collect ids/aliases and resolve them for as a separate
- // last pass.
- if (i != 0)
- componentRoots.append(i);
-
- }
-
- for (int i = 0; i < componentRoots.count(); ++i) {
- QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
- const QmlIR::Binding *rootBinding = component->firstBinding();
-
- _idToObjectIndex.clear();
-
- _objectsWithAliases.clear();
-
- if (!collectIdsAndAliases(rootBinding->value.objectIndex))
- return false;
-
- component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(componentRoots.at(i)))
- return false;
- }
-
- // Collect ids and aliases for root
- _idToObjectIndex.clear();
- _objectsWithAliases.clear();
-
- collectIdsAndAliases(/*root object*/0);
-
- QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
- rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(/*root object*/0))
- return false;
-
- // Implicit component insertion may have added objects and thus we also need
- // to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(std::move(propertyCaches));
- compiler->setComponentRoots(componentRoots);
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
-
- if (obj->idNameIndex != 0) {
- if (_idToObjectIndex.contains(obj->idNameIndex)) {
- recordError(obj->locationOfIdProperty, tr("id is not unique"));
- return false;
- }
- obj->id = _idToObjectIndex.count();
- _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
- }
-
- if (obj->aliasCount() > 0)
- _objectsWithAliases.append(objectIndex);
-
- // Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return true;
-
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
- }
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
-{
- if (_objectsWithAliases.isEmpty())
- return true;
-
- QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
-
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
-
- QQmlCompileError error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isSet()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
- if (error.isSet()) {
- recordError(error);
- return false;
- }
- atLeastOneAliasResolved = true;
- } else if (result == SomeAliasesResolved) {
- atLeastOneAliasResolved = true;
- pendingObjects.append(objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
- }
- qSwap(_objectsWithAliases, pendingObjects);
- } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
-
- if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
- const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
- for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
- recordError(alias->location, tr("Circular alias reference detected"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
- if (!obj->aliasCount())
- return AllAliasesResolved;
-
- int numResolvedAliases = 0;
- bool seenUnresolvedAlias = false;
-
- for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
- continue;
-
- seenUnresolvedAlias = true;
-
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
- if (targetObjectIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
- break;
- }
-
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
-
- const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
-
- 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());
-
- QQmlPropertyIndex propIdx;
-
- if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- } else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
- if (!targetCache) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- QQmlPropertyResolver resolver(targetCache);
-
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
-
- // If it's an alias that we haven't resolved yet, try again later.
- if (!targetProperty) {
- bool aliasPointsToOtherAlias = false;
- int localAliasIndex = 0;
- for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
- aliasPointsToOtherAlias = true;
- break;
- }
- }
- if (aliasPointsToOtherAlias) {
- if (targetObjectIndex == objectIndex) {
- alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- ++numResolvedAliases;
- continue;
- }
-
- // restore
- alias->idIndex = idIndex;
- // Try again later and resolve the target alias first.
- break;
- }
- }
-
- if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
-
- if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
- if (!valueTypeMetaObject) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
-
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
-
- propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
- } else {
- if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- }
- }
-
- alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- numResolvedAliases++;
- }
-
- if (numResolvedAliases == 0)
- return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
-
- return SomeAliasesResolved;
-}
-
-QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , customParsers(typeCompiler->customParserCache())
- , _seenObjectWithId(false)
-{
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
-{
- return scanObject(/*root object*/0);
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
- if (obj->idNameIndex != 0)
- _seenObjectWithId = true;
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return scanObject(componentBinding->value.objectIndex);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return true;
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
-
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QQmlPropertyData *pd = nullptr;
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- continue;
- }
- }
-
- if (name.isEmpty()) {
- pd = defaultProperty;
- name = defaultPropertyName;
- } else {
- if (name.constData()->isUpper())
- continue;
-
- bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision,
- QQmlPropertyResolver::CheckRevision);
- }
-
- bool seenSubObjectWithId = false;
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = scanObject(binding->value.objectIndex);
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- if (!subObjectValid)
- return false;
- _seenObjectWithId |= seenSubObjectWithId;
- }
-
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
- && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
-
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
- obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
- }
-
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (!pd) {
- if (customParser) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- }
- }
- }
-
- return true;
-}
-
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
- : QQmlCompilePass(typeCompiler)
- , customParsers(typeCompiler->customParserCache())
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , v4CodeGen(v4CodeGen)
-{
-}
-
-bool QQmlJSCodeGenerator::generateCodeForComponents()
-{
- const QVector<quint32> &componentRoots = compiler->componentRoots();
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool QQmlJSCodeGenerator::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = qmlObjects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
- return false;
-
- return true;
-}
-
-bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = qmlObjects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
- return true;
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
- if (!jsErrors.isEmpty()) {
- for (const QQmlError &e : jsErrors)
- compiler->recordError(e);
- return false;
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
- }
-
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
-
- return true;
-}
-
-QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties()
-{
- for (int i = 0; i < qmlObjects.count(); ++i)
- mergeDefaultProperties(i);
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
-{
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return;
-
- QmlIR::Object *object = qmlObjects.at(objectIndex);
-
- QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
- QmlIR::Binding *bindingsToReinsert = nullptr;
- QmlIR::Binding *tail = nullptr;
-
- QmlIR::Binding *previousBinding = nullptr;
- QmlIR::Binding *binding = object->firstBinding();
- while (binding) {
- if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
- previousBinding = binding;
- binding = binding->next;
- continue;
- }
-
- QmlIR::Binding *toReinsert = binding;
- binding = object->unlinkBinding(previousBinding, binding);
-
- if (!tail) {
- bindingsToReinsert = toReinsert;
- tail = toReinsert;
- } else {
- tail->next = toReinsert;
- tail = tail->next;
- }
- tail->next = nullptr;
- }
-
- binding = bindingsToReinsert;
- while (binding) {
- QmlIR::Binding *toReinsert = binding;
- binding = binding->next;
- object->insertSorted(toReinsert);
- }
-}
-
-QT_END_NAMESPACE