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
15QT_BEGIN_NAMESPACE
16
17using namespace Qt::StringLiterals;
18
19class QmltcVisitor : public QQmlJSImportVisitor
20{
21 void findCppIncludes();
22 void postVisitResolve(const QHash<QQmlJSScope::ConstPtr, QList<QQmlJSMetaPropertyBinding>>
23 &qmlIrOrderedBindings);
24 void setupAliases();
25 void checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &type);
26 void setRootFilePath();
27
28 QString sourceDirectoryPath(const QString &path);
29
30 using InlineComponentOrDocumentRootName = QQmlJSScope::InlineComponentOrDocumentRootName;
31
32public:
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
138protected:
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
189QT_END_NAMESPACE
190
191#endif // QMLTCVISITOR_H
192

source code of qtdeclarative/tools/qmltc/qmltcvisitor.h