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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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