/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** 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 http://www.qt.io/terms-conditions. For further ** information use the contact form at http://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 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QQMLTYPECOMPILER_P_H #define QQMLTYPECOMPILER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include QT_BEGIN_NAMESPACE class QQmlEnginePrivate; class QQmlCompiledData; class QQmlError; class QQmlTypeData; class QQmlImports; namespace QmlIR { struct Document; } namespace QV4 { namespace CompiledData { struct QmlUnit; struct Location; } } struct QQmlTypeCompiler { Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler) public: QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *document); bool compile(); QList compilationErrors() const { return errors; } void recordError(const QQmlError &error); QString stringAt(int idx) const; int registerString(const QString &str); QV4::IR::Module *jsIRModule() const; const QV4::CompiledData::Unit *qmlUnit() const; QUrl url() const { return typeData->finalUrl(); } QQmlEnginePrivate *enginePrivate() const { return engine; } const QQmlImports *imports() const; QHash *resolvedTypes(); QList *qmlObjects(); int rootObjectIndex() const; void setPropertyCaches(const QVector &caches); const QVector &propertyCaches() const; void setVMEMetaObjects(const QVector &metaObjects); QVector *vmeMetaObjects() const; QHash *objectIndexToIdForRoot(); QHash > *objectIndexToIdPerComponent(); QHash *customParserBindings(); QQmlJS::MemoryPool *memoryPool(); QStringRef newStringRef(const QString &string); const QV4::Compiler::StringTableGenerator *stringPool() const; void setDeferredBindingsPerObject(const QHash &deferredBindingsPerObject); void setBindingPropertyDataPerObject(const QVector &propertyData); const QHash &customParserCache() const { return customParsers; } QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const; private: QList errors; QQmlEnginePrivate *engine; QQmlCompiledData *compiledData; QQmlTypeData *typeData; QmlIR::Document *document; // index is string index of type name (use obj->inheritedTypeNameIndex) QHash customParsers; }; struct QQmlCompilePass { virtual ~QQmlCompilePass() {} QQmlCompilePass(QQmlTypeCompiler *typeCompiler); QString stringAt(int idx) const { return compiler->stringAt(idx); } protected: void recordError(const QV4::CompiledData::Location &location, const QString &description) const; QQmlTypeCompiler *compiler; }; class QQmlPropertyCacheCreator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator) public: QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler); ~QQmlPropertyCacheCreator(); bool buildMetaObjects(); protected: bool buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding); bool ensureMetaObject(int objectIndex); bool createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache); QQmlEnginePrivate *enginePrivate; const QList &qmlObjects; const QQmlImports *imports; QHash *resolvedTypes; QVector vmeMetaObjects; QVector propertyCaches; }; // "Converts" signal expressions to full-fleged function declarations with // parameters taken from the signal declarations // It also updates the QV4::CompiledData::Binding objects to set the property name // to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag. struct SignalHandlerConverter : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter) public: SignalHandlerConverter(QQmlTypeCompiler *typeCompiler); bool convertSignalHandlerExpressionsToFunctionDeclarations(); private: bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache); QQmlEnginePrivate *enginePrivate; const QList &qmlObjects; const QQmlImports *imports; const QHash &customParsers; const QHash &resolvedTypes; const QSet &illegalNames; const QVector &propertyCaches; }; // ### This will go away when the codegen resolves all enums to constant expressions // and we replace the constant expression with a literal binding instead of using // a script. class QQmlEnumTypeResolver : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlEnumTypeResolver) public: QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler); bool resolveEnumBindings(); private: bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding); int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const; const QList &qmlObjects; const QVector propertyCaches; const QQmlImports *imports; QHash *resolvedTypes; }; class QQmlCustomParserScriptIndexer: public QQmlCompilePass { public: QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler); void annotateBindingsWithScriptStrings(); private: void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false); const QList &qmlObjects; const QHash &customParsers; }; // Annotate properties bound to aliases with a flag class QQmlAliasAnnotator : public QQmlCompilePass { public: QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler); void annotateBindingsToAliases(); private: const QList &qmlObjects; const QVector propertyCaches; }; class QQmlScriptStringScanner : public QQmlCompilePass { public: QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler); void scan(); private: const QList &qmlObjects; const QVector propertyCaches; }; class QQmlComponentAndAliasResolver : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver) public: QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler); bool resolve(); protected: void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache); bool collectIdsAndAliases(int objectIndex); bool resolveAliases(); QQmlEnginePrivate *enginePrivate; QQmlJS::MemoryPool *pool; QList *qmlObjects; const int indexOfRootObject; // indices of the objects that are actually Component {} QVector componentRoots; // indices of objects that are the beginning of a new component // scope. This is sorted and used for binary search. QVector componentBoundaries; int _componentIndex; QHash _idToObjectIndex; QHash *_objectIndexToIdInScope; QList _objectsWithAliases; QHash *resolvedTypes; QVector propertyCaches; QVector *vmeMetaObjectData; QHash *objectIndexToIdForRoot; QHash > *objectIndexToIdPerComponent; }; class QQmlPropertyValidator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) public: QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler); bool validate(); const QQmlImports &imports() const; QQmlEnginePrivate *engine() const { return enginePrivate; } private: bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const; bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const; bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } bool canCoerce(int to, QQmlPropertyCache *fromMo) const; QQmlEnginePrivate *enginePrivate; const QV4::CompiledData::Unit *qmlUnit; const QHash &resolvedTypes; const QHash &customParsers; const QVector &propertyCaches; const QHash > objectIndexToIdPerComponent; QHash *customParserBindingsPerObject; // collected state variables, essentially write-only mutable QHash _deferredBindingsPerObject; mutable bool _seenObjectWithId; mutable QVector _bindingPropertyDataPerObject; }; // ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone. class QQmlJSCodeGenerator : public QQmlCompilePass { public: QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen); bool generateCodeForComponents(); private: bool compileComponent(int componentRoot, const QHash &objectIndexToId); bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex); bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } const QHash > &objectIndexToIdPerComponent; const QHash &resolvedTypes; const QHash &customParsers; const QList &qmlObjects; const QVector &propertyCaches; QmlIR::JSCodeGen * const v4CodeGen; }; class QQmlDefaultPropertyMerger : public QQmlCompilePass { public: QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler); void mergeDefaultProperties(); private: void mergeDefaultProperties(int objectIndex); const QList &qmlObjects; const QVector &propertyCaches; }; class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass, public QV4::IR::StmtVisitor { public: QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler); void reduceTranslationBindings(); private: void reduceTranslationBindings(int objectIndex); virtual void visitMove(QV4::IR::Move *move); virtual void visitJump(QV4::IR::Jump *) {} virtual void visitCJump(QV4::IR::CJump *) { discard(); } virtual void visitExp(QV4::IR::Exp *) { discard(); } virtual void visitPhi(QV4::IR::Phi *) {} virtual void visitRet(QV4::IR::Ret *ret); void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target); void discard() { _canSimplify = false; } bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding); bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding); const QList &qmlObjects; QV4::IR::Module *jsModule; bool _canSimplify; const QString *_nameOfFunctionCalled; QVector _functionParameters; int _functionCallReturnValue; QHash _temps; int _returnValueOfBindingExpression; int _synthesizedConsts; QVector irFunctionsToRemove; }; class QQmlIRFunctionCleanser : public QQmlCompilePass, public QV4::IR::StmtVisitor, public QV4::IR::ExprVisitor { public: QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector &functionsToRemove); void clean(); private: virtual void visitClosure(QV4::IR::Closure *closure); virtual void visitTemp(QV4::IR::Temp *) {} virtual void visitArgLocal(QV4::IR::ArgLocal *) {} virtual void visitMove(QV4::IR::Move *s) { s->source->accept(this); s->target->accept(this); } virtual void visitConvert(QV4::IR::Convert *e) { e->expr->accept(this); } virtual void visitPhi(QV4::IR::Phi *) { } virtual void visitExp(QV4::IR::Exp *s) { s->expr->accept(this); } virtual void visitJump(QV4::IR::Jump *) {} virtual void visitCJump(QV4::IR::CJump *s) { s->cond->accept(this); } virtual void visitRet(QV4::IR::Ret *s) { s->expr->accept(this); } virtual void visitConst(QV4::IR::Const *) {} virtual void visitString(QV4::IR::String *) {} virtual void visitRegExp(QV4::IR::RegExp *) {} virtual void visitName(QV4::IR::Name *) {} virtual void visitUnop(QV4::IR::Unop *e) { e->expr->accept(this); } virtual void visitBinop(QV4::IR::Binop *e) { e->left->accept(this); e->right->accept(this); } virtual void visitCall(QV4::IR::Call *e) { e->base->accept(this); for (QV4::IR::ExprList *it = e->args; it; it = it->next) it->expr->accept(this); } virtual void visitNew(QV4::IR::New *e) { e->base->accept(this); for (QV4::IR::ExprList *it = e->args; it; it = it->next) it->expr->accept(this); } virtual void visitSubscript(QV4::IR::Subscript *e) { e->base->accept(this); e->index->accept(this); } virtual void visitMember(QV4::IR::Member *e) { e->base->accept(this); } private: QV4::IR::Module *module; const QVector &functionsToRemove; QVector newFunctionIndices; }; QT_END_NAMESPACE #endif // QQMLTYPECOMPILER_P_H