1// Copyright (C) 2019 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 QQMLJSIMPORTEDMEMBERSVISITOR_P_H
5#define QQMLJSIMPORTEDMEMBERSVISITOR_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16
17#include <private/qtqmlcompilerexports_p.h>
18
19#include "qqmljsannotation_p.h"
20#include "qqmljsimporter_p.h"
21#include "qqmljslogger_p.h"
22#include "qqmljsscope_p.h"
23#include "qqmljsscopesbyid_p.h"
24
25#include <QtCore/qvariant.h>
26#include <QtCore/qstack.h>
27
28#include <private/qqmljsast_p.h>
29#include <private/qqmljsdiagnosticmessage_p.h>
30#include <private/qv4compileddata_p.h>
31
32#include <functional>
33
34QT_BEGIN_NAMESPACE
35
36namespace QQmlJS::Dom {
37class QQmlDomAstCreatorWithQQmlJSScope;
38}
39
40struct QQmlJSResourceFileMapper;
41class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSImportVisitor : public QQmlJS::AST::Visitor
42{
43public:
44 QQmlJSImportVisitor();
45 QQmlJSImportVisitor(const QQmlJSScope::Ptr &target,
46 QQmlJSImporter *importer, QQmlJSLogger *logger,
47 const QString &implicitImportDirectory,
48 const QStringList &qmldirFiles = QStringList());
49 ~QQmlJSImportVisitor();
50
51 using QQmlJS::AST::Visitor::endVisit;
52 using QQmlJS::AST::Visitor::postVisit;
53 using QQmlJS::AST::Visitor::preVisit;
54 using QQmlJS::AST::Visitor::visit;
55
56 QQmlJSScope::Ptr result() const { return m_exportedRootScope; }
57
58 const QQmlJSLogger *logger() const { return m_logger; }
59 QQmlJSLogger *logger() { return m_logger; }
60
61 QQmlJSImporter::ImportedTypes imports() const { return m_rootScopeImports; }
62 QQmlJSScopesById addressableScopes() const { return m_scopesById; }
63 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> signalHandlers() const
64 {
65 return m_signalHandlers;
66 }
67 QSet<QQmlJSScope::ConstPtr> literalScopesToCheck() const { return m_literalScopesToCheck; }
68 QList<QQmlJSScope::ConstPtr> qmlTypes() const { return m_qmlTypes; }
69 QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> scopesBylocation() const
70 {
71 return m_scopesByIrLocation;
72 }
73
74 static QString implicitImportDirectory(
75 const QString &localFile, QQmlJSResourceFileMapper *mapper);
76
77 // ### should this be restricted?
78 QQmlJSImporter *importer() { return m_importer; }
79 const QQmlJSImporter *importer() const { return m_importer; }
80
81 struct UnfinishedBinding
82 {
83 QQmlJSScope::Ptr owner;
84 std::function<QQmlJSMetaPropertyBinding()> create;
85 QQmlJSScope::BindingTargetSpecifier specifier = QQmlJSScope::SimplePropertyTarget;
86 };
87
88protected:
89 // Linter warnings, we might want to move this at some point
90 bool visit(QQmlJS::AST::StringLiteral *) override;
91
92 bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
93 void endVisit(QQmlJS::AST::ExpressionStatement *ast) override;
94
95 bool visit(QQmlJS::AST::UiProgram *) override;
96 void endVisit(QQmlJS::AST::UiProgram *) override;
97 bool visit(QQmlJS::AST::UiObjectDefinition *) override;
98 void endVisit(QQmlJS::AST::UiObjectDefinition *) override;
99 bool visit(QQmlJS::AST::UiInlineComponent *) override;
100 void endVisit(QQmlJS::AST::UiInlineComponent *) override;
101 bool visit(QQmlJS::AST::UiPublicMember *) override;
102 void endVisit(QQmlJS::AST::UiPublicMember *) override;
103 bool visit(QQmlJS::AST::UiRequired *required) override;
104 bool visit(QQmlJS::AST::UiScriptBinding *) override;
105 void endVisit(QQmlJS::AST::UiScriptBinding *) override;
106 bool visit(QQmlJS::AST::UiArrayBinding *) override;
107 void endVisit(QQmlJS::AST::UiArrayBinding *) override;
108 bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
109 bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
110 void endVisit(QQmlJS::AST::FunctionExpression *) override;
111 bool visit(QQmlJS::AST::UiSourceElement *) override;
112 bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
113 void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
114 bool visit(QQmlJS::AST::ClassExpression *ast) override;
115 void endVisit(QQmlJS::AST::ClassExpression *) override;
116 bool visit(QQmlJS::AST::UiImport *import) override;
117 bool visit(QQmlJS::AST::UiPragma *pragma) override;
118 bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
119 void endVisit(QQmlJS::AST::ClassDeclaration *ast) override;
120 bool visit(QQmlJS::AST::ForStatement *ast) override;
121 void endVisit(QQmlJS::AST::ForStatement *ast) override;
122 bool visit(QQmlJS::AST::ForEachStatement *ast) override;
123 void endVisit(QQmlJS::AST::ForEachStatement *ast) override;
124 bool visit(QQmlJS::AST::Block *ast) override;
125 void endVisit(QQmlJS::AST::Block *ast) override;
126 bool visit(QQmlJS::AST::CaseBlock *ast) override;
127 void endVisit(QQmlJS::AST::CaseBlock *ast) override;
128 bool visit(QQmlJS::AST::Catch *ast) override;
129 void endVisit(QQmlJS::AST::Catch *ast) override;
130 bool visit(QQmlJS::AST::WithStatement *withStatement) override;
131 void endVisit(QQmlJS::AST::WithStatement *ast) override;
132
133 bool visit(QQmlJS::AST::VariableDeclarationList *vdl) override;
134 bool visit(QQmlJS::AST::FormalParameterList *fpl) override;
135
136 bool visit(QQmlJS::AST::UiObjectBinding *uiob) override;
137 void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override;
138
139 bool visit(QQmlJS::AST::ExportDeclaration *exp) override;
140 void endVisit(QQmlJS::AST::ExportDeclaration *exp) override;
141
142 bool visit(QQmlJS::AST::ESModule *module) override;
143 void endVisit(QQmlJS::AST::ESModule *module) override;
144
145 bool visit(QQmlJS::AST::Program *program) override;
146 void endVisit(QQmlJS::AST::Program *program) override;
147
148 void endVisit(QQmlJS::AST::FieldMemberExpression *) override;
149 bool visit(QQmlJS::AST::IdentifierExpression *idexp) override;
150
151 bool visit(QQmlJS::AST::PatternElement *) override;
152
153 void throwRecursionDepthError() override;
154
155 QString m_implicitImportDirectory;
156 QStringList m_qmldirFiles;
157 QQmlJSScope::Ptr m_currentScope;
158 const QQmlJSScope::Ptr m_exportedRootScope;
159 QQmlJSImporter *m_importer = nullptr;
160 QQmlJSLogger *m_logger = nullptr;
161
162 using RootDocumentNameType = QQmlJSScope::RootDocumentNameType;
163 using InlineComponentNameType = QQmlJSScope::InlineComponentNameType;
164 using InlineComponentOrDocumentRootName = QQmlJSScope::RootDocumentNameType;
165 QQmlJSScope::InlineComponentOrDocumentRootName m_currentRootName =
166 QQmlJSScope::RootDocumentNameType();
167 bool m_nextIsInlineComponent = false;
168 bool m_rootIsSingleton = false;
169 QQmlJSScope::Ptr m_savedBindingOuterScope;
170 QQmlJSScope::ConstPtr m_globalScope;
171 QQmlJSScopesById m_scopesById;
172 QQmlJSImporter::ImportedTypes m_rootScopeImports;
173 QList<QQmlJSScope::ConstPtr> m_qmlTypes;
174
175 // We need to record the locations as IR locations because those contain less data.
176 // This way we can look up objects by IR location later.
177 QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> m_scopesByIrLocation;
178
179 // Maps all qmlNames to the source location of their import
180 QMultiHash<QString, QQmlJS::SourceLocation> m_importTypeLocationMap;
181 // Maps all static modules to the source location of their import
182 QMultiHash<QString, QQmlJS::SourceLocation> m_importStaticModuleLocationMap;
183 // Contains all import source locations (could be extracted from above but that is expensive)
184 QSet<QQmlJS::SourceLocation> m_importLocations;
185 // A set of all types that have been used during type resolution
186 QSet<QString> m_usedTypes;
187
188 QList<UnfinishedBinding> m_bindings;
189
190 // stores JS functions and Script bindings per scope (only the name). mimics
191 // the content of QmlIR::Object::functionsAndExpressions
192 QHash<QQmlJSScope::ConstPtr, QList<QString>> m_functionsAndExpressions;
193
194 struct FunctionOrExpressionIdentifier
195 {
196 QQmlJSScope::ConstPtr scope;
197 QString name;
198 friend bool operator==(const FunctionOrExpressionIdentifier &x,
199 const FunctionOrExpressionIdentifier &y)
200 {
201 return x.scope == y.scope && x.name == y.name;
202 }
203 friend bool operator!=(const FunctionOrExpressionIdentifier &x,
204 const FunctionOrExpressionIdentifier &y)
205 {
206 return !(x == y);
207 }
208 friend size_t qHash(const FunctionOrExpressionIdentifier &x, size_t seed = 0)
209 {
210 return qHashMulti(seed, args: x.scope, args: x.name);
211 }
212 };
213
214 // tells whether last-processed UiScriptBinding is truly a script binding
215 bool m_thisScriptBindingIsJavaScript = false;
216 QStack<FunctionOrExpressionIdentifier> m_functionStack;
217 // stores the number of functions inside each function
218 QHash<FunctionOrExpressionIdentifier, int> m_innerFunctions;
219 QQmlJSMetaMethod::RelativeFunctionIndex
220 addFunctionOrExpression(const QQmlJSScope::ConstPtr &scope, const QString &name);
221 void forgetFunctionExpression(const QString &name);
222 int synthesizeCompilationUnitRuntimeFunctionIndices(const QQmlJSScope::Ptr &scope,
223 int count) const;
224 void populateRuntimeFunctionIndicesForDocument() const;
225
226 void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
227 const QQmlJS::SourceLocation &location);
228 // Finds an existing scope before attempting to create a new one. Returns \c
229 // true if the scope already exists and \c false if the new scope is created
230 bool enterEnvironmentNonUnique(QQmlJSScope::ScopeType type, const QString &name,
231 const QQmlJS::SourceLocation &location);
232 void leaveEnvironment();
233
234 // A set of types that have not been resolved but have been used during the
235 // AST traversal
236 QSet<QQmlJSScope::ConstPtr> m_unresolvedTypes;
237 template<typename ErrorHandler>
238 bool isTypeResolved(const QQmlJSScope::ConstPtr &type, ErrorHandler handle)
239 {
240 if (type->isFullyResolved())
241 return true;
242
243 // Note: ignore duplicates, but only after we are certain that the type
244 // is still unresolved
245 if (m_unresolvedTypes.contains(value: type))
246 return false;
247
248 m_unresolvedTypes.insert(value: type);
249
250 handle(type);
251 return false;
252 }
253 bool isTypeResolved(const QQmlJSScope::ConstPtr &type);
254
255 QVector<QQmlJSAnnotation> parseAnnotations(QQmlJS::AST::UiAnnotationList *list);
256 void setAllBindings();
257 void addDefaultProperties();
258 void processDefaultProperties();
259 void processPropertyBindings();
260 void checkRequiredProperties();
261 void processPropertyTypes();
262 void processPropertyBindingObjects();
263 void flushPendingSignalParameters();
264
265 QQmlJSScope::ConstPtr scopeById(const QString &id, const QQmlJSScope::ConstPtr &current);
266
267 void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
268 void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
269 void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
270 bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
271
272 enum class BindingExpressionParseResult { Invalid, Script, Literal, Translation };
273 BindingExpressionParseResult parseBindingExpression(const QString &name,
274 const QQmlJS::AST::Statement *statement);
275 bool isImportPrefix(QString prefix) const;
276
277 // Used to temporarily store annotations for functions and generators wrapped in UiSourceElements
278 QVector<QQmlJSAnnotation> m_pendingMethodAnnotations;
279
280 struct PendingPropertyType
281 {
282 QQmlJSScope::Ptr scope;
283 QString name;
284 QQmlJS::SourceLocation location;
285 };
286
287 struct PendingPropertyObjectBinding
288 {
289 QQmlJSScope::Ptr scope;
290 QQmlJSScope::Ptr childScope;
291 QString name;
292 QQmlJS::SourceLocation location;
293 bool onToken;
294 };
295
296 struct RequiredProperty
297 {
298 QQmlJSScope::Ptr scope;
299 QString name;
300 QQmlJS::SourceLocation location;
301 };
302
303 /*!
304 Utility wrapper that adds visibility scope to the data.
305
306 This wrapper becomes useful for binding processing where we need to know
307 both the property (or signal handler) owner and the scope in which the
308 binding is executed (the "visibility" scope).
309
310 As visibility scope (and data) does not typically have sufficient
311 information about a proper source location of that data, the location
312 also has to be provided to simplify the error reporting.
313 */
314 template<typename T>
315 struct WithVisibilityScope
316 {
317 QQmlJSScope::Ptr visibilityScope;
318 QQmlJS::SourceLocation dataLocation;
319 T data;
320 };
321
322 QHash<QQmlJSScope::Ptr, QVector<QQmlJSScope::Ptr>> m_pendingDefaultProperties;
323 QVector<PendingPropertyType> m_pendingPropertyTypes;
324 QVector<PendingPropertyObjectBinding> m_pendingPropertyObjectBindings;
325 QVector<RequiredProperty> m_requiredProperties;
326 QVector<QQmlJSScope::Ptr> m_objectBindingScopes;
327 QVector<QQmlJSScope::Ptr> m_objectDefinitionScopes;
328
329 QHash<QQmlJSScope::Ptr, QVector<WithVisibilityScope<QString>>> m_propertyBindings;
330
331 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
332 QSet<QQmlJSScope::ConstPtr> m_literalScopesToCheck;
333 QQmlJS::SourceLocation m_pendingSignalHandler;
334
335private:
336 void checkSignal(
337 const QQmlJSScope::ConstPtr &signalScope, const QQmlJS::SourceLocation &location,
338 const QString &handlerName, const QStringList &handlerParameters);
339 void importBaseModules();
340 void resolveAliasesAndIds();
341 void handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding);
342
343 void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
344 void processImportWarnings(
345 const QString &what,
346 const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
347 void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc);
348 void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
349 const QQmlJS::SourceLocation &location);
350 void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
351 const QQmlJS::SourceLocation &location);
352
353 void importFromHost(const QString &path, const QString &prefix,
354 const QQmlJS::SourceLocation &location);
355 void importFromQrc(const QString &path, const QString &prefix,
356 const QQmlJS::SourceLocation &location);
357
358public:
359 friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope;
360};
361
362QT_END_NAMESPACE
363
364#endif // QQMLJSIMPORTEDMEMBERSVISITOR_P_H
365

source code of qtdeclarative/src/qmlcompiler/qqmljsimportvisitor_p.h