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 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
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
138 bool checkCustomParser(const QQmlJSScope::ConstPtr &scope) override;
139 bool hasSeenCustomParsers() const { return m_seenCustomParsers; }
140
141protected:
142 QStringList m_qmlTypeNames; // names of QML types arranged as a stack
143 QHash<QString, int> m_qmlTypeNameCounts;
144 /*!
145 * \internal
146 * QML types with composite/QML base types, mapped from inline component name to types
147 */
148 QHash<InlineComponentOrDocumentRootName, QList<QQmlJSScope::ConstPtr>> m_qmlTypesWithQmlBases;
149 QSet<QString> m_cppIncludes; // all C++ includes found from QQmlJSScope hierarchy
150 QHash<InlineComponentOrDocumentRootName, QList<QQmlJSScope::ConstPtr>>
151 m_pureQmlTypes; // the ones not under QQmlComponent
152 /*!
153 * \internal
154 * List of the names of the inline components, useful when iterating over QHash that
155 * uses those names as keys. Ends with the the document root.
156 */
157 QList<InlineComponentOrDocumentRootName> m_inlineComponentNames;
158 /*!
159 * \internal
160 * Map inline component names to the corresponding type, and the document root
161 * name to all types not belonging to any inline component.
162 */
163 QHash<InlineComponentOrDocumentRootName, QQmlJSScope::Ptr> m_inlineComponents;
164 /*!
165 * \internal
166 * Map types to their creation indices. Childrens are stored at their creation index in
167 * a QObject* array either in the document root or in the inline component they belong to.
168 * Therefore two types in the same file might have the same creation index, if they belong
169 * to different inline components.
170 */
171 QHash<QQmlJSScope::ConstPtr, qsizetype> m_creationIndices;
172 /*!
173 * \internal
174 * Counts the types (pure qml types and explicit/implicit components) per inline component.
175 * Needed to set the size of the QObject* array in the document root or the inline component
176 * they belong to.
177 */
178 QHash<InlineComponentOrDocumentRootName, qsizetype> m_inlineComponentTypeCount;
179 QHash<QQmlJSScope::ConstPtr, qsizetype> m_syntheticTypeIndices;
180 QHash<QQmlJSScope::ConstPtr, qsizetype> m_qmlIrObjectIndices;
181
182 QSet<QQmlJSScope::ConstPtr> m_typesWithDeferredBindings;
183
184 // prefer allQmlTypes or pureQmlTypes. this function is misleading in qmltc
185 QList<QQmlJSScope::ConstPtr> qmlTypes() const { return QQmlJSImportVisitor::qmlTypes(); }
186
187 QHash<QQmlJSScope::ConstPtr, int> m_typesWithId;
188
189 Mode m_mode = Mode::Import;
190
191 bool m_seenCustomParsers = false;
192};
193
194QT_END_NAMESPACE
195
196#endif // QMLTCVISITOR_H
197

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