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 // Warn on unresolved parent of grouped properties instead of the grouped property itself,
264 // as we can't resolve grouped properties on unresolved types.
265 if (type->scopeType() == QQmlSA::ScopeType::GroupedPropertyScope && type->parentScope()
266 && !checkTypeResolved(type->parentScope(), handle)) {
267 return false;
268 }
269
270 // Note: ignore duplicates, but only after we are certain that the type
271 // is still unresolved
272 if (!m_unresolvedTypes.hasSeen(type))
273 handle(type);
274
275 return false;
276 }
277
278 bool checkTypeResolved(const QQmlJSScope::ConstPtr &type)
279 {
280 return checkTypeResolved(type, [&](const QQmlJSScope::ConstPtr &type) {
281 warnUnresolvedType(type);
282 });
283 }
284
285 void warnUnresolvedType(const QQmlJSScope::ConstPtr &type) const;
286 void warnMissingPropertyForBinding(
287 const QString &property, const QQmlJS::SourceLocation &location,
288 const std::optional<QQmlJSFixSuggestion> &fixSuggestion = {});
289
290 QList<QQmlJSAnnotation> parseAnnotations(QQmlJS::AST::UiAnnotationList *list);
291 void setAllBindings();
292 void addDefaultProperties();
293 void processDefaultProperties();
294 void processPropertyBindings();
295 void checkRequiredProperties();
296 void processPropertyTypes();
297 void processMethodTypes();
298 void processPropertyBindingObjects();
299 void flushPendingSignalParameters();
300
301 void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
302 void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
303 virtual void checkGroupedAndAttachedScopes() { }
304 void checkForComponentTypeWithProperties(const QQmlJSScope::ConstPtr &scope);
305 bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
306
307 enum class BindingExpressionParseResult { Invalid, Script, Literal, Translation };
308 enum class BindingForPropertyDefintion { Yes, No };
309 virtual BindingExpressionParseResult parseBindingExpression(
310 const QString &name, const QQmlJS::AST::Statement *statement,
311 const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr);
312 bool isImportPrefix(QString prefix) const;
313
314 // Used to temporarily store annotations for functions and generators wrapped in UiSourceElements
315 QList<QQmlJSAnnotation> m_pendingMethodAnnotations;
316
317 struct PendingPropertyType
318 {
319 QQmlJSScope::Ptr scope;
320 QString name;
321 QQmlJS::SourceLocation location;
322 };
323
324 struct PendingMethodTypeAnnotations
325 {
326 QQmlJSScope::Ptr scope;
327 QString methodName;
328 // This keeps type annotations' locations in order (parameters then return type).
329 // If an annotation is not present, it is represented by an invalid source location.
330 QVarLengthArray<QQmlJS::SourceLocation, 3> locations;
331 };
332
333 struct PendingPropertyObjectBinding
334 {
335 QQmlJSScope::Ptr scope;
336 QQmlJSScope::Ptr childScope;
337 QString name;
338 QQmlJS::SourceLocation location;
339 bool onToken;
340 };
341
342 struct RequiredProperty
343 {
344 QQmlJSScope::Ptr scope;
345 QString name;
346 QQmlJS::SourceLocation location;
347 };
348
349 /*!
350 Utility wrapper that adds visibility scope to the data.
351
352 This wrapper becomes useful for binding processing where we need to know
353 both the property (or signal handler) owner and the scope in which the
354 binding is executed (the "visibility" scope).
355
356 As visibility scope (and data) does not typically have sufficient
357 information about a proper source location of that data, the location
358 also has to be provided to simplify the error reporting.
359 */
360 template<typename T>
361 struct WithVisibilityScope
362 {
363 QQmlJSScope::Ptr visibilityScope;
364 QQmlJS::SourceLocation dataLocation;
365 T data;
366 };
367
368 QHash<QQmlJSScope::Ptr, QList<QQmlJSScope::Ptr>> m_pendingDefaultProperties;
369 QList<PendingPropertyType> m_pendingPropertyTypes;
370 QList<PendingMethodTypeAnnotations> m_pendingMethodTypeAnnotations;
371 QList<PendingPropertyObjectBinding> m_pendingPropertyObjectBindings;
372 QList<RequiredProperty> m_requiredProperties;
373 QList<QQmlJSScope::Ptr> m_objectBindingScopes;
374 QList<QQmlJSScope::Ptr> m_objectDefinitionScopes;
375
376 QHash<QQmlJSScope::Ptr, QList<WithVisibilityScope<QString>>> m_propertyBindings;
377 QList<Alias> m_aliasDefinitions;
378 QHash<Property, QList<Alias>> m_propertyAliases;
379
380 QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
381 QQmlJS::SourceLocation m_pendingSignalHandler;
382 QStringList m_seenModuleQualifiers;
383 QHash<QStringView, QQmlJS::SourceLocation> m_seenInlineComponents;
384
385private:
386 void registerTargetIntoImporter(const QQmlJSScope::Ptr &target);
387 void checkSignal(
388 const QQmlJSScope::ConstPtr &signalScope, const QQmlJS::SourceLocation &location,
389 const QString &handlerName, const QStringList &handlerParameters);
390 void importBaseModules();
391 void resolveAliases();
392 bool resolveAliasProperty(const QQmlJSScope::Ptr &object, const QQmlJSMetaProperty &property);
393 void populatePropertyAliases();
394 void resolveGroupProperties();
395 void handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding);
396 virtual void handleLiteralBinding(const QQmlJSMetaPropertyBinding &,
397 const QQmlJS::AST::UiPublicMember *);
398
399 void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
400 void processImportWarnings(
401 const QString &what, const QList<QQmlJS::DiagnosticMessage> &warnings,
402 const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
403protected:
404 virtual void addImportWithLocation(const QString &, const QQmlJS::SourceLocation &, bool) { }
405 virtual void addStaticImportWithLocation(const QString &, const QQmlJS::SourceLocation &, bool)
406 {
407 }
408
409private:
410 void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
411 const QQmlJS::SourceLocation &location);
412 void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
413 const QQmlJS::SourceLocation &location);
414
415 QList<QQmlJS::DiagnosticMessage> importFromHost(
416 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
417 QList<QQmlJS::DiagnosticMessage> importFromQrc(
418 const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location);
419
420public:
421 friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope;
422};
423
424QT_END_NAMESPACE
425
426#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