| 1 | // Copyright (C) 2021 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 | 
| 3 |  | 
| 4 | #ifndef QMLTCVISITOR_H | 
| 5 | #define QMLTCVISITOR_H | 
| 6 |  | 
| 7 | #include <QtCore/qstring.h> | 
| 8 | #include <QtCore/qstringlist.h> | 
| 9 | #include <QtCore/qlist.h> | 
| 10 |  | 
| 11 | #include <QtQml/private/qqmlirbuilder_p.h> | 
| 12 | #include <private/qqmljsimportvisitor_p.h> | 
| 13 | #include <private/qqmljslogger_p.h> | 
| 14 |  | 
| 15 | QT_BEGIN_NAMESPACE | 
| 16 |  | 
| 17 | using namespace Qt::StringLiterals; | 
| 18 |  | 
| 19 | class QmltcVisitor : public QQmlJSImportVisitor | 
| 20 | { | 
| 21 |     void findCppIncludes(); | 
| 22 |     void postVisitResolve(const QHash<QQmlJSScope::ConstPtr, QList<QQmlJSMetaPropertyBinding>> | 
| 23 |                                   &qmlIrOrderedBindings); | 
| 24 |     void setupAliases(); | 
| 25 |     void checkNamesAndTypes(const QQmlJSScope::ConstPtr &type); | 
| 26 |     QString filePath(const QQmlJSScope::ConstPtr &scope) const; | 
| 27 |  | 
| 28 |     QString sourceDirectoryPath(const QString &path) const; | 
| 29 |  | 
| 30 |     using InlineComponentOrDocumentRootName = QQmlJSScope::InlineComponentOrDocumentRootName; | 
| 31 |  | 
| 32 | public: | 
| 33 |     QmltcVisitor(const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger, | 
| 34 |                  const QString &implicitImportDirectory, | 
| 35 |                  const QStringList &qmldirFiles = QStringList()); | 
| 36 |  | 
| 37 |     bool visit(QQmlJS::AST::UiObjectDefinition *) override; | 
| 38 |     void endVisit(QQmlJS::AST::UiObjectDefinition *) override; | 
| 39 |  | 
| 40 |     bool visit(QQmlJS::AST::UiObjectBinding *) override; | 
| 41 |     void endVisit(QQmlJS::AST::UiObjectBinding *) override; | 
| 42 |  | 
| 43 |     bool visit(QQmlJS::AST::UiScriptBinding *) override; | 
| 44 |  | 
| 45 |     bool visit(QQmlJS::AST::UiPublicMember *) override; | 
| 46 |  | 
| 47 |     bool visit(QQmlJS::AST::UiInlineComponent *) override; | 
| 48 |  | 
| 49 |     void endVisit(QQmlJS::AST::UiProgram *) override; | 
| 50 |  | 
| 51 |     QList<QQmlJSScope::ConstPtr> | 
| 52 |     qmlTypesWithQmlBases(const InlineComponentOrDocumentRootName &inlinedComponentName) const | 
| 53 |     { | 
| 54 |         return m_qmlTypesWithQmlBases.value(key: inlinedComponentName); | 
| 55 |     } | 
| 56 |     QSet<QString> cppIncludeFiles() const { return m_cppIncludes; } | 
| 57 |  | 
| 58 |     qsizetype creationIndex(const QQmlJSScope::ConstPtr &type) const | 
| 59 |     { | 
| 60 |         Q_ASSERT(type->scopeType() == QQmlSA::ScopeType::QMLScope); | 
| 61 |         return m_creationIndices.value(key: type, defaultValue: -1); | 
| 62 |     } | 
| 63 |  | 
| 64 |     qsizetype typeCount(const InlineComponentOrDocumentRootName &inlineComponent) const | 
| 65 |     { | 
| 66 |         return m_inlineComponentTypeCount.value(key: inlineComponent); | 
| 67 |     } | 
| 68 |  | 
| 69 |     qsizetype qmlComponentIndex(const QQmlJSScope::ConstPtr &type) const | 
| 70 |     { | 
| 71 |         Q_ASSERT(type->scopeType() == QQmlSA::ScopeType::QMLScope); | 
| 72 |         return m_syntheticTypeIndices.value(key: type, defaultValue: -1); | 
| 73 |     } | 
| 74 |  | 
| 75 |     qsizetype qmlIrObjectIndex(const QQmlJSScope::ConstPtr &type) const | 
| 76 |     { | 
| 77 |         Q_ASSERT(type->scopeType() == QQmlSA::ScopeType::QMLScope); | 
| 78 |         Q_ASSERT(m_qmlIrObjectIndices.contains(type)); | 
| 79 |         return m_qmlIrObjectIndices.value(key: type, defaultValue: -1); | 
| 80 |     } | 
| 81 |  | 
| 82 |     /*! \internal | 
| 83 |         Returns a runtime index counterpart of `id: foo` for \a type. Returns -1 | 
| 84 |         if \a type does not have an id. | 
| 85 |     */ | 
| 86 |     int runtimeId(const QQmlJSScope::ConstPtr &type) const | 
| 87 |     { | 
| 88 |         // NB: this function is expected to be called for "pure" types | 
| 89 |         Q_ASSERT(!m_typesWithId.contains(type) || m_typesWithId[type] != -1); | 
| 90 |         return m_typesWithId.value(key: type, defaultValue: -1); | 
| 91 |     } | 
| 92 |  | 
| 93 |     /*! \internal | 
| 94 |         Returns all encountered QML types. | 
| 95 |     */ | 
| 96 |     QList<QQmlJSScope::ConstPtr> allQmlTypes() const { return qmlTypes(); } | 
| 97 |  | 
| 98 |     /*! \internal | 
| 99 |         Returns QML types which return \c false in | 
| 100 |         \c{isComponentRootElement()}. The QHash key are the enclosing inline component | 
| 101 |         or the root document name when not beloning to any inline component. | 
| 102 |         Called "pure", because these are the ones | 
| 103 |         that are not wrapped into QQmlComponent. Pure QML types can be created | 
| 104 |         through direct constructor invocation. | 
| 105 |     */ | 
| 106 |     QList<QQmlJSScope::ConstPtr> | 
| 107 |     pureQmlTypes(const InlineComponentOrDocumentRootName &inlineComponent) const | 
| 108 |     { | 
| 109 |         return m_pureQmlTypes[inlineComponent]; | 
| 110 |     } | 
| 111 |  | 
| 112 |     /*! | 
| 113 |      * \internal | 
| 114 |      * Returns a list of the inline components. This list ends with the document root. | 
| 115 |      */ | 
| 116 |     QList<InlineComponentOrDocumentRootName> inlineComponentNames() const | 
| 117 |     { | 
| 118 |         return m_inlineComponentNames; | 
| 119 |     } | 
| 120 |     QQmlJSScope::ConstPtr | 
| 121 |     inlineComponent(const InlineComponentOrDocumentRootName &inlineComponentName) const | 
| 122 |     { | 
| 123 |         return m_inlineComponents.value(key: inlineComponentName); | 
| 124 |     } | 
| 125 |  | 
| 126 |     /*! \internal | 
| 127 |         Returns \c true when \a type has deferred bindings. Returns \c false | 
| 128 |         otherwise. | 
| 129 |     */ | 
| 130 |     bool hasDeferredBindings(const QQmlJSScope::ConstPtr &type) const | 
| 131 |     { | 
| 132 |         return m_typesWithDeferredBindings.contains(value: type); | 
| 133 |     } | 
| 134 |  | 
| 135 |     enum Mode { Import, Compile }; | 
| 136 |     void setMode(Mode mode) { m_mode = mode; } | 
| 137 |  | 
| 138 | protected: | 
| 139 |     QStringList m_qmlTypeNames; // names of QML types arranged as a stack | 
| 140 |     QHash<QString, int> m_qmlTypeNameCounts; | 
| 141 |     /*! | 
| 142 |      * \internal | 
| 143 |      *  QML types with composite/QML base types, mapped from inline component name to types | 
| 144 |      */ | 
| 145 |     QHash<InlineComponentOrDocumentRootName, QList<QQmlJSScope::ConstPtr>> m_qmlTypesWithQmlBases; | 
| 146 |     QSet<QString> m_cppIncludes; // all C++ includes found from QQmlJSScope hierarchy | 
| 147 |     QHash<InlineComponentOrDocumentRootName, QList<QQmlJSScope::ConstPtr>> | 
| 148 |             m_pureQmlTypes; // the ones not under QQmlComponent | 
| 149 |     /*! | 
| 150 |      * \internal | 
| 151 |      *  List of the names of the inline components, useful when iterating over QHash that | 
| 152 |      *  uses those names as keys. Ends with the the document root. | 
| 153 |      */ | 
| 154 |     QList<InlineComponentOrDocumentRootName> m_inlineComponentNames; | 
| 155 |     /*! | 
| 156 |      * \internal | 
| 157 |      *  Map inline component names to the corresponding type, and the document root | 
| 158 |      *  name to all types not belonging to any inline component. | 
| 159 |      */ | 
| 160 |     QHash<InlineComponentOrDocumentRootName, QQmlJSScope::Ptr> m_inlineComponents; | 
| 161 |     /*! | 
| 162 |      * \internal | 
| 163 |      *  Map types to their creation indices. Childrens are stored at their creation index in | 
| 164 |      *  a QObject* array either in the document root or in the inline component they belong to. | 
| 165 |      *  Therefore two types in the same file might have the same creation index, if they belong | 
| 166 |      *  to different inline components. | 
| 167 |      */ | 
| 168 |     QHash<QQmlJSScope::ConstPtr, qsizetype> m_creationIndices; | 
| 169 |     /*! | 
| 170 |      * \internal | 
| 171 |      *  Counts the types (pure qml types and explicit/implicit components) per inline component. | 
| 172 |      *  Needed to set the size of the QObject* array in the document root or the inline component | 
| 173 |      *  they belong to. | 
| 174 |      */ | 
| 175 |     QHash<InlineComponentOrDocumentRootName, qsizetype> m_inlineComponentTypeCount; | 
| 176 |     QHash<QQmlJSScope::ConstPtr, qsizetype> m_syntheticTypeIndices; | 
| 177 |     QHash<QQmlJSScope::ConstPtr, qsizetype> m_qmlIrObjectIndices; | 
| 178 |  | 
| 179 |     QSet<QQmlJSScope::ConstPtr> m_typesWithDeferredBindings; | 
| 180 |  | 
| 181 |     // prefer allQmlTypes or pureQmlTypes. this function is misleading in qmltc | 
| 182 |     QList<QQmlJSScope::ConstPtr> qmlTypes() const { return QQmlJSImportVisitor::qmlTypes(); } | 
| 183 |  | 
| 184 |     QHash<QQmlJSScope::ConstPtr, int> m_typesWithId; | 
| 185 |  | 
| 186 |     Mode m_mode = Mode::Import; | 
| 187 | }; | 
| 188 |  | 
| 189 | QT_END_NAMESPACE | 
| 190 |  | 
| 191 | #endif // QMLTCVISITOR_H | 
| 192 |  |