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