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(const QString &localFile,
75 const 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 bool visit(QQmlJS::AST::PatternElement *) override;
147
148 bool visit(QQmlJS::AST::IfStatement *) override;
149
150 void throwRecursionDepthError() override;
151
152 virtual bool checkCustomParser(const QQmlJSScope::ConstPtr &scope);
153
154 void setScopeName(QQmlJSScope::Ptr &scope, QQmlJSScope::ScopeType type, const QString &name);
155 virtual bool safeInsertJSIdentifier(QQmlJSScope::Ptr &scope, const QString &name,
156 const QQmlJSScope::JavaScriptIdentifier &identifier);
157 void createAttachedAndGroupedScopes(QQmlJS::AST::UiQualifiedId *propertyName);
158 int openAttachedAndGroupedScopes(QQmlJS::AST::UiQualifiedId *propertyName);
159
160 QString m_implicitImportDirectory;
161 QStringList m_qmldirFiles;
162 QQmlJSScope::Ptr m_currentScope;
163 const QQmlJSScope::Ptr m_exportedRootScope;
164 QQmlJSImporter *m_importer = nullptr;
165 QQmlJSLogger *m_logger = nullptr;
166
167 using RootDocumentNameType = QQmlJSScope::RootDocumentNameType;
168 using InlineComponentNameType = QQmlJSScope::InlineComponentNameType;
169 using InlineComponentOrDocumentRootName = QQmlJSScope::RootDocumentNameType;
170 QQmlJSScope::InlineComponentOrDocumentRootName m_currentRootName =
171 QQmlJSScope::RootDocumentNameType();
172 bool m_nextIsInlineComponent = false;
173 bool m_rootIsSingleton = false;
174 QQmlJSScope::Ptr m_savedBindingOuterScope;
175 QQmlJSScope::ConstPtr m_globalScope;
176 QQmlJSScopesById m_scopesById;
177 QQmlJSImporter::ImportedTypes m_rootScopeImports;
178 QList<QQmlJSScope::ConstPtr> m_qmlTypes;
179
180 // We need to record the locations as IR locations because those contain less data.
181 // This way we can look up objects by IR location later.
182 QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> m_scopesByIrLocation;
183
184 virtual QSet<QString> *usedTypes() { return nullptr; };
185
186 QList<UnfinishedBinding> m_bindings;
187
188 // stores JS functions and Script bindings per scope (only the name). mimics
189 // the content of QmlIR::Object::functionsAndExpressions
190 QHash<QQmlJSScope::ConstPtr, QList<QString>> m_functionsAndExpressions;
191
192 template <bool scopeIsConst = true>
193 struct ScopeAndNameT
194 {
195 using Scope = std::conditional_t<scopeIsConst, QQmlJSScope::ConstPtr, QQmlJSScope::Ptr>;
196
197 ScopeAndNameT() = default;
198 ScopeAndNameT(const Scope &scope, const QString &name) : scope(scope), name(name) { }
199 ScopeAndNameT(const ScopeAndNameT &) = default;
200 ScopeAndNameT(ScopeAndNameT &&) = default;
201 ScopeAndNameT &operator=(const ScopeAndNameT &) = default;
202 ScopeAndNameT &operator=(ScopeAndNameT &&) = default;
203 ~ScopeAndNameT() = default;
204
205 // Create const from non-const
206 ScopeAndNameT(typename std::enable_if<scopeIsConst, ScopeAndNameT<false>>::type &nonConst)
207 : scope(nonConst.scope), name(nonConst.name)
208 {
209 }
210
211 friend bool operator==(const ScopeAndNameT &lhs, const ScopeAndNameT &rhs)
212 {
213 return lhs.scope == rhs.scope && lhs.name == rhs.name;
214 }
215 friend bool operator!=(const ScopeAndNameT &lhs, const ScopeAndNameT &rhs)
216 {
217 return !(lhs == rhs);
218 }
219 friend size_t qHash(const ScopeAndNameT &san, size_t seed = 0)
220 {
221 return qHashMulti(seed, san.scope, san.name);
222 }
223
224 Scope scope;
225 QString name;
226 };
227 using ConstScopeAndName = ScopeAndNameT<true>;
228 using ScopeAndName = ScopeAndNameT<false>;
229
230 using FunctionOrExpressionIdentifier = ConstScopeAndName;
231 using Property = ConstScopeAndName;
232 using Alias = ConstScopeAndName;
233
234 // tells whether last-processed UiScriptBinding is truly a script binding
235 bool m_thisScriptBindingIsJavaScript = false;
236 QStack<FunctionOrExpressionIdentifier> m_functionStack;
237 // stores the number of functions inside each function
238 QHash<FunctionOrExpressionIdentifier, int> m_innerFunctions;
239 QQmlJSMetaMethod::RelativeFunctionIndex
240 addFunctionOrExpression(const QQmlJSScope::ConstPtr &scope, const QString &name);
241 void forgetFunctionExpression(const QString &name);
242 int synthesizeCompilationUnitRuntimeFunctionIndices(const QQmlJSScope::Ptr &scope,
243 int count) const;
244 void populateRuntimeFunctionIndicesForDocument() const;
245
246 void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
247 const QQmlJS::SourceLocation &location);
248 // Finds an existing scope before attempting to create a new one. Returns \c
249 // true if the scope already exists and \c false if the new scope is created
250 bool enterEnvironmentNonUnique(QQmlJSScope::ScopeType type, const QString &name,
251 const QQmlJS::SourceLocation &location);
252 virtual void leaveEnvironment();
253
254 // A set of types that have not been resolved but have been used during the
255 // AST traversal
256 QDuplicateTracker<QQmlJSScope::ConstPtr> m_unresolvedTypes;
257 template<typename ErrorHandler>
258 bool checkTypeResolved(const QQmlJSScope::ConstPtr &type, ErrorHandler handle)
259 {
260 if (type->isFullyResolved() || checkCustomParser(type))
261 return true;
262
263 // Note: ignore duplicates, but only after we are certain that the type
264 // is still unresolved
265 if (!m_unresolvedTypes.hasSeen(type))
266 handle(type);
267
268 return false;
269 }
270
271 bool checkTypeResolved(const QQmlJSScope::ConstPtr &type)
272 {
273 return checkTypeResolved(type, [&](const QQmlJSScope::ConstPtr &type) {
274 warnUnresolvedType(type);
275 });
276 }
277
278 void warnUnresolvedType(const QQmlJSScope::ConstPtr &type) const;
279 void warnMissingPropertyForBinding(
280 const QString &property, const QQmlJS::SourceLocation &location,
281 const std::optional<QQmlJSFixSuggestion> &fixSuggestion = {});
282
283 QList<QQmlJSAnnotation> parseAnnotations(QQmlJS::AST::UiAnnotationList *list);
284 void setAllBindings();
285 void addDefaultProperties();
286 void processDefaultProperties();
287 void processPropertyBindings();
288 void checkRequiredProperties();
289 void processPropertyTypes();
290 void processMethodTypes();
291 void processPropertyBindingObjects();
292 void flushPendingSignalParameters();
293
294 void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
295 void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
296 void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
297 void checkForComponentTypeWithProperties(const QQmlJSScope::ConstPtr &scope);
298 bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
299
300 enum class BindingExpressionParseResult { Invalid, Script, Literal, Translation };
301 enum class BindingForPropertyDefintion { Yes, No };
302 virtual BindingExpressionParseResult parseBindingExpression(
303 const QString &name, const QQmlJS::AST::Statement *statement,
304 const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr);
305 bool isImportPrefix(QString prefix) const;
306
307 // Used to temporarily store annotations for functions and generators wrapped in UiSourceElements
308 QList<QQmlJSAnnotation> m_pendingMethodAnnotations;
309
310 struct PendingPropertyType
311 {
312 QQmlJSScope::Ptr scope;
313 QString name;
314 QQmlJS::SourceLocation location;
315 };
316
317 struct PendingMethodTypeAnnotations
318 {
319 QQmlJSScope::Ptr scope;
320 QString methodName;
321 // This keeps type annotations' locations in order (parameters then return type).
322 // If an annotation is not present, it is represented by an invalid source location.
323 QVarLengthArray<QQmlJS::SourceLocation, 3> locations;
324 };
325
326 struct PendingPropertyObjectBinding
327 {
328 QQmlJSScope::Ptr scope;
329 QQmlJSScope::Ptr childScope;
330 QString name;
331 QQmlJS::SourceLocation location;
332 bool onToken;
333 };
334
335 struct RequiredProperty
336 {
337 QQmlJSScope::Ptr scope;
338 QString name;
339 QQmlJS::SourceLocation location;
340 };
341
342 /*!
343 Utility wrapper that adds visibility scope to the data.
344
345 This wrapper becomes useful for binding processing where we need to know
346 both the property (or signal handler) owner and the scope in which the
347 binding is executed (the "visibility" scope).
348
349 As visibility scope (and data) does not typically have sufficient
350 information about a proper source location of that data, the location
351 also has to be provided to simplify the error reporting.
352 */
353 template<typename T>
354 struct WithVisibilityScope
355 {
356 QQmlJSScope::Ptr visibilityScope;
357 QQmlJS::SourceLocation dataLocation;
358 T data;
359 };
360
361 QHash<QQmlJSScope::Ptr, QList<QQmlJSScope::Ptr>> m_pendingDefaultProperties;
362 QList<PendingPropertyType> m_pendingPropertyTypes;
363 QList<PendingMethodTypeAnnotations> m_pendingMethodTypeAnnotations;
364 QList<PendingPropertyObjectBinding> m_pendingPropertyObjectBindings;
365 QList<RequiredProperty> m_requiredProperties;
366 QList<QQmlJSScope::Ptr> m_objectBindingScopes;
367 QList<QQmlJSScope::Ptr> m_objectDefinitionScopes;
368
369 QHash<QQmlJSScope::Ptr, QList<WithVisibilityScope<QString>>> m_propertyBindings;
370 QList<Alias> m_aliasDefinitions;
371 QHash<Property, QList<Alias>> m_propertyAliases;
372
373 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
374 QQmlJS::SourceLocation m_pendingSignalHandler;
375 QStringList m_seenModuleQualifiers;
376 QHash<QStringView, QQmlJS::SourceLocation> m_seenInlineComponents;
377
378private:
379 void registerTargetIntoImporter(const QQmlJSScope::Ptr &target);
380 void checkSignal(
381 const QQmlJSScope::ConstPtr &signalScope, const QQmlJS::SourceLocation &location,
382 const QString &handlerName, const QStringList &handlerParameters);
383 void importBaseModules();
384 void resolveAliases();
385 bool resolveAliasProperty(const QQmlJSScope::Ptr &object, const QQmlJSMetaProperty &property);
386 void populatePropertyAliases();
387 void resolveGroupProperties();
388 void handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding);
389 virtual void handleLiteralBinding(const QQmlJSMetaPropertyBinding &,
390 const QQmlJS::AST::UiPublicMember *);
391
392 void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
393 void processImportWarnings(
394 const QString &what, const QList<QQmlJS::DiagnosticMessage> &warnings,
395 const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
396protected:
397 virtual void addImportWithLocation(const QString &, const QQmlJS::SourceLocation &, bool) { }
398 virtual void addStaticImportWithLocation(const QString &, const QQmlJS::SourceLocation &, bool)
399 {
400 }
401
402private:
403 void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
404 const QQmlJS::SourceLocation &location);
405 void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
406 const QQmlJS::SourceLocation &location);
407
408 QList<QQmlJS::DiagnosticMessage> importFromHost(
409 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
410 QList<QQmlJS::DiagnosticMessage> importFromQrc(
411 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
412
413public:
414 friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope;
415};
416
417QT_END_NAMESPACE
418
419#endif // QQMLJSIMPORTEDMEMBERSVISITOR_P_H
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 const QString prefixedName(const QString &prefix, const QString &name)
static QString ensureSlashQmldir(const QString &path)
static QString resolvePreferredPath(const QString &qmldirPath, const QString &prefer, const QQmlJSResourceFileMapper *mapper)
static const QLatin1String SlashQmldir
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes
QQmlJSImporterFlag
@ UseOptionalImports
@ PreferQmlFilesFromSourceFolder
@ TolerateFileSelectors