Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmljsimportvisitor_p.h
Go to the documentation of this file.
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// Qt-Security score:significant
4
5#ifndef QQMLJSIMPORTEDMEMBERSVISITOR_P_H
6#define QQMLJSIMPORTEDMEMBERSVISITOR_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17
18#include <private/qduplicatetracker_p.h>
19#include <private/qqmljsannotation_p.h>
20#include <private/qqmljsast_p.h>
21#include <private/qqmljscontextualtypes_p.h>
22#include <private/qqmljsdiagnosticmessage_p.h>
23#include <private/qqmljsimporter_p.h>
24#include <private/qqmljslogger_p.h>
25#include <private/qqmljsscope_p.h>
26#include <private/qqmljsscopesbyid_p.h>
27#include <private/qv4compileddata_p.h>
28
29#include <QtQmlCompiler/qtqmlcompilerexports.h>
30
31#include <QtCore/qvariant.h>
32#include <QtCore/qstack.h>
33
34#include <functional>
35
36QT_BEGIN_NAMESPACE
37
41
42struct QQmlJSResourceFileMapper;
43class Q_QMLCOMPILER_EXPORT QQmlJSImportVisitor : public QQmlJS::AST::Visitor
44{
45public:
46 QQmlJSImportVisitor(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 QDuplicateTracker<QQmlJSScope::ConstPtr> *knownUnresolvedTypes() { return &m_unresolvedTypes; }
64 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> signalHandlers() const
65 {
66 return m_signalHandlers;
67 }
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
88 QStringList seenModuleQualifiers() const { return m_seenModuleQualifiers; }
89
90protected:
91 bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
92 void endVisit(QQmlJS::AST::ExpressionStatement *ast) override;
93
94 bool visit(QQmlJS::AST::UiProgram *) override;
95 void endVisit(QQmlJS::AST::UiProgram *) override;
96 bool visit(QQmlJS::AST::UiObjectDefinition *) override;
97 void endVisit(QQmlJS::AST::UiObjectDefinition *) override;
98 bool visit(QQmlJS::AST::UiInlineComponent *) override;
99 void endVisit(QQmlJS::AST::UiInlineComponent *) override;
100 bool visit(QQmlJS::AST::UiPublicMember *) override;
101 void endVisit(QQmlJS::AST::UiPublicMember *) override;
102 bool visit(QQmlJS::AST::UiRequired *required) override;
103 bool visit(QQmlJS::AST::UiScriptBinding *) override;
104 void endVisit(QQmlJS::AST::UiScriptBinding *) override;
105 bool visit(QQmlJS::AST::UiArrayBinding *) override;
106 void endVisit(QQmlJS::AST::UiArrayBinding *) override;
107 bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
108 bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
109 void endVisit(QQmlJS::AST::FunctionExpression *) override;
110 bool visit(QQmlJS::AST::UiSourceElement *) override;
111 bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
112 void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
113 bool visit(QQmlJS::AST::ClassExpression *ast) override;
114 void endVisit(QQmlJS::AST::ClassExpression *) override;
115 bool visit(QQmlJS::AST::UiImport *import) override;
116 bool visit(QQmlJS::AST::UiPragma *pragma) override;
117 bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
118 void endVisit(QQmlJS::AST::ClassDeclaration *ast) override;
119 bool visit(QQmlJS::AST::ForStatement *ast) override;
120 void endVisit(QQmlJS::AST::ForStatement *ast) override;
121 bool visit(QQmlJS::AST::ForEachStatement *ast) override;
122 void endVisit(QQmlJS::AST::ForEachStatement *ast) override;
123 bool visit(QQmlJS::AST::Block *ast) override;
124 void endVisit(QQmlJS::AST::Block *ast) override;
125 bool visit(QQmlJS::AST::CaseBlock *ast) override;
126 void endVisit(QQmlJS::AST::CaseBlock *ast) override;
127 bool visit(QQmlJS::AST::Catch *ast) override;
128 void endVisit(QQmlJS::AST::Catch *ast) override;
129 bool visit(QQmlJS::AST::WithStatement *withStatement) override;
130 void endVisit(QQmlJS::AST::WithStatement *ast) override;
131
132 bool visit(QQmlJS::AST::FormalParameterList *fpl) override;
133
134 bool visit(QQmlJS::AST::UiObjectBinding *uiob) override;
135 void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override;
136
137 bool visit(QQmlJS::AST::ExportDeclaration *exp) override;
138 void endVisit(QQmlJS::AST::ExportDeclaration *exp) override;
139
140 bool visit(QQmlJS::AST::ESModule *module) override;
141 void endVisit(QQmlJS::AST::ESModule *module) override;
142
143 bool visit(QQmlJS::AST::Program *program) override;
144 void endVisit(QQmlJS::AST::Program *program) override;
145
146 void endVisit(QQmlJS::AST::FieldMemberExpression *) override;
147 bool visit(QQmlJS::AST::IdentifierExpression *idexp) override;
148
149 bool visit(QQmlJS::AST::PatternElement *) override;
150
151 bool visit(QQmlJS::AST::IfStatement *) override;
152
153 void throwRecursionDepthError() override;
154
155 virtual bool checkCustomParser(const QQmlJSScope::ConstPtr &scope);
156
157 void setScopeName(QQmlJSScope::Ptr &scope, QQmlJSScope::ScopeType type, const QString &name);
158 virtual bool safeInsertJSIdentifier(QQmlJSScope::Ptr &scope, const QString &name,
159 const QQmlJSScope::JavaScriptIdentifier &identifier);
160 void createAttachedAndGroupedScopes(QQmlJS::AST::UiQualifiedId *propertyName);
161 int openAttachedAndGroupedScopes(QQmlJS::AST::UiQualifiedId *propertyName);
162
163 QString m_implicitImportDirectory;
164 QStringList m_qmldirFiles;
165 QQmlJSScope::Ptr m_currentScope;
166 const QQmlJSScope::Ptr m_exportedRootScope;
167 QQmlJSImporter *m_importer = nullptr;
168 QQmlJSLogger *m_logger = nullptr;
169
170 using RootDocumentNameType = QQmlJSScope::RootDocumentNameType;
171 using InlineComponentNameType = QQmlJSScope::InlineComponentNameType;
172 using InlineComponentOrDocumentRootName = QQmlJSScope::RootDocumentNameType;
173 QQmlJSScope::InlineComponentOrDocumentRootName m_currentRootName =
174 QQmlJSScope::RootDocumentNameType();
175 bool m_nextIsInlineComponent = false;
176 bool m_rootIsSingleton = false;
177 QQmlJSScope::Ptr m_savedBindingOuterScope;
178 QQmlJSScope::ConstPtr m_globalScope;
179 QQmlJSScopesById m_scopesById;
180 QQmlJSImporter::ImportedTypes m_rootScopeImports;
181 QList<QQmlJSScope::ConstPtr> m_qmlTypes;
182
183 // We need to record the locations as IR locations because those contain less data.
184 // This way we can look up objects by IR location later.
185 QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> m_scopesByIrLocation;
186
187 // Maps all qmlNames to the source location of their import
188 QMultiHash<QString, QQmlJS::SourceLocation> m_importTypeLocationMap;
189 // Maps all static modules to the source location of their import
190 QMultiHash<QString, QQmlJS::SourceLocation> m_importStaticModuleLocationMap;
191 // Contains all import source locations (could be extracted from above but that is expensive)
192 QSet<QQmlJS::SourceLocation> m_importLocations;
193 // A set of all types that have been used during type resolution
194 QSet<QString> m_usedTypes;
195
196 QList<UnfinishedBinding> m_bindings;
197
198 // stores JS functions and Script bindings per scope (only the name). mimics
199 // the content of QmlIR::Object::functionsAndExpressions
200 QHash<QQmlJSScope::ConstPtr, QList<QString>> m_functionsAndExpressions;
201
202 template <bool scopeIsConst = true>
203 struct ScopeAndNameT
204 {
205 using Scope = std::conditional_t<scopeIsConst, QQmlJSScope::ConstPtr, QQmlJSScope::Ptr>;
206
207 ScopeAndNameT() = default;
208 ScopeAndNameT(const Scope &scope, const QString &name) : scope(scope), name(name) { }
209 ScopeAndNameT(const ScopeAndNameT &) = default;
210 ScopeAndNameT(ScopeAndNameT &&) = default;
211 ScopeAndNameT &operator=(const ScopeAndNameT &) = default;
212 ScopeAndNameT &operator=(ScopeAndNameT &&) = default;
213 ~ScopeAndNameT() = default;
214
215 // Create const from non-const
216 ScopeAndNameT(typename std::enable_if<scopeIsConst, ScopeAndNameT<false>>::type &nonConst)
217 : scope(nonConst.scope), name(nonConst.name)
218 {
219 }
220
221 friend bool operator==(const ScopeAndNameT &lhs, const ScopeAndNameT &rhs)
222 {
223 return lhs.scope == rhs.scope && lhs.name == rhs.name;
224 }
225 friend bool operator!=(const ScopeAndNameT &lhs, const ScopeAndNameT &rhs)
226 {
227 return !(lhs == rhs);
228 }
229 friend size_t qHash(const ScopeAndNameT &san, size_t seed = 0)
230 {
231 return qHashMulti(seed, san.scope, san.name);
232 }
233
234 Scope scope;
235 QString name;
236 };
237 using ConstScopeAndName = ScopeAndNameT<true>;
238 using ScopeAndName = ScopeAndNameT<false>;
239
240 using FunctionOrExpressionIdentifier = ConstScopeAndName;
241 using Property = ConstScopeAndName;
242 using Alias = ConstScopeAndName;
243
244 // tells whether last-processed UiScriptBinding is truly a script binding
245 bool m_thisScriptBindingIsJavaScript = false;
246 QStack<FunctionOrExpressionIdentifier> m_functionStack;
247 // stores the number of functions inside each function
248 QHash<FunctionOrExpressionIdentifier, int> m_innerFunctions;
249 QQmlJSMetaMethod::RelativeFunctionIndex
250 addFunctionOrExpression(const QQmlJSScope::ConstPtr &scope, const QString &name);
251 void forgetFunctionExpression(const QString &name);
252 int synthesizeCompilationUnitRuntimeFunctionIndices(const QQmlJSScope::Ptr &scope,
253 int count) const;
254 void populateRuntimeFunctionIndicesForDocument() const;
255
256 void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
257 const QQmlJS::SourceLocation &location);
258 // Finds an existing scope before attempting to create a new one. Returns \c
259 // true if the scope already exists and \c false if the new scope is created
260 bool enterEnvironmentNonUnique(QQmlJSScope::ScopeType type, const QString &name,
261 const QQmlJS::SourceLocation &location);
262 virtual void leaveEnvironment();
263
264 // A set of types that have not been resolved but have been used during the
265 // AST traversal
266 QDuplicateTracker<QQmlJSScope::ConstPtr> m_unresolvedTypes;
267 template<typename ErrorHandler>
268 bool checkTypeResolved(const QQmlJSScope::ConstPtr &type, ErrorHandler handle)
269 {
270 if (type->isFullyResolved() || checkCustomParser(type))
271 return true;
272
273 // Note: ignore duplicates, but only after we are certain that the type
274 // is still unresolved
275 if (!m_unresolvedTypes.hasSeen(type))
276 handle(type);
277
278 return false;
279 }
280
281 bool checkTypeResolved(const QQmlJSScope::ConstPtr &type)
282 {
283 return checkTypeResolved(type, [&](const QQmlJSScope::ConstPtr &type) {
284 warnUnresolvedType(type);
285 });
286 }
287
288 void warnUnresolvedType(const QQmlJSScope::ConstPtr &type) const;
289 void warnMissingPropertyForBinding(
290 const QString &property, const QQmlJS::SourceLocation &location,
291 const std::optional<QQmlJSFixSuggestion> &fixSuggestion = {});
292
293 QList<QQmlJSAnnotation> parseAnnotations(QQmlJS::AST::UiAnnotationList *list);
294 void setAllBindings();
295 void addDefaultProperties();
296 void processDefaultProperties();
297 void processPropertyBindings();
298 void checkRequiredProperties();
299 void processPropertyTypes();
300 void processMethodTypes();
301 void processPropertyBindingObjects();
302 void flushPendingSignalParameters();
303
304 void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
305 void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
306 void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
307 void checkForComponentTypeWithProperties(const QQmlJSScope::ConstPtr &scope);
308 bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
309
310 enum class BindingExpressionParseResult { Invalid, Script, Literal, Translation };
311 enum class BindingForPropertyDefintion { Yes, No };
312 virtual BindingExpressionParseResult parseBindingExpression(
313 const QString &name, const QQmlJS::AST::Statement *statement,
314 const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr);
315 bool isImportPrefix(QString prefix) const;
316
317 // Used to temporarily store annotations for functions and generators wrapped in UiSourceElements
318 QList<QQmlJSAnnotation> m_pendingMethodAnnotations;
319
320 struct PendingPropertyType
321 {
322 QQmlJSScope::Ptr scope;
323 QString name;
324 QQmlJS::SourceLocation location;
325 };
326
327 struct PendingMethodTypeAnnotations
328 {
329 QQmlJSScope::Ptr scope;
330 QString methodName;
331 // This keeps type annotations' locations in order (parameters then return type).
332 // If an annotation is not present, it is represented by an invalid source location.
333 QVarLengthArray<QQmlJS::SourceLocation, 3> locations;
334 };
335
336 struct PendingPropertyObjectBinding
337 {
338 QQmlJSScope::Ptr scope;
339 QQmlJSScope::Ptr childScope;
340 QString name;
341 QQmlJS::SourceLocation location;
342 bool onToken;
343 };
344
345 struct RequiredProperty
346 {
347 QQmlJSScope::Ptr scope;
348 QString name;
349 QQmlJS::SourceLocation location;
350 };
351
352 /*!
353 Utility wrapper that adds visibility scope to the data.
354
355 This wrapper becomes useful for binding processing where we need to know
356 both the property (or signal handler) owner and the scope in which the
357 binding is executed (the "visibility" scope).
358
359 As visibility scope (and data) does not typically have sufficient
360 information about a proper source location of that data, the location
361 also has to be provided to simplify the error reporting.
362 */
363 template<typename T>
364 struct WithVisibilityScope
365 {
366 QQmlJSScope::Ptr visibilityScope;
367 QQmlJS::SourceLocation dataLocation;
368 T data;
369 };
370
371 QHash<QQmlJSScope::Ptr, QList<QQmlJSScope::Ptr>> m_pendingDefaultProperties;
372 QList<PendingPropertyType> m_pendingPropertyTypes;
373 QList<PendingMethodTypeAnnotations> m_pendingMethodTypeAnnotations;
374 QList<PendingPropertyObjectBinding> m_pendingPropertyObjectBindings;
375 QList<RequiredProperty> m_requiredProperties;
376 QList<QQmlJSScope::Ptr> m_objectBindingScopes;
377 QList<QQmlJSScope::Ptr> m_objectDefinitionScopes;
378
379 QHash<QQmlJSScope::Ptr, QList<WithVisibilityScope<QString>>> m_propertyBindings;
380 QList<Alias> m_aliasDefinitions;
381 QHash<Property, QList<Alias>> m_propertyAliases;
382
383 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
384 QQmlJS::SourceLocation m_pendingSignalHandler;
385 QStringList m_seenModuleQualifiers;
386 QHash<QStringView, QQmlJS::SourceLocation> m_seenInlineComponents;
387
388private:
389 void registerTargetIntoImporter(const QQmlJSScope::Ptr &target);
390 void checkSignal(
391 const QQmlJSScope::ConstPtr &signalScope, const QQmlJS::SourceLocation &location,
392 const QString &handlerName, const QStringList &handlerParameters);
393 void importBaseModules();
394 void resolveAliases();
395 void populatePropertyAliases();
396 void resolveGroupProperties();
397 void handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding);
398 virtual void handleLiteralBinding(const QQmlJSMetaPropertyBinding &,
399 const QQmlJS::AST::UiPublicMember *);
400
401 void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
402 void processImportWarnings(
403 const QString &what, const QList<QQmlJS::DiagnosticMessage> &warnings,
404 const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
405 void addImportWithLocation(
406 const QString &name, const QQmlJS::SourceLocation &loc, bool hadWarnings);
407 void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
408 const QQmlJS::SourceLocation &location);
409 void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
410 const QQmlJS::SourceLocation &location);
411
412 QList<QQmlJS::DiagnosticMessage> importFromHost(
413 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
414 QList<QQmlJS::DiagnosticMessage> importFromQrc(
415 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
416
417public:
418 friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope;
419};
420
421QT_END_NAMESPACE
422
423#endif // QQMLJSIMPORTEDMEMBERSVISITOR_P_H
QQmlJSTypeReader(QQmlJSImporter *importer, const QString &file)
bool operator()(const QSharedPointer< QQmlJSScope > &scope)
QList< QQmlJS::DiagnosticMessage > errors() const
friend bool operator==(const Import &a, const Import &b)
QString prefix() const
bool isValid() const
QTypeRevision version() const
QString name() const
bool isDependency() const
Import()=default
bool isFile() const
friend size_t qHash(const Import &key, size_t seed=0) noexcept
Import(QString prefix, QString name, QTypeRevision version, bool isFile, bool isDependency)
\inmodule QtCore
Combined button and popup list for selecting options.
static QStringList aliases(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String JsrootDotQmltypes
static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry, const QQmlJS::Import &importDescription)
static bool isComposite(const QQmlJSScope::ConstPtr &scope)
static QString resolvePreferredPath(const QString &qmldirPath, const QString &prefer, QQmlJSResourceFileMapper *mapper)
static const QString prefixedName(const QString &prefix, const QString &name)
static const QLatin1String SlashQmldir
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes
QQmlJSImporterFlag
@ UseOptionalImports
@ PreferQmlFilesFromSourceFolder
@ TolerateFileSelectors