Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmljsimportvisitor.cpp
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
5#include "qqmljsmetatypes_p.h"
7
8#include <QtCore/qfileinfo.h>
9#include <QtCore/qdir.h>
10#include <QtCore/qqueue.h>
11#include <QtCore/qscopedvaluerollback.h>
12#include <QtCore/qpoint.h>
13#include <QtCore/qrect.h>
14#include <QtCore/qsize.h>
15
16#include <QtQml/private/qv4codegen_p.h>
17#include <QtQml/private/qqmlstringconverters_p.h>
18#include <QtQml/private/qqmlirbuilder_p.h>
19#include "qqmljsscope_p.h"
20#include "qqmljsutils_p.h"
21#include "qqmljsloggingutils.h"
22#include "qqmlsaconstants.h"
23
24#include <algorithm>
25#include <limits>
26#include <optional>
27#include <variant>
28
30
31using namespace Qt::StringLiterals;
32
33using namespace QQmlJS::AST;
34
40{
41 Q_ASSERT(scope);
44 scope->setInternalName(name);
45 else
46 scope->setBaseTypeName(name);
47}
48
54{
55 Q_ASSERT(scope);
58 return scope->internalName();
59
60 return scope->baseTypeName();
61}
62
63template<typename Node>
65{
67 for (const Node *segment = node; segment; segment = segment->next) {
68 if (!result.isEmpty())
69 result += u'.';
70 result += segment->name;
71 }
72 return result;
73}
74
76 const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
77 const QString &implicitImportDirectory, const QStringList &qmldirFiles)
78 : m_implicitImportDirectory(implicitImportDirectory),
79 m_qmldirFiles(qmldirFiles),
80 m_currentScope(QQmlJSScope::create()),
81 m_exportedRootScope(target),
82 m_importer(importer),
83 m_logger(logger),
84 m_rootScopeImports(
85 QQmlJSImporter::ImportedTypes::QML, {},
86 importer->builtinInternalNames().arrayType())
87{
88 m_currentScope->setScopeType(QQmlSA::ScopeType::JSFunctionScope);
89 Q_ASSERT(logger); // must be valid
90
91 m_globalScope = m_currentScope;
92 m_currentScope->setIsComposite(true);
93
94 m_currentScope->setInternalName(u"global"_s);
95
96 QLatin1String jsGlobVars[] = { /* Not listed on the MDN page; browser and QML extensions: */
97 // console/debug api
98 QLatin1String("console"), QLatin1String("print"),
99 // garbage collector
100 QLatin1String("gc"),
101 // i18n
102 QLatin1String("qsTr"), QLatin1String("qsTrId"),
103 QLatin1String("QT_TR_NOOP"), QLatin1String("QT_TRANSLATE_NOOP"),
104 QLatin1String("QT_TRID_NOOP"),
105 // XMLHttpRequest
106 QLatin1String("XMLHttpRequest")
107 };
108
109 QQmlJSScope::JavaScriptIdentifier globalJavaScript = {
111 true
112 };
113 for (const char **globalName = QV4::Compiler::Codegen::s_globalNames; *globalName != nullptr;
114 ++globalName) {
115 m_currentScope->insertJSIdentifier(QString::fromLatin1(*globalName), globalJavaScript);
116 }
117 for (const auto &jsGlobVar : jsGlobVars)
118 m_currentScope->insertJSIdentifier(jsGlobVar, globalJavaScript);
119}
120
122
123void QQmlJSImportVisitor::populateCurrentScope(
125{
131 m_scopesByIrLocation.insert({ location.startLine, location.startColumn }, m_currentScope);
132}
133
134void QQmlJSImportVisitor::enterRootScope(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
135{
138 populateCurrentScope(type, name, location);
139}
140
143{
146 m_currentScope = std::move(newScope);
147 populateCurrentScope(type, name, location);
148}
149
151 const QString &name,
153{
156
157 const auto pred = [&](const QQmlJSScope::ConstPtr &s) {
158 // it's either attached or group property, so use internalName()
159 // directly. see setScopeName() for details
160 return s->internalName() == name;
161 };
162 const auto scopes = m_currentScope->childScopes();
163 // TODO: linear search. might want to make childScopes() a set/hash-set and
164 // use faster algorithm here
165 auto it = std::find_if(scopes.begin(), scopes.end(), pred);
166 if (it == scopes.end()) {
167 // create and enter new scope
169 return false;
170 }
171 // enter found scope
172 m_scopesByIrLocation.insert({ location.startLine, location.startColumn }, *it);
174 return true;
175}
176
178{
180}
181
183{
184 const auto handleUnresolvedType = [this](const QQmlJSScope::ConstPtr &type) {
185 m_logger->log(QStringLiteral("Type %1 is used but it is not resolved")
186 .arg(getScopeName(type, type->scopeType())),
187 qmlUnresolvedType, type->sourceLocation());
188 };
189 return isTypeResolved(type, handleUnresolvedType);
190}
191
193{
194 return scope->scopeType() == QQmlSA::ScopeType::GroupedPropertyScope && !scope->baseType();
195}
196
197void QQmlJSImportVisitor::resolveAliasesAndIds()
198{
201
202 qsizetype lastRequeueLength = std::numeric_limits<qsizetype>::max();
204
205 while (!objects.isEmpty()) {
206 const QQmlJSScope::Ptr object = objects.dequeue();
207 const auto properties = object->ownProperties();
208
209 bool doRequeue = false;
210 for (const auto &property : properties) {
211 if (!property.isAlias() || !property.type().isNull())
212 continue;
213
214 QStringList components = property.aliasExpression().split(u'.');
215 QQmlJSMetaProperty targetProperty;
216
217 bool foundProperty = false;
218
219 // The first component has to be an ID. Find the object it refers to.
221 QQmlJSScope::ConstPtr typeScope;
222 if (!type.isNull()) {
223 foundProperty = true;
224
225 // Any further components are nested properties of that object.
226 // Technically we can only resolve a limited depth in the engine, but the rules
227 // on that are fuzzy and subject to change. Let's ignore it for now.
228 // If the target is itself an alias and has not been resolved, re-queue the object
229 // and try again later.
230 while (type && !components.isEmpty()) {
231 const QString name = components.takeFirst();
232
233 if (!type->hasProperty(name)) {
234 foundProperty = false;
235 type = {};
236 break;
237 }
238
239 const auto target = type->property(name);
240 if (!target.type() && target.isAlias())
241 doRequeue = true;
242 typeScope = type;
243 type = target.type();
244 targetProperty = target;
245 }
246 }
247
248 if (type.isNull()) {
249 if (doRequeue)
250 continue;
251 if (foundProperty) {
252 m_logger->log(QStringLiteral("Cannot deduce type of alias \"%1\"")
253 .arg(property.propertyName()),
254 qmlMissingType, object->sourceLocation());
255 } else {
256 m_logger->log(QStringLiteral("Cannot resolve alias \"%1\"")
257 .arg(property.propertyName()),
258 qmlUnresolvedAlias, object->sourceLocation());
259 }
260
261 Q_ASSERT(property.index() >= 0); // this property is already in object
262 object->addOwnProperty(property);
263
264 } else {
265 QQmlJSMetaProperty newProperty = property;
266 newProperty.setType(type);
267 // Copy additional property information from target
268 newProperty.setIsList(targetProperty.isList());
269 newProperty.setIsWritable(targetProperty.isWritable());
270 newProperty.setIsPointer(targetProperty.isPointer());
271
272 if (!typeScope.isNull()) {
273 object->setPropertyLocallyRequired(
274 newProperty.propertyName(),
275 typeScope->isPropertyRequired(targetProperty.propertyName()));
276 }
277
278 if (const QString internalName = type->internalName(); !internalName.isEmpty())
279 newProperty.setTypeName(internalName);
280
281 Q_ASSERT(newProperty.index() >= 0); // this property is already in object
282 object->addOwnProperty(newProperty);
283 }
284 }
285
286 const auto childScopes = object->childScopes();
287 for (const auto &childScope : childScopes) {
289 const QString name = childScope->internalName();
290 if (object->isNameDeferred(name)) {
291 const QQmlJSScope::ConstPtr deferred = m_scopesById.scope(name, childScope);
292 if (!deferred.isNull()) {
294 childScope, deferred, m_rootScopeImports, &m_usedTypes);
295 }
296 }
297 }
298 objects.enqueue(childScope);
299 }
300
301 if (doRequeue)
302 requeue.enqueue(object);
303
304 if (objects.isEmpty() && requeue.size() < lastRequeueLength) {
305 lastRequeueLength = requeue.size();
306 objects.swap(requeue);
307 }
308 }
309
310 while (!requeue.isEmpty()) {
311 const QQmlJSScope::Ptr object = requeue.dequeue();
312 const auto properties = object->ownProperties();
313 for (const auto &property : properties) {
314 if (!property.isAlias() || property.type())
315 continue;
316 m_logger->log(QStringLiteral("Alias \"%1\" is part of an alias cycle")
317 .arg(property.propertyName()),
318 qmlAliasCycle, object->sourceLocation());
319 }
320 }
321}
322
324 const QString &localFile, QQmlJSResourceFileMapper *mapper)
325{
326 if (mapper) {
327 const auto resource = mapper->entry(
329 if (resource.isValid()) {
330 return resource.resourcePath.contains(u'/')
331 ? (u':' + resource.resourcePath.left(
332 resource.resourcePath.lastIndexOf(u'/') + 1))
333 : QStringLiteral(":/");
334 }
335 }
336
337 return QFileInfo(localFile).canonicalPath() + u'/';
338}
339
340void QQmlJSImportVisitor::processImportWarnings(
341 const QString &what, const QQmlJS::SourceLocation &srcLocation)
342{
343 const auto warnings = m_importer->takeWarnings();
344 if (warnings.isEmpty())
345 return;
346
347 m_logger->log(QStringLiteral("Warnings occurred while importing %1:").arg(what), qmlImport,
348 srcLocation);
350}
351
352void QQmlJSImportVisitor::importBaseModules()
353{
354 Q_ASSERT(m_rootScopeImports.types().isEmpty());
356
357 const QQmlJS::SourceLocation invalidLoc;
358 for (auto it = m_rootScopeImports.types().keyBegin(), end = m_rootScopeImports.types().keyEnd();
359 it != end; it++) {
360 addImportWithLocation(*it, invalidLoc);
361 }
362
363 if (!m_qmldirFiles.isEmpty())
365
366 // Pulling in the modules and neighboring qml files of the qmltypes we're trying to lint is not
367 // something we need to do.
368 if (!m_logger->fileName().endsWith(u".qmltypes"_s)) {
369 QQmlJSScope::ContextualTypes fromDirectory =
371 m_rootScopeImports.addTypes(std::move(fromDirectory));
372
373 // Import all possible resource directories the file may belong to.
374 // This is somewhat fuzzy, but if you're mapping the same file to multiple resource
375 // locations, you're on your own anyway.
377 const QStringList resourcePaths = mapper->resourcePaths(QQmlJSResourceFileMapper::Filter {
379 for (const QString &path : resourcePaths) {
380 const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
381 if (lastSlash == -1)
382 continue;
384 }
385 }
386 }
387
388 processImportWarnings(QStringLiteral("base modules"));
389}
390
392{
393 importBaseModules();
394 return true;
395}
396
398{
399 for (const auto &scope : m_objectBindingScopes) {
401 checkDeprecation(scope);
402 }
403
404 for (const auto &scope : m_objectDefinitionScopes) {
405 if (m_pendingDefaultProperties.contains(scope))
406 continue; // We're going to check this one below.
408 checkDeprecation(scope);
409 }
410
411 for (const auto &scope : m_pendingDefaultProperties.keys()) {
413 checkDeprecation(scope);
414 }
415
416 resolveAliasesAndIds();
417
418 for (const auto &scope : m_objectDefinitionScopes)
420
427
428 auto unusedImports = m_importLocations;
429 for (const QString &type : m_usedTypes) {
430 for (const auto &importLocation : m_importTypeLocationMap.values(type))
431 unusedImports.remove(importLocation);
432
433 // If there are no more unused imports left we can abort early
434 if (unusedImports.isEmpty())
435 break;
436 }
437
439 unusedImports.remove(import);
440
441 for (const auto &import : unusedImports) {
442 m_logger->log(QString::fromLatin1("Unused import"), qmlUnusedImports, import);
443 }
444
446}
447
449{
450 ExpressionStatement *expr = cast<ExpressionStatement *>(statement);
451
452 if (!statement || !expr->expression)
453 return {};
454
455 switch (expr->expression->kind) {
456 case Node::Kind_StringLiteral:
457 return cast<StringLiteral *>(expr->expression)->value.toString();
458 case Node::Kind_NumericLiteral:
459 return cast<NumericLiteral *>(expr->expression)->value;
460 default:
461 return {};
462 }
463}
464
466{
467
468 QVector<QQmlJSAnnotation> annotationList;
469
470 for (UiAnnotationList *item = list; item != nullptr; item = item->next) {
471 UiAnnotation *annotation = item->annotation;
472
473 QQmlJSAnnotation qqmljsAnnotation;
474 qqmljsAnnotation.name = buildName(annotation->qualifiedTypeNameId);
475
476 for (UiObjectMemberList *memberItem = annotation->initializer->members; memberItem != nullptr; memberItem = memberItem->next) {
477 switch (memberItem->member->kind) {
478 case Node::Kind_UiScriptBinding: {
479 auto *scriptBinding = QQmlJS::AST::cast<UiScriptBinding*>(memberItem->member);
480 qqmljsAnnotation.bindings[buildName(scriptBinding->qualifiedId)]
481 = bindingToVariant(scriptBinding->statement);
482 break;
483 }
484 default:
485 // We ignore all the other information contained in the annotation
486 break;
487 }
488 }
489
490 annotationList.append(qqmljsAnnotation);
491 }
492
493 return annotationList;
494}
495
497{
498 for (auto it = m_bindings.cbegin(); it != m_bindings.cend(); ++it) {
499 // ensure the scope is resolved, if not - it is an error
500 auto type = it->owner;
501 if (!type->isFullyResolved()) {
502 if (!type->isInCustomParserParent()) { // special otherwise
503 m_logger->log(QStringLiteral("'%1' is used but it is not resolved")
504 .arg(getScopeName(type, type->scopeType())),
505 qmlUnresolvedType, type->sourceLocation());
506 }
507 continue;
508 }
509 auto binding = it->create();
510 if (binding.isValid())
511 type->addOwnPropertyBinding(binding, it->specifier);
512 }
513}
514
516{
517 for (auto it = m_pendingDefaultProperties.constBegin();
518 it != m_pendingDefaultProperties.constEnd(); ++it) {
519 QQmlJSScope::ConstPtr parentScope = it.key();
520
521 // We can't expect custom parser default properties to be sensible, discard them for now.
522 if (parentScope->isInCustomParserParent())
523 continue;
524
525 /* consider:
526 *
527 * QtObject { // <- parentScope
528 * default property var p // (1)
529 * QtObject {} // (2)
530 * }
531 *
532 * `p` (1) is a property of a subtype of QtObject, it couldn't be used
533 * in a property binding (2)
534 */
535 // thus, use a base type of parent scope to detect a default property
536 parentScope = parentScope->baseType();
537
538 const QString defaultPropertyName =
539 parentScope ? parentScope->defaultPropertyName() : QString();
540
541 if (defaultPropertyName.isEmpty()) {
542 // If the parent scope is based on Component it can have any child element
543 // TODO: We should also store these somewhere
544 bool isComponent = false;
545 for (QQmlJSScope::ConstPtr s = parentScope; s; s = s->baseType()) {
546 if (s->internalName() == QStringLiteral("QQmlComponent")) {
547 isComponent = true;
548 break;
549 }
550 }
551
552 if (!isComponent) {
553 m_logger->log(QStringLiteral("Cannot assign to non-existent default property"),
554 qmlMissingProperty, it.value().constFirst()->sourceLocation());
555 }
556
557 continue;
558 }
559
560 const QQmlJSMetaProperty defaultProp = parentScope->property(defaultPropertyName);
561 auto propType = defaultProp.type();
562 const auto handleUnresolvedDefaultProperty = [&](const QQmlJSScope::ConstPtr &) {
563 // Property type is not fully resolved we cannot tell any more than this
564 m_logger->log(QStringLiteral("Property \"%1\" has incomplete type \"%2\". You may be "
565 "missing an import.")
566 .arg(defaultPropertyName)
567 .arg(defaultProp.typeName()),
568 qmlMissingProperty, it.value().constFirst()->sourceLocation());
569 };
570
571 if (propType.isNull()) {
572 handleUnresolvedDefaultProperty(propType);
573 continue;
574 }
575
576 if (it.value().size() > 1
577 && !defaultProp.isList()
578 && !propType->isListProperty()) {
579 m_logger->log(
580 QStringLiteral("Cannot assign multiple objects to a default non-list property"),
581 qmlNonListProperty, it.value().constFirst()->sourceLocation());
582 }
583
584 if (!isTypeResolved(propType, handleUnresolvedDefaultProperty))
585 continue;
586
587 const auto scopes = *it;
588 for (const auto &scope : scopes) {
589 if (!isTypeResolved(scope))
590 continue;
591
592 // Assigning any element to a QQmlComponent property implicitly wraps it into a Component
593 // Check whether the property can be assigned the scope
594 if (propType->canAssign(scope)) {
595 scope->setIsWrappedInImplicitComponent(
597 continue;
598 }
599
600 m_logger->log(QStringLiteral("Cannot assign to default property of incompatible type"),
601 qmlIncompatibleType, scope->sourceLocation());
602 }
603 }
604}
605
607{
609 Q_ASSERT(type.scope->hasOwnProperty(type.name));
610
611 auto property = type.scope->ownProperty(type.name);
612
613 if (const auto propertyType =
615 property.setType(propertyType);
616 type.scope->addOwnProperty(property);
617 } else {
618 m_logger->log(property.typeName()
619 + QStringLiteral(" was not found. Did you add all import paths?"),
620 qmlImport, type.location);
621 }
622 }
623}
624
626{
628 {
629 // Note: populating literals here is special, because we do not store
630 // them in m_pendingPropertyObjectBindings, so we have to lookup all
631 // bindings on a property for each scope and see if there are any
632 // literal bindings there. this is safe to do once at the beginning
633 // because this function doesn't add new literal bindings and all
634 // literal bindings must already be added at this point.
636 for (const PendingPropertyObjectBinding &objectBinding :
637 std::as_const(m_pendingPropertyObjectBindings)) {
638 // unique because it's per-scope and per-property
639 const auto uniqueBindingId = qMakePair(objectBinding.scope, objectBinding.name);
640 if (visited.contains(uniqueBindingId))
641 continue;
642 visited.insert(uniqueBindingId);
643
644 auto [existingBindingsBegin, existingBindingsEnd] =
645 uniqueBindingId.first->ownPropertyBindings(uniqueBindingId.second);
646 const bool hasLiteralBindings =
647 std::any_of(existingBindingsBegin, existingBindingsEnd,
648 [](const QQmlJSMetaPropertyBinding &x) { return x.hasLiteral(); });
649 if (hasLiteralBindings)
650 foundLiterals.insert(uniqueBindingId);
651 }
652 }
653
655 QSet<QPair<QQmlJSScope::Ptr, QString>> foundInterceptors;
656 QSet<QPair<QQmlJSScope::Ptr, QString>> foundValueSources;
657
658 for (const PendingPropertyObjectBinding &objectBinding :
659 std::as_const(m_pendingPropertyObjectBindings)) {
660 const QString propertyName = objectBinding.name;
661 QQmlJSScope::ConstPtr childScope = objectBinding.childScope;
662
663 if (!isTypeResolved(objectBinding.scope)) // guarantees property lookup
664 continue;
665
666 QQmlJSMetaProperty property = objectBinding.scope->property(propertyName);
667
668 if (!property.isValid()) {
669 m_logger->log(QStringLiteral("Property \"%1\" does not exist").arg(propertyName),
670 qmlMissingProperty, objectBinding.location);
671 continue;
672 }
673 const auto handleUnresolvedProperty = [&](const QQmlJSScope::ConstPtr &) {
674 // Property type is not fully resolved we cannot tell any more than this
675 m_logger->log(QStringLiteral("Property \"%1\" has incomplete type \"%2\". You may be "
676 "missing an import.")
677 .arg(propertyName)
678 .arg(property.typeName()),
679 qmlUnresolvedType, objectBinding.location);
680 };
681 if (property.type().isNull()) {
682 handleUnresolvedProperty(property.type());
683 continue;
684 }
685
686 // guarantee that canAssign() can be called
687 if (!isTypeResolved(property.type(), handleUnresolvedProperty)
688 || !isTypeResolved(childScope)) {
689 continue;
690 }
691
692 if (!objectBinding.onToken && !property.type()->canAssign(childScope)) {
693 // the type is incompatible
694 m_logger->log(QStringLiteral("Property \"%1\" of type \"%2\" is assigned an "
695 "incompatible type \"%3\"")
696 .arg(propertyName)
697 .arg(property.typeName())
698 .arg(getScopeName(childScope, QQmlSA::ScopeType::QMLScope)),
699 qmlIncompatibleType, objectBinding.location);
700 continue;
701 }
702
703 objectBinding.childScope->setIsWrappedInImplicitComponent(
705
706 // unique because it's per-scope and per-property
707 const auto uniqueBindingId = qMakePair(objectBinding.scope, objectBinding.name);
709
710 if (objectBinding.onToken) {
711 if (childScope->hasInterface(QStringLiteral("QQmlPropertyValueInterceptor"))) {
712 if (foundInterceptors.contains(uniqueBindingId)) {
713 m_logger->log(QStringLiteral("Duplicate interceptor on property \"%1\"")
714 .arg(propertyName),
715 qmlDuplicatePropertyBinding, objectBinding.location);
716 } else {
717 foundInterceptors.insert(uniqueBindingId);
718 }
719 } else if (childScope->hasInterface(QStringLiteral("QQmlPropertyValueSource"))) {
720 if (foundValueSources.contains(uniqueBindingId)) {
721 m_logger->log(QStringLiteral("Duplicate value source on property \"%1\"")
722 .arg(propertyName),
723 qmlDuplicatePropertyBinding, objectBinding.location);
724 } else if (foundObjects.contains(uniqueBindingId)
725 || foundLiterals.contains(uniqueBindingId)) {
726 m_logger->log(QStringLiteral("Cannot combine value source and binding on "
727 "property \"%1\"")
728 .arg(propertyName),
729 qmlDuplicatePropertyBinding, objectBinding.location);
730 } else {
731 foundValueSources.insert(uniqueBindingId);
732 }
733 } else {
734 m_logger->log(QStringLiteral("On-binding for property \"%1\" has wrong type \"%2\"")
735 .arg(propertyName)
736 .arg(typeName),
737 qmlIncompatibleType, objectBinding.location);
738 }
739 } else {
740 // TODO: Warn here if binding.hasValue() is true
741 if (foundValueSources.contains(uniqueBindingId)) {
742 m_logger->log(
743 QStringLiteral("Cannot combine value source and binding on property \"%1\"")
744 .arg(propertyName),
745 qmlDuplicatePropertyBinding, objectBinding.location);
746 } else {
747 foundObjects.insert(uniqueBindingId);
748 }
749 }
750 }
751}
752
754{
755 for (const auto &required : m_requiredProperties) {
756 if (!required.scope->hasProperty(required.name)) {
757 m_logger->log(
758 QStringLiteral("Property \"%1\" was marked as required but does not exist.")
759 .arg(required.name),
760 qmlRequired, required.location);
761 }
762 }
763
764 for (const auto &defScope : m_objectDefinitionScopes) {
765 if (defScope->parentScope() == m_globalScope || defScope->isInlineComponent() || defScope->isComponentRootElement())
766 continue;
767
768 QVector<QQmlJSScope::ConstPtr> scopesToSearch;
769 for (QQmlJSScope::ConstPtr scope = defScope; scope; scope = scope->baseType()) {
770 scopesToSearch << scope;
771 const auto ownProperties = scope->ownProperties();
772 for (auto propertyIt = ownProperties.constBegin();
773 propertyIt != ownProperties.constEnd(); ++propertyIt) {
774 const QString propName = propertyIt.key();
775
776 QQmlJSScope::ConstPtr prevRequiredScope;
777 for (QQmlJSScope::ConstPtr requiredScope : scopesToSearch) {
778 if (requiredScope->isPropertyLocallyRequired(propName)) {
779 bool found =
780 std::find_if(scopesToSearch.constBegin(), scopesToSearch.constEnd(),
781 [&](QQmlJSScope::ConstPtr scope) {
782 return scope->hasPropertyBindings(propName);
783 })
784 != scopesToSearch.constEnd();
785
786 if (!found) {
787 const QString scopeId = m_scopesById.id(defScope, scope);
788 bool propertyUsedInRootAlias = false;
789 if (!scopeId.isEmpty()) {
790 for (const QQmlJSMetaProperty &property :
792 if (!property.isAlias())
793 continue;
794
795 QStringList aliasExpression =
796 property.aliasExpression().split(u'.');
797
798 if (aliasExpression.size() != 2)
799 continue;
800 if (aliasExpression[0] == scopeId
801 && aliasExpression[1] == propName) {
802 propertyUsedInRootAlias = true;
803 break;
804 }
805 }
806 }
807
808 if (propertyUsedInRootAlias)
809 continue;
810
811 const QQmlJSScope::ConstPtr propertyScope = scopesToSearch.size() > 1
812 ? scopesToSearch.at(scopesToSearch.size() - 2)
814
815 const QString propertyScopeName = !propertyScope.isNull()
817 : u"here"_s;
818
819 const QString requiredScopeName = prevRequiredScope
820 ? getScopeName(prevRequiredScope, QQmlSA::ScopeType::QMLScope)
821 : u"here"_s;
822
823 std::optional<QQmlJSFixSuggestion> suggestion;
824
827 "Component is missing required property %1 from %2")
828 .arg(propName)
829 .arg(propertyScopeName);
830 if (requiredScope != scope) {
831 if (!prevRequiredScope.isNull()) {
832 auto sourceScope = prevRequiredScope->baseType();
833 suggestion = QQmlJSFixSuggestion {
834 "%1:%2:%3: Property marked as required in %4"_L1
835 .arg(sourceScope->filePath())
836 .arg(sourceScope->sourceLocation().startLine)
837 .arg(sourceScope->sourceLocation().startColumn)
838 .arg(requiredScopeName),
839 sourceScope->sourceLocation()
840 };
841 suggestion->setFilename(sourceScope->filePath());
842 } else {
843 message += QStringLiteral(" (marked as required by %1)")
844 .arg(requiredScopeName);
845 }
846 }
847
848 m_logger->log(message, qmlRequired, defScope->sourceLocation(), true,
849 true, suggestion);
850 }
851 }
852 prevRequiredScope = requiredScope;
853 }
854 }
855 }
856 }
857}
858
860{
861 for (auto it = m_propertyBindings.constBegin(); it != m_propertyBindings.constEnd(); ++it) {
862 QQmlJSScope::Ptr scope = it.key();
863 for (auto &[visibilityScope, location, name] : it.value()) {
864 if (!scope->hasProperty(name)) {
865 // These warnings do not apply for custom parsers and their children and need to be
866 // handled on a case by case basis
867
868 if (scope->isInCustomParserParent())
869 continue;
870
871 // TODO: Can this be in a better suited category?
872 std::optional<QQmlJSFixSuggestion> fixSuggestion;
873
874 for (QQmlJSScope::ConstPtr baseScope = scope; !baseScope.isNull();
875 baseScope = baseScope->baseType()) {
876 if (auto suggestion = QQmlJSUtils::didYouMean(
877 name, baseScope->ownProperties().keys(), location);
878 suggestion.has_value()) {
879 fixSuggestion = suggestion;
880 break;
881 }
882 }
883
884 m_logger->log(QStringLiteral("Binding assigned to \"%1\", but no property \"%1\" "
885 "exists in the current element.")
886 .arg(name),
887 qmlMissingProperty, location, true, true, fixSuggestion);
888 continue;
889 }
890
891 const auto property = scope->property(name);
892 if (!property.type()) {
893 m_logger->log(QStringLiteral("No type found for property \"%1\". This may be due "
894 "to a missing import statement or incomplete "
895 "qmltypes files.")
896 .arg(name),
898 }
899
900 const auto &annotations = property.annotations();
901
902 const auto deprecationAnn =
903 std::find_if(annotations.cbegin(), annotations.cend(),
904 [](const QQmlJSAnnotation &ann) { return ann.isDeprecation(); });
905
906 if (deprecationAnn != annotations.cend()) {
907 const auto deprecation = deprecationAnn->deprecation();
908
909 QString message = QStringLiteral("Binding on deprecated property \"%1\"")
910 .arg(property.propertyName());
911
912 if (!deprecation.reason.isEmpty())
913 message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
914
916 }
917 }
918 }
919}
920
921void QQmlJSImportVisitor::checkSignal(
922 const QQmlJSScope::ConstPtr &signalScope, const QQmlJS::SourceLocation &location,
923 const QString &handlerName, const QStringList &handlerParameters)
924{
925 const auto signal = QQmlJSUtils::signalName(handlerName);
926
927 std::optional<QQmlJSMetaMethod> signalMethod;
928 const auto setSignalMethod = [&](const QQmlJSScope::ConstPtr &scope, const QString &name) {
929 const auto methods = scope->methods(name, QQmlJSMetaMethodType::Signal);
930 if (!methods.isEmpty())
931 signalMethod = methods[0];
932 };
933
934 if (signal.has_value()) {
935 if (signalScope->hasMethod(*signal)) {
936 setSignalMethod(signalScope, *signal);
937 } else if (auto p = QQmlJSUtils::changeHandlerProperty(signalScope, *signal);
938 p.has_value()) {
939 // we have a change handler of the form "onXChanged" where 'X'
940 // is a property name
941
942 // NB: qqmltypecompiler prefers signal to bindable
943 if (auto notify = p->notify(); !notify.isEmpty()) {
944 setSignalMethod(signalScope, notify);
945 } else {
946 Q_ASSERT(!p->bindable().isEmpty());
947 signalMethod = QQmlJSMetaMethod {}; // use dummy in this case
948 }
949 }
950 }
951
952 if (!signalMethod.has_value()) { // haven't found anything
953 std::optional<QQmlJSFixSuggestion> fix;
954
955 // There is a small chance of suggesting this fix for things that are not actually
956 // QtQml/Connections elements, but rather some other thing that is also called
957 // "Connections". However, I guess we can live with this.
958 if (signalScope->baseTypeName() == QStringLiteral("Connections")) {
959
960 // Cut to the end of the line to avoid hairy issues with pre-existing function()
961 // and the colon.
962 const qsizetype newLength = m_logger->code().indexOf(u'\n', location.end())
963 - location.offset;
964
965 fix = QQmlJSFixSuggestion {
966 "Implicitly defining %1 as signal handler in Connections is deprecated. "
967 "Create a function instead"_L1.arg(handlerName),
968 QQmlJS::SourceLocation(location.offset, newLength, location.startLine,
969 location.startColumn),
970 "function %1(%2) { ... }"_L1.arg(handlerName, handlerParameters.join(u", "))
971 };
972 }
973
974 m_logger->log(QStringLiteral("no matching signal found for handler \"%1\"")
975 .arg(handlerName),
976 qmlUnqualified, location, true, true, fix);
977 return;
978 }
979
980 const auto signalParameters = signalMethod->parameters();
981 QHash<QString, qsizetype> parameterNameIndexes;
982 // check parameter positions and also if signal is suitable for onSignal handler
983 for (int i = 0, end = signalParameters.size(); i < end; i++) {
984 auto &p = signalParameters[i];
985 parameterNameIndexes[p.name()] = i;
986
987 auto signalName = [&]() {
988 if (signal)
989 return u" called %1"_s.arg(*signal);
990 return QString();
991 };
992 auto type = p.type();
993 if (!type) {
994 m_logger->log(
996 "Type %1 of parameter %2 in signal%3 was not found, but is "
997 "required to compile %4. Did you add all import paths?")
998 .arg(p.typeName(), p.name(), signalName(), handlerName),
1000 continue;
1001 }
1002
1003 if (type->isComposite())
1004 continue;
1005
1006 // only accept following parameters for non-composite types:
1007 // * QObjects by pointer (nonconst*, const*, const*const,*const)
1008 // * Value types by value (QFont, int)
1009 // * Value types by const ref (const QFont&, const int&)
1010
1011 auto parameterName = [&]() {
1012 if (p.name().isEmpty())
1013 return QString();
1014 return u" called %1"_s.arg(p.name());
1015 };
1016 switch (type->accessSemantics()) {
1017 case QQmlJSScope::AccessSemantics::Reference:
1018 if (!p.isPointer())
1019 m_logger->log(QStringLiteral("Type %1 of parameter%2 in signal%3 should be "
1020 "passed by pointer to be able to compile %4. ")
1021 .arg(p.typeName(), parameterName(), signalName(),
1022 handlerName),
1024 break;
1025 case QQmlJSScope::AccessSemantics::Value:
1026 case QQmlJSScope::AccessSemantics::Sequence:
1027 if (p.isPointer())
1028 m_logger->log(
1030 "Type %1 of parameter%2 in signal%3 should be passed by "
1031 "value or const reference to be able to compile %4. ")
1032 .arg(p.typeName(), parameterName(), signalName(),
1033 handlerName),
1035 break;
1036 case QQmlJSScope::AccessSemantics::None:
1037 m_logger->log(
1038 QStringLiteral("Type %1 of parameter%2 in signal%3 required by the "
1039 "compilation of %4 cannot be used. ")
1040 .arg(p.typeName(), parameterName(), signalName(), handlerName),
1042 break;
1043 }
1044 }
1045
1046 if (handlerParameters.size() > signalParameters.size()) {
1047 m_logger->log(QStringLiteral("Signal handler for \"%2\" has more formal"
1048 " parameters than the signal it handles.")
1049 .arg(handlerName),
1051 return;
1052 }
1053
1054 for (qsizetype i = 0, end = handlerParameters.size(); i < end; i++) {
1055 const QStringView handlerParameter = handlerParameters.at(i);
1056 auto it = parameterNameIndexes.constFind(handlerParameter.toString());
1057 if (it == parameterNameIndexes.constEnd())
1058 continue;
1059 const qsizetype j = *it;
1060
1061 if (j == i)
1062 continue;
1063
1064 m_logger->log(QStringLiteral("Parameter %1 to signal handler for \"%2\""
1065 " is called \"%3\". The signal has a parameter"
1066 " of the same name in position %4.")
1067 .arg(i + 1)
1068 .arg(handlerName, handlerParameter)
1069 .arg(j + 1),
1071 }
1072}
1073
1075{
1077 if (m_currentScope == m_exportedRootScope || parentScope->isArrayScope()
1078 || m_currentScope->isInlineComponent()) // inapplicable
1079 return;
1080
1082
1083 if (parentScope->isInCustomParserParent())
1084 return;
1085
1086 /* consider:
1087 *
1088 * QtObject { // <- parentScope
1089 * default property var p // (1)
1090 * QtObject {} // (2)
1091 * }
1092 *
1093 * `p` (1) is a property of a subtype of QtObject, it couldn't be used
1094 * in a property binding (2)
1095 */
1096 // thus, use a base type of parent scope to detect a default property
1097 parentScope = parentScope->baseType();
1098
1099 const QString defaultPropertyName =
1100 parentScope ? parentScope->defaultPropertyName() : QString();
1101
1102 if (defaultPropertyName.isEmpty()) // an error somewhere else
1103 return;
1104
1105 // Note: in this specific code path, binding on default property
1106 // means an object binding (we work with pending objects here)
1107 QQmlJSMetaPropertyBinding binding(m_currentScope->sourceLocation(), defaultPropertyName);
1110 m_bindings.append(UnfinishedBinding { m_currentScope->parentScope(), [=]() { return binding; },
1112}
1113
1115{
1117 for (QQmlJSScope::ConstPtr scope = originalScope; scope;) {
1118 if (scopes.contains(scope)) {
1119 QString inheritenceCycle;
1120 for (const auto &seen : std::as_const(scopes)) {
1121 inheritenceCycle.append(seen->baseTypeName());
1122 inheritenceCycle.append(QLatin1String(" -> "));
1123 }
1124 inheritenceCycle.append(scopes.first()->baseTypeName());
1125
1126 const QString message = QStringLiteral("%1 is part of an inheritance cycle: %2")
1127 .arg(scope->internalName(), inheritenceCycle);
1129 originalScope->clearBaseType();
1130 originalScope->setBaseTypeError(message);
1131 break;
1132 }
1133
1134 scopes.append(scope);
1135
1136 const auto newScope = scope->baseType();
1137 if (newScope.isNull()) {
1138 const QString error = scope->baseTypeError();
1139 const QString name = scope->baseTypeName();
1140 if (!error.isEmpty()) {
1141 m_logger->log(error, qmlImport, scope->sourceLocation(), true, true);
1142 } else if (!name.isEmpty()) {
1143 m_logger->log(
1144 name + QStringLiteral(" was not found. Did you add all import paths?"),
1145 qmlImport, scope->sourceLocation(), true, true,
1147 m_rootScopeImports.types().keys(),
1148 scope->sourceLocation()));
1149 }
1150 }
1151
1152 scope = newScope;
1153 }
1154}
1155
1157{
1158 for (QQmlJSScope::ConstPtr scope = originalScope; scope; scope = scope->baseType()) {
1159 for (const QQmlJSAnnotation &annotation : scope->annotations()) {
1160 if (annotation.isDeprecation()) {
1161 QQQmlJSDeprecation deprecation = annotation.deprecation();
1162
1164 QStringLiteral("Type \"%1\" is deprecated").arg(scope->internalName());
1165
1166 if (!deprecation.reason.isEmpty())
1167 message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
1168
1169 m_logger->log(message, qmlDeprecated, originalScope->sourceLocation());
1170 }
1171 }
1172 }
1173}
1174
1176{
1177 // These warnings do not apply for custom parsers and their children and need to be handled on a
1178 // case by case basis
1179 if (scope->isInCustomParserParent())
1180 return;
1181
1182 auto children = scope->childScopes();
1183 while (!children.isEmpty()) {
1184 auto childScope = children.takeFirst();
1185 const auto type = childScope->scopeType();
1186 switch (type) {
1189 if (!childScope->baseType()) {
1190 m_logger->log(QStringLiteral("unknown %1 property scope %2.")
1192 ? QStringLiteral("grouped")
1193 : QStringLiteral("attached"),
1194 childScope->internalName()),
1195 qmlUnqualified, childScope->sourceLocation());
1196 }
1197 children.append(childScope->childScopes());
1198 default:
1199 break;
1200 }
1201 }
1202}
1203
1205{
1207 for (const QString &parameter : handler.signalParameters) {
1210 m_pendingSignalHandler, std::nullopt, false });
1211 }
1213}
1214
1224 const QString &name)
1225{
1226 auto &array = m_functionsAndExpressions[scope];
1227 array.emplaceBack(name);
1228
1229 // add current function to all preceding functions in the stack. we don't
1230 // know which one is going to be the "publicly visible" one, so just blindly
1231 // add it to every level and let further logic take care of that. this
1232 // matches what m_innerFunctions represents as function at each level just
1233 // got a new inner function
1234 for (const auto &function : m_functionStack)
1236 m_functionStack.push({ scope, name }); // create new function
1237
1238 return QQmlJSMetaMethod::RelativeFunctionIndex { int(array.size() - 1) };
1239}
1240
1251{
1252 auto nameToVerify = name.isEmpty() ? u"<anon>"_s : name;
1253 Q_UNUSED(nameToVerify);
1254 Q_ASSERT(!m_functionStack.isEmpty());
1255 Q_ASSERT(m_functionStack.top().name == nameToVerify);
1256 m_functionStack.pop();
1257}
1258
1272 const QQmlJSScope::Ptr &scope, int count) const
1273{
1274 const auto suitableScope = [](const QQmlJSScope::Ptr &scope) {
1275 const auto type = scope->scopeType();
1279 };
1280
1281 if (!suitableScope(scope))
1282 return count;
1283
1285 auto it = m_functionsAndExpressions.constFind(scope);
1286 if (it == m_functionsAndExpressions.cend()) // scope has no runtime functions
1287 return count;
1288
1289 const auto &functionsAndExpressions = *it;
1290 for (const QString &functionOrExpression : functionsAndExpressions) {
1293 ++count;
1294
1295 // there are special cases: onSignal: function() { doSomethingUsefull }
1296 // in which we would register 2 functions in the runtime functions table
1297 // for the same expression. even more, we can have named and unnamed
1298 // closures inside a function or a script binding e.g.:
1299 // ```
1300 // function foo() {
1301 // var closure = () => { return 42; }; // this is an inner function
1302 // /* or:
1303 // property = Qt.binding(function() { return anotherProperty; });
1304 // */
1305 // return closure();
1306 // }
1307 // ```
1308 // see Codegen::defineFunction() in qv4codegen.cpp for more details
1309 count += m_innerFunctions.value({ scope, functionOrExpression }, 0);
1310 }
1311
1312 return count;
1313}
1314
1316{
1317 int count = 0;
1318 const auto synthesize = [&](const QQmlJSScope::Ptr &current) {
1320 };
1322}
1323
1325{
1328 ast->firstSourceLocation());
1330 }
1331 return true;
1332}
1333
1335{
1337 && m_currentScope->baseTypeName() == u"signalhandler"_s) {
1339 }
1340}
1341
1343{
1345
1346 if (s.contains(QLatin1Char('\r')) || s.contains(QLatin1Char('\n')) || s.contains(QChar(0x2028u))
1347 || s.contains(QChar(0x2029u))) {
1348 QString templateString;
1349
1350 bool escaped = false;
1351 const QChar stringQuote = s[0];
1352 for (qsizetype i = 1; i < s.size() - 1; i++) {
1353 const QChar c = s[i];
1354
1355 if (c == u'\\') {
1356 escaped = !escaped;
1357 } else if (escaped) {
1358 // If we encounter an escaped quote, unescape it since we use backticks here
1359 if (c == stringQuote)
1360 templateString.chop(1);
1361
1362 escaped = false;
1363 } else {
1364 if (c == u'`')
1365 templateString += u'\\';
1366 if (c == u'$' && i + 1 < s.size() - 1 && s[i + 1] == u'{')
1367 templateString += u'\\';
1368 }
1369
1370 templateString += c;
1371 }
1372
1373 QQmlJSFixSuggestion suggestion = {
1374 "Use a template literal instead"_L1,
1375 sl->literalToken,
1376 u"`" % templateString % u"`"
1377 };
1378 suggestion.setAutoApplicable();
1379 m_logger->log(QStringLiteral("String contains unescaped line terminator which is "
1380 "deprecated."),
1381 qmlMultilineStrings, sl->literalToken, true, true, suggestion);
1382 }
1383
1384 return true;
1385}
1386
1389 const QQmlJS::SourceLocation &srcLocation);
1390
1392{
1393 const QString superType = buildName(definition->qualifiedTypeNameId);
1394
1395 const bool isRoot = !rootScopeIsValid();
1396 Q_ASSERT(!superType.isEmpty());
1397 if (superType.front().isUpper()) {
1398 if (!isRoot) {
1400 definition->firstSourceLocation());
1401 } else {
1402 enterRootScope(QQmlSA::ScopeType::QMLScope, superType,
1403 definition->firstSourceLocation());
1405 }
1406
1409 if (auto base = m_currentScope->baseType(); base) {
1410 if (isRoot && base->internalName() == u"QQmlComponent") {
1411 m_logger->log(u"Qml top level type cannot be 'Component'."_s, qmlTopLevelComponent,
1412 definition->qualifiedTypeNameId->identifierToken, true, true);
1413 }
1414 if (base->isSingleton() && m_currentScope->isComposite()) {
1415 m_logger->log(u"Singleton Type %1 is not creatable."_s.arg(
1418 true, true);
1419
1420 } else if (!base->isCreatable()) {
1421 // composite type m_currentScope is allowed to be uncreatable, but it cannot be the base of anything else
1422 m_logger->log(u"Type %1 is not creatable."_s.arg(m_currentScope->baseTypeName()),
1424 true, true);
1425 }
1426 }
1428 Q_ASSERT(std::holds_alternative<InlineComponentNameType>(m_currentRootName));
1429 const QString &name = std::get<InlineComponentNameType>(m_currentRootName);
1434 }
1435
1438 m_qmlTypes.append(m_currentScope);
1439
1441 } else {
1443 definition->firstSourceLocation());
1446 definition->firstSourceLocation()));
1448 }
1449
1451
1452 return true;
1453}
1454
1456{
1459}
1460
1462{
1463 if (!std::holds_alternative<RootDocumentNameType>(m_currentRootName)) {
1464 m_logger->log(u"Nested inline components are not supported"_s, qmlSyntax,
1465 component->firstSourceLocation());
1466 return true;
1467 }
1468
1470 m_currentRootName = component->name.toString();
1471 return true;
1472}
1473
1475{
1478 m_logger->log(u"Inline component declaration must be followed by a typename"_s,
1479 qmlSyntax, component->firstSourceLocation());
1480 }
1481 m_nextIsInlineComponent = false; // might have missed an inline component if file contains invalid QML
1482}
1483
1485{
1486 switch (publicMember->type) {
1488 if (m_currentScope->ownMethods().contains(publicMember->name.toString())) {
1489 m_logger->log(QStringLiteral("Duplicated signal name \"%1\".").arg(
1490 publicMember->name.toString()), qmlDuplicatedName,
1491 publicMember->firstSourceLocation());
1492 }
1493 UiParameterList *param = publicMember->parameters;
1495 method.setMethodType(QQmlJSMetaMethodType::Signal);
1496 method.setMethodName(publicMember->name.toString());
1497 while (param) {
1498 method.addParameter(
1500 param->name.toString(),
1501 param->type ? param->type->toString() : QString()
1502 ));
1503 param = param->next;
1504 }
1506 break;
1507 }
1509 if (m_currentScope->ownProperties().contains(publicMember->name.toString())) {
1510 m_logger->log(QStringLiteral("Duplicated property name \"%1\".").arg(
1511 publicMember->name.toString()), qmlDuplicatedName,
1512 publicMember->firstSourceLocation());
1513 }
1514 QString typeName = buildName(publicMember->memberType);
1515 QString aliasExpr;
1516 const bool isAlias = (typeName == u"alias"_s);
1517 if (isAlias) {
1518 auto tryParseAlias = [&]() {
1519 typeName.clear(); // type name is useless for alias here, so keep it empty
1520 if (!publicMember->statement) {
1521 m_logger->log(QStringLiteral("Invalid alias expression – an initalizer is needed."),
1522 qmlSyntax, publicMember->memberType->firstSourceLocation()); // TODO: extend warning to cover until endSourceLocation
1523 return;
1524 }
1525 const auto expression = cast<ExpressionStatement *>(publicMember->statement);
1526 auto node = expression ? expression->expression : nullptr;
1527 auto fex = cast<FieldMemberExpression *>(node);
1528 while (fex) {
1529 node = fex->base;
1530 aliasExpr.prepend(u'.' + fex->name.toString());
1531 fex = cast<FieldMemberExpression *>(node);
1532 }
1533
1534 if (const auto idExpression = cast<IdentifierExpression *>(node)) {
1535 aliasExpr.prepend(idExpression->name.toString());
1536 } else {
1537 // cast to expression might have failed above, so use publicMember->statement
1538 // to obtain the source location
1539 m_logger->log(QStringLiteral("Invalid alias expression. Only IDs and field "
1540 "member expressions can be aliased."),
1541 qmlSyntax, publicMember->statement->firstSourceLocation());
1542 }
1543 };
1544 tryParseAlias();
1545 } else {
1547 && !m_rootScopeImports.type(typeName).scope.isNull()) {
1550 }
1551 }
1552 QQmlJSMetaProperty prop;
1553 prop.setPropertyName(publicMember->name.toString());
1554 prop.setIsList(publicMember->typeModifier == QLatin1String("list"));
1555 prop.setIsWritable(!publicMember->isReadonly());
1556 prop.setAliasExpression(aliasExpr);
1557 const auto type =
1559 if (type) {
1560 prop.setType(prop.isList() ? type->listType() : type);
1561 const QString internalName = type->internalName();
1563 } else if (!isAlias) {
1565 publicMember->firstSourceLocation() };
1566 prop.setTypeName(typeName);
1567 }
1568 prop.setAnnotations(parseAnnotations(publicMember->annotations));
1569 if (publicMember->isDefaultMember())
1573 if (publicMember->isRequired())
1575
1577 // if property is an alias, initialization expression is not a binding
1578 if (!isAlias) {
1579 parseResult =
1580 parseBindingExpression(publicMember->name.toString(), publicMember->statement);
1581 }
1582
1583 // however, if we have a property with a script binding assigned to it,
1584 // we have to create a new scope
1585 if (parseResult == BindingExpressionParseResult::Script) {
1586 Q_ASSERT(!m_savedBindingOuterScope); // automatically true due to grammar
1589 publicMember->statement->firstSourceLocation());
1590 }
1591
1592 break;
1593 }
1594 }
1595
1596 return true;
1597}
1598
1600{
1604 // m_savedBindingOuterScope is only set if we encounter a script binding
1605 forgetFunctionExpression(publicMember->name.toString());
1606 }
1607}
1608
1610{
1611 const QString name = required->name.toString();
1612
1614 required->firstSourceLocation() };
1615
1617 return true;
1618}
1619
1620void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
1621{
1622 using namespace QQmlJS::AST;
1623 auto name = fexpr->name.toString();
1624 if (!name.isEmpty()) {
1626 method.setMethodType(QQmlJSMetaMethodType::Method);
1627
1628 if (!m_pendingMethodAnnotations.isEmpty()) {
1629 method.setAnnotations(m_pendingMethodAnnotations);
1631 }
1632
1633 // If signatures are explicitly ignored, we don't parse the types
1634 const bool parseTypes = m_scopesById.signaturesAreEnforced();
1635
1636 bool formalsFullyTyped = parseTypes;
1637 bool anyFormalTyped = false;
1638 if (const auto *formals = parseTypes ? fexpr->formals : nullptr) {
1639 const auto parameters = formals->formals();
1640 for (const auto &parameter : parameters) {
1641 const QString type = parameter.typeAnnotation
1642 ? parameter.typeAnnotation->type->toString()
1643 : QString();
1644 if (type.isEmpty()) {
1645 formalsFullyTyped = false;
1646 method.addParameter(QQmlJSMetaParameter(parameter.id, QStringLiteral("var")));
1647 } else {
1648 anyFormalTyped = true;
1649 method.addParameter(QQmlJSMetaParameter(parameter.id, type));
1650 }
1651 }
1652 }
1653
1654 // If a function is fully typed, we can call it like a C++ function.
1655 method.setIsJavaScriptFunction(!formalsFullyTyped);
1656
1657 // Methods with explicit return type return that.
1658 // Methods with only untyped arguments return an untyped value.
1659 // Methods with at least one typed argument but no explicit return type return void.
1660 // In order to make a function without arguments return void, you have to specify that.
1661 if (parseTypes && fexpr->typeAnnotation)
1662 method.setReturnTypeName(fexpr->typeAnnotation->type->toString());
1663 else if (anyFormalTyped)
1664 method.setReturnTypeName(QStringLiteral("void"));
1665 else
1666 method.setReturnTypeName(QStringLiteral("var"));
1667
1668 method.setJsFunctionIndex(addFunctionOrExpression(m_currentScope, method.methodName()));
1670
1674 fexpr->firstSourceLocation(),
1675 method.returnTypeName(), false });
1676 }
1678 } else {
1681 fexpr->firstSourceLocation());
1682 }
1683}
1684
1686{
1687 visitFunctionExpressionHelper(fexpr);
1688 return true;
1689}
1690
1692{
1695}
1696
1698{
1700 return true;
1701}
1702
1704{
1705 visitFunctionExpressionHelper(fdecl);
1706 return true;
1707}
1708
1710{
1713}
1714
1716{
1717 QQmlJSMetaProperty prop;
1718 prop.setPropertyName(ast->name.toString());
1721 ast->firstSourceLocation());
1722 return true;
1723}
1724
1726{
1728}
1729
1732{
1733 QStringView contextString;
1734 QStringView mainString;
1735 QStringView commentString;
1736 auto registerContextString = [&](QStringView string) {
1737 contextString = string;
1738 return 0;
1739 };
1740 auto registerMainString = [&](QStringView string) {
1741 mainString = string;
1742 return 0;
1743 };
1744 auto registerCommentString = [&](QStringView string) {
1745 commentString = string;
1746 return 0;
1747 };
1748 auto finalizeBinding = [&](QV4::CompiledData::Binding::Type type,
1751 binding.setTranslation(mainString, commentString, contextString, data.number);
1753 binding.setTranslationId(mainString, data.number);
1754 } else {
1755 binding.setStringLiteral(mainString);
1756 }
1757 };
1759 base, args,
1760 registerMainString, registerCommentString, registerContextString, finalizeBinding);
1761}
1762
1765 const QQmlJS::AST::Statement *statement)
1766{
1767 if (statement == nullptr)
1769
1770 const auto *exprStatement = cast<const ExpressionStatement *>(statement);
1771
1772 if (exprStatement == nullptr) {
1774
1775 if (const auto *block = cast<const Block *>(statement); block && block->statements) {
1776 location = block->statements->firstSourceLocation();
1777 }
1778
1782 m_bindings.append(UnfinishedBinding { m_currentScope, [=]() { return binding; } });
1784 }
1785
1786 auto expr = exprStatement->expression;
1788 combine(expr->firstSourceLocation(), expr->lastSourceLocation()),
1789 name);
1790
1791 bool isUndefinedBinding = false;
1792
1793 switch (expr->kind) {
1794 case Node::Kind_TrueLiteral:
1795 binding.setBoolLiteral(true);
1796 break;
1797 case Node::Kind_FalseLiteral:
1798 binding.setBoolLiteral(false);
1799 break;
1800 case Node::Kind_NullExpression:
1801 binding.setNullLiteral();
1802 break;
1803 case Node::Kind_IdentifierExpression: {
1804 auto idExpr = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(expr);
1805 Q_ASSERT(idExpr);
1806 isUndefinedBinding = (idExpr->name == u"undefined");
1807 break;
1808 }
1809 case Node::Kind_NumericLiteral:
1810 binding.setNumberLiteral(cast<NumericLiteral *>(expr)->value);
1811 break;
1812 case Node::Kind_StringLiteral:
1813 binding.setStringLiteral(cast<StringLiteral *>(expr)->value);
1814 break;
1815 case Node::Kind_RegExpLiteral:
1816 binding.setRegexpLiteral(cast<RegExpLiteral *>(expr)->pattern);
1817 break;
1818 case Node::Kind_TemplateLiteral: {
1819 auto templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
1820 Q_ASSERT(templateLit);
1821 if (templateLit->hasNoSubstitution) {
1822 binding.setStringLiteral(templateLit->value);
1823 } else {
1826 for (QQmlJS::AST::TemplateLiteral *l = templateLit; l; l = l->next) {
1827 if (QQmlJS::AST::ExpressionNode *expression = l->expression)
1828 expression->accept(this);
1829 }
1830 }
1831 break;
1832 }
1833 default:
1834 if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
1835 if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression))
1836 binding.setNumberLiteral(-lit->value);
1837 } else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
1838 if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base))
1839 handleTranslationBinding(binding, base->name, call->arguments);
1840 }
1841 break;
1842 }
1843
1844 if (!binding.isValid()) {
1845 // consider this to be a script binding (see IRBuilder::setBindingValue)
1850 }
1851 m_bindings.append(UnfinishedBinding { m_currentScope, [=]() { return binding; } });
1852
1853 // translations are neither literal bindings nor script bindings
1857 }
1858 if (!QQmlJSMetaPropertyBinding::isLiteralBinding(binding.bindingType()))
1862}
1863
1865{
1866 if (prefix.isEmpty() || !prefix.front().isUpper())
1867 return false;
1868
1869 return m_rootScopeImports.isNullType(prefix);
1870}
1871
1872void QQmlJSImportVisitor::handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding)
1873{
1874 const auto *statement = cast<ExpressionStatement *>(scriptBinding->statement);
1875 if (!statement) {
1876 m_logger->log(u"id must be followed by an identifier"_s, qmlSyntax,
1877 scriptBinding->statement->firstSourceLocation());
1878 return;
1879 }
1880 const QString name = [&]() {
1881 if (const auto *idExpression = cast<IdentifierExpression *>(statement->expression))
1882 return idExpression->name.toString();
1883 else if (const auto *idString = cast<StringLiteral *>(statement->expression)) {
1884 m_logger->log(u"ids do not need quotation marks"_s, qmlSyntaxIdQuotation,
1885 idString->firstSourceLocation());
1886 return idString->value.toString();
1887 }
1888 m_logger->log(u"Failed to parse id"_s, qmlSyntax,
1889 statement->expression->firstSourceLocation());
1890 return QString();
1891
1892 }();
1894 // ### TODO: find an alternative to breakInhertianceCycles here
1895 // we shouldn't need to search for the current root component in any case here
1897 if (auto otherScopeWithID = m_scopesById.scope(name, m_currentScope)) {
1898 auto otherLocation = otherScopeWithID->sourceLocation();
1899 // critical because subsequent analysis cannot cope with messed up ids
1900 // and the file is invalid
1901 m_logger->log(u"Found a duplicated id. id %1 was first declared at %2:%3"_s.arg(
1902 name, QString::number(otherLocation.startLine),
1903 QString::number(otherLocation.startColumn)),
1905 scriptBinding->firstSourceLocation());
1906 }
1907 }
1908 if (!name.isEmpty())
1910}
1911
1920 const QQmlJS::SourceLocation &srcLocation)
1921{
1922 const auto createBinding = [=]() {
1923 const QQmlJSScope::ScopeType type = scope->scopeType();
1929
1930 const auto propertyBindings = scope->parentScope()->ownPropertyBindings(name);
1931 const bool alreadyHasBinding = std::any_of(propertyBindings.first, propertyBindings.second,
1932 [&](const QQmlJSMetaPropertyBinding &binding) {
1933 return binding.bindingType() == bindingType;
1934 });
1935 if (alreadyHasBinding) // no need to create any more
1937
1938 QQmlJSMetaPropertyBinding binding(srcLocation, name);
1940 binding.setGroupBinding(static_cast<QSharedPointer<QQmlJSScope>>(scope));
1941 else
1942 binding.setAttachedBinding(static_cast<QSharedPointer<QQmlJSScope>>(scope));
1943 return binding;
1944 };
1945 return { scope->parentScope(), createBinding };
1946}
1947
1949{
1950 Q_ASSERT(!m_savedBindingOuterScope); // automatically true due to grammar
1951 Q_ASSERT(!m_thisScriptBindingIsJavaScript); // automatically true due to grammar
1953 const auto id = scriptBinding->qualifiedId;
1954 if (!id->next && id->name == QLatin1String("id")) {
1955 handleIdDeclaration(scriptBinding);
1956 return true;
1957 }
1958
1959 auto group = id;
1960
1961 QString prefix;
1962 for (; group->next; group = group->next) {
1963 const QString name = group->name.toString();
1964 if (name.isEmpty())
1965 break;
1966
1967 if (group == id && isImportPrefix(name)) {
1968 prefix = name + u'.';
1969 continue;
1970 }
1971
1972 const bool isAttachedProperty = name.front().isUpper();
1973 if (isAttachedProperty) {
1974 // attached property
1976 group->firstSourceLocation());
1977 } else {
1978 // grouped property
1980 group->firstSourceLocation());
1981 }
1983 group->firstSourceLocation()));
1984
1985 prefix.clear();
1986 }
1987
1988 auto name = group->name.toString();
1989
1990 // This is a preliminary check.
1991 // Even if the name starts with "on", it might later turn out not to be a signal.
1992 const auto signal = QQmlJSUtils::signalName(name);
1993
1994 if (!signal.has_value() || m_currentScope->hasProperty(name)) {
1996 { m_savedBindingOuterScope, group->firstSourceLocation(), name });
1997 // ### TODO: report Invalid parse status as a warning/error
1998 auto result = parseBindingExpression(name, scriptBinding->statement);
2000 } else {
2001 const auto statement = scriptBinding->statement;
2002 QStringList signalParameters;
2003
2004 if (ExpressionStatement *expr = cast<ExpressionStatement *>(statement)) {
2005 if (FunctionExpression *func = expr->expression->asFunctionDefinition()) {
2006 for (FormalParameterList *formal = func->formals; formal; formal = formal->next)
2007 signalParameters << formal->element->bindingIdentifier.toString();
2008 }
2009 }
2010
2011 QQmlJSMetaMethod scopeSignal;
2012 const auto methods = m_currentScope->methods(*signal, QQmlJSMetaMethodType::Signal);
2013 if (!methods.isEmpty())
2014 scopeSignal = methods[0];
2015
2016 const auto firstSourceLocation = statement->firstSourceLocation();
2017 bool hasMultilineStatementBody =
2018 statement->lastSourceLocation().startLine > firstSourceLocation.startLine;
2019 m_pendingSignalHandler = firstSourceLocation;
2020 m_signalHandlers.insert(firstSourceLocation,
2021 { scopeSignal.parameterNames(), hasMultilineStatementBody });
2022
2023 // NB: calculate runtime index right away to avoid miscalculation due to
2024 // losing real AST traversal order
2026 const auto createBinding = [
2027 this,
2028 scope = m_currentScope,
2029 signalName = *signal,
2030 index,
2031 name,
2032 firstSourceLocation,
2033 groupLocation = group->firstSourceLocation(),
2034 signalParameters]() {
2035 // when encountering a signal handler, add it as a script binding
2036 Q_ASSERT(scope->isFullyResolved());
2038 const auto methods = scope->methods(signalName, QQmlJSMetaMethodType::Signal);
2039 if (!methods.isEmpty()) {
2041 checkSignal(scope, groupLocation, name, signalParameters);
2042 } else if (QQmlJSUtils::changeHandlerProperty(scope, signalName).has_value()) {
2044 checkSignal(scope, groupLocation, name, signalParameters);
2045 } else if (scope->hasProperty(name)) {
2046 // Not a signal handler after all.
2047 // We can see this now because the type is fully resolved.
2049 m_signalHandlers.remove(firstSourceLocation);
2050 } else {
2051 // We already know it's bad, but let's allow checkSignal() to do its thing.
2052 checkSignal(scope, groupLocation, name, signalParameters);
2053 }
2054
2055 QQmlJSMetaPropertyBinding binding(firstSourceLocation, name);
2056 binding.setScriptBinding(index, kind);
2057 return binding;
2058 };
2061 }
2062
2063 // TODO: before leaving the scopes, we must create the binding.
2064
2065 // Leave any group/attached scopes so that the binding scope doesn't see its properties.
2069 }
2070
2072 scriptBinding->statement->firstSourceLocation());
2073
2074 return true;
2075}
2076
2078{
2082 }
2083
2084 // forgetFunctionExpression() but without the name check since script
2085 // bindings are special (script bindings only sometimes result in java
2086 // script bindings. e.g. a literal binding is also a UiScriptBinding)
2089 Q_ASSERT(!m_functionStack.isEmpty());
2090 m_functionStack.pop();
2091 }
2092}
2093
2095{
2097 arrayBinding->firstSourceLocation());
2099
2100 // TODO: support group/attached properties
2101
2102 return true;
2103}
2104
2106{
2107 // immediate children (QML scopes) of m_currentScope are the objects inside
2108 // the array binding. note that we always work with object bindings here as
2109 // this is the only kind of bindings that UiArrayBinding is created for. any
2110 // other expressions involving lists (e.g. `var p: [1,2,3]`) are considered
2111 // to be script bindings
2112 const auto children = m_currentScope->childScopes();
2113 const auto propertyName = getScopeName(m_currentScope, QQmlSA::ScopeType::QMLScope);
2115
2116 qsizetype i = 0;
2117 for (auto element = arrayBinding->members; element; element = element->next, ++i) {
2118 const auto &type = children[i];
2119 if ((type->scopeType() != QQmlSA::ScopeType::QMLScope)) {
2120 m_logger->log(u"Declaring an object which is not an Qml object"
2121 " as a list member."_s, qmlSyntax, element->firstSourceLocation());
2122 return;
2123 }
2126 element->firstSourceLocation(), false };
2127 QQmlJSMetaPropertyBinding binding(element->firstSourceLocation(), propertyName);
2130 m_bindings.append(UnfinishedBinding { m_currentScope, [=]() { return binding; },
2132 }
2133}
2134
2136{
2138 m_logger->log(u"Enums declared inside of inline component are ignored."_s, qmlSyntax,
2139 uied->firstSourceLocation());
2140 }
2141 QQmlJSMetaEnum qmlEnum(uied->name.toString());
2142 for (const auto *member = uied->members; member; member = member->next) {
2143 qmlEnum.addKey(member->member.toString());
2144 qmlEnum.addValue(int(member->value));
2145 }
2147 return true;
2148}
2149
2150void QQmlJSImportVisitor::addImportWithLocation(const QString &name,
2151 const QQmlJS::SourceLocation &loc)
2152{
2155 return;
2156
2158
2159 // If it's not valid it's a builtin. We don't need to complain about it being unused.
2160 if (loc.isValid())
2162}
2163
2164void QQmlJSImportVisitor::importFromHost(const QString &path, const QString &prefix,
2166{
2167 QFileInfo fileInfo(path);
2168 if (fileInfo.isFile()) {
2169 const auto scope = m_importer->importFile(path);
2170 const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix;
2171 m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
2172 addImportWithLocation(actualPrefix, location);
2173 } else if (fileInfo.isDir()) {
2174 const auto scopes = m_importer->importDirectory(path, prefix);
2176 for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++)
2177 addImportWithLocation(*it, location);
2178 }
2179}
2180
2181void QQmlJSImportVisitor::importFromQrc(const QString &path, const QString &prefix,
2183{
2184 if (const auto &mapper = m_importer->resourceFileMapper()) {
2185 if (mapper->isFile(path)) {
2186 const auto entry = m_importer->resourceFileMapper()->entry(
2188 const auto scope = m_importer->importFile(entry.filePath);
2189 const QString actualPrefix =
2190 prefix.isEmpty() ? QFileInfo(entry.resourcePath).baseName() : prefix;
2191 m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
2192 addImportWithLocation(actualPrefix, location);
2193 } else {
2194 const auto scopes = m_importer->importDirectory(path, prefix);
2196 for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++)
2197 addImportWithLocation(*it, location);
2198 }
2199 }
2200}
2201
2203{
2204 // construct path
2205 QString prefix = QLatin1String("");
2206 if (import->asToken.isValid()) {
2207 prefix += import->importId;
2208 }
2209
2210 auto filename = import->fileName.toString();
2211 if (!filename.isEmpty()) {
2212 const QUrl url(filename);
2213 const QString scheme = url.scheme();
2214 const QQmlJS::SourceLocation importLocation = import->firstSourceLocation();
2215 if (scheme == ""_L1) {
2216 QFileInfo fileInfo(url.path());
2217 QString absolute = fileInfo.isRelative()
2218 ? QDir::cleanPath(QDir(m_implicitImportDirectory).filePath(filename))
2219 : filename;
2220 if (absolute.startsWith(u':')) {
2221 importFromQrc(absolute, prefix, importLocation);
2222 } else {
2223 importFromHost(absolute, prefix, importLocation);
2224 }
2225 processImportWarnings("path \"%1\""_L1.arg(url.path()), importLocation);
2226 return true;
2227 } else if (scheme == "file"_L1) {
2228 importFromHost(url.path(), prefix, importLocation);
2229 processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation);
2230 return true;
2231 } else if (scheme == "qrc"_L1) {
2232 importFromQrc(":"_L1 + url.path(), prefix, importLocation);
2233 processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation);
2234 return true;
2235 } else {
2236 m_logger->log("Unknown import syntax. Imports can be paths, qrc urls or file urls"_L1,
2237 qmlImport, import->firstSourceLocation());
2238 }
2239 }
2240
2241 const QString path = buildName(import->importUri);
2242
2243 QStringList staticModulesProvided;
2244
2245 const auto imported = m_importer->importModule(
2246 path, prefix, import->version ? import->version->version : QTypeRevision(),
2247 &staticModulesProvided);
2248 m_rootScopeImports.addTypes(imported);
2249 for (auto it = imported.types().keyBegin(), end = imported.types().keyEnd(); it != end; it++)
2250 addImportWithLocation(*it, import->firstSourceLocation());
2251
2252 if (prefix.isEmpty()) {
2253 for (const QString &staticModule : staticModulesProvided) {
2254 // Always prefer a direct import of static module to it being imported as a dependency
2255 if (path != staticModule && m_importStaticModuleLocationMap.contains(staticModule))
2256 continue;
2257
2258 m_importStaticModuleLocationMap[staticModule] = import->firstSourceLocation();
2259 }
2260 }
2261
2262 processImportWarnings(QStringLiteral("module \"%1\"").arg(path), import->firstSourceLocation());
2263 return true;
2264}
2265
2266#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
2267template<typename F>
2269{
2270 for (const QQmlJS::AST::UiPragmaValueList *v = pragma->values; v; v = v->next)
2271 assign(v->value);
2272}
2273#else
2274template<typename F>
2275void handlePragmaValues(QQmlJS::AST::UiPragma *pragma, F &&assign)
2276{
2277 assign(pragma->value);
2278}
2279#endif
2280
2282{
2283 if (pragma->name == u"Strict"_s) {
2284 // If a file uses pragma Strict, it expects to be compiled, so automatically
2285 // enable compiler warnings unless the level is set explicitly already (e.g.
2286 // by the user).
2287
2289 // TODO: the logic here is rather complicated and may be buggy
2292 }
2293 } else if (pragma->name == u"Singleton") {
2294 m_rootIsSingleton = true;
2295 } else if (pragma->name == u"ComponentBehavior") {
2296 handlePragmaValues(pragma, [this, pragma](QStringView value) {
2297 if (value == u"Bound") {
2299 } else if (value == u"Unbound") {
2301 } else {
2302 m_logger->log(
2303 u"Unkonwn argument \"%s\" to pragma ComponentBehavior"_s.arg(value),
2304 qmlSyntax, pragma->firstSourceLocation());
2305 }
2306 });
2307 } else if (pragma->name == u"FunctionSignatureBehavior") {
2308 handlePragmaValues(pragma, [this, pragma](QStringView value) {
2309 if (value == u"Enforced") {
2311 } else if (value == u"Ignored") {
2313 } else {
2314 m_logger->log(
2315 u"Unkonwn argument \"%s\" to pragma FunctionSignatureBehavior"_s.arg(value),
2316 qmlSyntax, pragma->firstSourceLocation());
2317 }
2318 });
2319 } else if (pragma->name == u"ValueTypeBehavior") {
2320 handlePragmaValues(pragma, [this, pragma](QStringView value) {
2321 if (value == u"Copy") {
2322 // Ignore
2323 } else if (value == u"Reference") {
2324 // Ignore
2325 } else if (value == u"Addressable") {
2327 } else if (value == u"Inaddressable") {
2329 } else {
2330 m_logger->log(
2331 u"Unkonwn argument \"%s\" to pragma ValueTypeBehavior"_s.arg(value),
2332 qmlSyntax, pragma->firstSourceLocation());
2333 }
2334 });
2335 }
2336
2337 return true;
2338}
2339
2341{
2342 m_logger->log(QStringLiteral("Maximum statement or expression depth exceeded"),
2344}
2345
2347{
2349 ast->firstSourceLocation());
2350 return true;
2351}
2352
2354{
2356}
2357
2359{
2361 ast->firstSourceLocation());
2362 return true;
2363}
2364
2366{
2368}
2369
2371{
2373 ast->firstSourceLocation());
2374 return true;
2375}
2376
2378{
2380}
2381
2383{
2385 ast->firstSourceLocation());
2386
2389
2390 return true;
2391}
2392
2394{
2396}
2397
2399{
2401 ast->firstSourceLocation());
2402 return true;
2403}
2404
2406{
2408}
2409
2411{
2413 catchStatement->firstSourceLocation());
2415 catchStatement->patternElement->bindingIdentifier.toString(),
2416 { QQmlJSScope::JavaScriptIdentifier::LexicalScoped,
2417 catchStatement->patternElement->firstSourceLocation(), std::nullopt,
2418 catchStatement->patternElement->scope == QQmlJS::AST::VariableScope::Const });
2419 return true;
2420}
2421
2423{
2425}
2426
2428{
2430 ast->firstSourceLocation());
2431
2432 m_logger->log(QStringLiteral("with statements are strongly discouraged in QML "
2433 "and might cause false positives when analysing unqualified "
2434 "identifiers"),
2436
2437 return true;
2438}
2439
2441{
2443}
2444
2446{
2447 while (vdl) {
2448 std::optional<QString> typeName;
2449 if (TypeAnnotation *annotation = vdl->declaration->typeAnnotation)
2450 if (Type *type = annotation->type)
2451 typeName = type->toString();
2452
2455 { (vdl->declaration->scope == QQmlJS::AST::VariableScope::Var)
2456 ? QQmlJSScope::JavaScriptIdentifier::FunctionScoped
2457 : QQmlJSScope::JavaScriptIdentifier::LexicalScoped,
2458 vdl->declaration->firstSourceLocation(), typeName,
2459 vdl->declaration->scope == QQmlJS::AST::VariableScope::Const });
2460 vdl = vdl->next;
2461 }
2462 return true;
2463}
2464
2466{
2467 for (auto const &boundName : fpl->boundNames()) {
2468
2469 std::optional<QString> typeName;
2470 if (TypeAnnotation *annotation = boundName.typeAnnotation.data())
2471 if (Type *type = annotation->type)
2472 typeName = type->toString();
2473 m_currentScope->insertJSIdentifier(boundName.id,
2475 boundName.location, typeName, false });
2476 }
2477 return true;
2478}
2479
2481{
2482 // ... __styleData: QtObject {...}
2483
2485
2486 bool needsResolution = false;
2487 int scopesEnteredCounter = 0;
2488
2489 QString prefix;
2490 for (auto group = uiob->qualifiedId; group->next; group = group->next) {
2491 const QString idName = group->name.toString();
2492
2493 if (idName.isEmpty())
2494 break;
2495
2496 if (group == uiob->qualifiedId && isImportPrefix(idName)) {
2497 prefix = idName + u'.';
2498 continue;
2499 }
2500
2501 const auto scopeKind = idName.front().isUpper() ? QQmlSA::ScopeType::AttachedPropertyScope
2503
2504 bool exists =
2505 enterEnvironmentNonUnique(scopeKind, prefix + idName, group->firstSourceLocation());
2506
2508 group->firstSourceLocation()));
2509
2510 ++scopesEnteredCounter;
2511 needsResolution = needsResolution || !exists;
2512
2513 prefix.clear();
2514 }
2515
2516 for (int i=0; i < scopesEnteredCounter; ++i) { // leave the scopes we entered again
2518 }
2519
2520 // recursively resolve types for current scope if new scopes are found
2521 if (needsResolution)
2523
2527
2528 m_qmlTypes.append(m_currentScope); // new QMLScope is created here, so add it
2530 return true;
2531}
2532
2534{
2536 // must be mutable, as we might mark it as implicitly wrapped in a component
2537 const QQmlJSScope::Ptr childScope = m_currentScope;
2539
2540 auto group = uiob->qualifiedId;
2541 int scopesEnteredCounter = 0;
2542
2543 QString prefix;
2544 for (; group->next; group = group->next) {
2545 const QString idName = group->name.toString();
2546
2547 if (idName.isEmpty())
2548 break;
2549
2550 if (group == uiob->qualifiedId && isImportPrefix(idName)) {
2551 prefix = idName + u'.';
2552 continue;
2553 }
2554
2555 const auto scopeKind = idName.front().isUpper() ? QQmlSA::ScopeType::AttachedPropertyScope
2557 // definitely exists
2558 [[maybe_unused]] bool exists =
2559 enterEnvironmentNonUnique(scopeKind, prefix + idName, group->firstSourceLocation());
2560 Q_ASSERT(exists);
2561 scopesEnteredCounter++;
2562
2563 prefix.clear();
2564 }
2565
2566 // on ending the visit to UiObjectBinding, set the property type to the
2567 // just-visited one if the property exists and this type is valid
2568
2569 const QString propertyName = group->name.toString();
2570
2571 if (m_currentScope->isNameDeferred(propertyName)) {
2572 bool foundIds = false;
2573 QList<QQmlJSScope::ConstPtr> childScopes { childScope };
2574
2575 while (!childScopes.isEmpty()) {
2576 const QQmlJSScope::ConstPtr scope = childScopes.takeFirst();
2577 if (!m_scopesById.id(scope, scope).isEmpty()) {
2578 foundIds = true;
2579 break;
2580 }
2581
2582 childScopes << scope->childScopes();
2583 }
2584
2585 if (foundIds) {
2586 m_logger->log(
2587 u"Cannot defer property assignment to \"%1\". Assigning an id to an object or one of its sub-objects bound to a deferred property will make the assignment immediate."_s
2588 .arg(propertyName),
2590 }
2591 }
2592
2594 // These warnings do not apply for custom parsers and their children and need to be handled
2595 // on a case by case basis
2596 } else {
2598 << PendingPropertyObjectBinding { m_currentScope, childScope, propertyName,
2599 uiob->firstSourceLocation(), uiob->hasOnToken };
2600
2601 QQmlJSMetaPropertyBinding binding(uiob->firstSourceLocation(), propertyName);
2602 if (uiob->hasOnToken) {
2603 if (childScope->hasInterface(u"QQmlPropertyValueInterceptor"_s)) {
2605 QQmlJSScope::ConstPtr(childScope));
2606 } else { // if (childScope->hasInterface(u"QQmlPropertyValueSource"_s))
2608 QQmlJSScope::ConstPtr(childScope));
2609 }
2610 } else {
2612 QQmlJSScope::ConstPtr(childScope));
2613 }
2614 m_bindings.append(UnfinishedBinding { m_currentScope, [=]() { return binding; } });
2615 }
2616
2617 for (int i = 0; i < scopesEnteredCounter; ++i)
2619}
2620
2622{
2627 return true;
2628}
2629
2631{
2635}
2636
2638{
2640 enterRootScope(QQmlSA::ScopeType::JSLexicalScope, QStringLiteral("module"),
2641 module->firstSourceLocation());
2643 importBaseModules();
2645 return true;
2646}
2647
2649{
2651}
2652
2654{
2660 importBaseModules();
2661 return true;
2662}
2663
2665{
2667}
2668
2670{
2671 // This is a rather rough approximation of "used type" but the "unused import"
2672 // info message doesn't have to be 100% accurate.
2673 const QString name = fieldMember->name.toString();
2676 if (type.scope.isNull()) {
2679 } else if (!type.scope->ownAttachedTypeName().isEmpty()) {
2681 }
2682 }
2683}
2684
2686{
2687 const QString name = idexp->name.toString();
2690 }
2691
2692 return true;
2693}
2694
2696{
2697 // Handles variable declarations such as var x = [1,2,3].
2698 if (element->isVariableDeclaration()) {
2700 element->boundNames(&names);
2701 for (const auto &name : names) {
2702 std::optional<QString> typeName;
2703 if (TypeAnnotation *annotation = name.typeAnnotation.data())
2704 if (Type *type = annotation->type)
2705 typeName = type->toString();
2707 name.id,
2711 name.location, typeName,
2713 }
2714 }
2715
2716 return true;
2717}
2718
static JNINativeMethod methods[]
Definition lalr.h:137
\inmodule QtCore
Definition qchar.h:48
constexpr bool isUpper() const noexcept
Returns true if the character is an uppercase letter, for example category() is Letter_Uppercase.
Definition qchar.h:475
\inmodule QtCore
Definition qdir.h:19
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2395
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString baseName() const
Returns the base name of the file without the path.
QString absoluteFilePath() const
Returns an absolute path including the file name.
QString canonicalPath() const
Returns the file's path canonical path (excluding the file name), i.e.
bool isRelative() const
Returns true if the file path is relative, otherwise returns false (i.e.
\inmodule QtCore
Definition qhash.h:818
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
T & first()
Definition qlist.h:628
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator constBegin() const noexcept
Definition qlist.h:615
void append(parameter_type t)
Definition qlist.h:441
const_iterator constEnd() const noexcept
Definition qlist.h:616
QList< T > values() const
Returns a list containing all the values in the hash, in an arbitrary order.
Definition qhash.h:1676
bool contains(const Key &key) const noexcept
Definition qhash.h:1567
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1930
void setFilename(const QString &filename)
void setAutoApplicable(bool autoApply=true)
QStack< FunctionOrExpressionIdentifier > m_functionStack
void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope)
QHash< QQmlJSScope::ConstPtr, QList< QString > > m_functionsAndExpressions
QMultiHash< QString, QQmlJS::SourceLocation > m_importTypeLocationMap
QQmlJSScope::Ptr m_currentScope
QMultiHash< QString, QQmlJS::SourceLocation > m_importStaticModuleLocationMap
QQmlJS::SourceLocation m_pendingSignalHandler
QQmlJSScope::ConstPtr m_globalScope
void breakInheritanceCycles(const QQmlJSScope::Ptr &scope)
QList< QQmlJSScope::ConstPtr > m_qmlTypes
void checkDeprecation(const QQmlJSScope::ConstPtr &scope)
QQmlJSScope::Ptr m_savedBindingOuterScope
static QString implicitImportDirectory(const QString &localFile, QQmlJSResourceFileMapper *mapper)
void populateRuntimeFunctionIndicesForDocument() const
QHash< QQmlJS::SourceLocation, QQmlJSMetaSignalHandler > m_signalHandlers
QHash< QV4::CompiledData::Location, QQmlJSScope::ConstPtr > m_scopesByIrLocation
QList< UnfinishedBinding > m_bindings
QHash< QQmlJSScope::Ptr, QVector< QQmlJSScope::Ptr > > m_pendingDefaultProperties
QVector< QQmlJSScope::Ptr > m_objectDefinitionScopes
QVector< QQmlJSAnnotation > m_pendingMethodAnnotations
QQmlJSScope::RootDocumentNameType RootDocumentNameType
void endVisit(QQmlJS::AST::ExpressionStatement *ast) override
bool enterEnvironmentNonUnique(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
void throwRecursionDepthError() override
void forgetFunctionExpression(const QString &name)
QHash< FunctionOrExpressionIdentifier, int > m_innerFunctions
QQmlJSMetaMethod::RelativeFunctionIndex addFunctionOrExpression(const QQmlJSScope::ConstPtr &scope, const QString &name)
bool isImportPrefix(QString prefix) const
QVector< QQmlJSAnnotation > parseAnnotations(QQmlJS::AST::UiAnnotationList *list)
QVector< PendingPropertyObjectBinding > m_pendingPropertyObjectBindings
QSet< QQmlJS::SourceLocation > m_importLocations
QVector< RequiredProperty > m_requiredProperties
QVector< PendingPropertyType > m_pendingPropertyTypes
int synthesizeCompilationUnitRuntimeFunctionIndices(const QQmlJSScope::Ptr &scope, int count) const
QVector< QQmlJSScope::Ptr > m_objectBindingScopes
QSet< QQmlJSScope::ConstPtr > m_literalScopesToCheck
bool isTypeResolved(const QQmlJSScope::ConstPtr &type, ErrorHandler handle)
void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
bool visit(QQmlJS::AST::StringLiteral *) override
const QQmlJSScope::Ptr m_exportedRootScope
BindingExpressionParseResult parseBindingExpression(const QString &name, const QQmlJS::AST::Statement *statement)
QQmlJSImporter::ImportedTypes m_rootScopeImports
QHash< QQmlJSScope::Ptr, QVector< WithVisibilityScope< QString > > > m_propertyBindings
QQmlJSScopesById m_scopesById
QQmlJSScope::InlineComponentOrDocumentRootName m_currentRootName
void importQmldirs(const QStringList &qmltypesFiles)
Imports types from the specified qmltypesFiles.
ImportedTypes builtinInternalNames()
QQmlJSScope::Ptr importFile(const QString &file)
ImportedTypes importBuiltins()
Imports builtins.qmltypes and jsroot.qmltypes found in any of the import paths.
QList< QQmlJS::DiagnosticMessage > takeWarnings()
ImportedTypes importDirectory(const QString &directory, const QString &prefix=QString())
QQmlJSResourceFileMapper * resourceFileMapper() const
ImportedTypes importModule(const QString &module, const QString &prefix=QString(), QTypeRevision version=QTypeRevision(), QStringList *staticModuleList=nullptr)
void processMessages(const QList< QQmlJS::DiagnosticMessage > &messages, const QQmlJS::LoggerWarningId id)
QString code() const
QString fileName() const
bool wasCategoryChanged(QQmlJS::LoggerWarningId id) const
void setCategoryIgnored(QQmlJS::LoggerWarningId id, bool error)
void setCategoryLevel(QQmlJS::LoggerWarningId id, QtMsgType level)
void log(const QString &message, QQmlJS::LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation, bool showContext=true, bool showFileName=true, const std::optional< QQmlJSFixSuggestion > &suggestion={}, const QString overrideFileName=QString())
void addValue(int value)
void addKey(const QString &key)
QStringList parameterNames() const
void setStringLiteral(QAnyStringView value)
void setScriptBinding(QQmlJSMetaMethod::RelativeFunctionIndex value, ScriptBindingKind kind, ScriptBindingValueType valueType=ScriptBindingValueType::ScriptValue_Unknown)
void setRegexpLiteral(QAnyStringView value)
void setInterceptor(const QString &typeName, const QSharedPointer< const QQmlJSScope > &type)
void setTranslationId(QStringView id, int number)
void setObject(const QString &typeName, const QSharedPointer< const QQmlJSScope > &type)
void setGroupBinding(const QSharedPointer< const QQmlJSScope > &groupScope)
BindingType bindingType() const
void setNumberLiteral(double value)
void setAttachedBinding(const QSharedPointer< const QQmlJSScope > &attachingScope)
void setTranslation(QStringView text, QStringView comment, QStringView context, int number)
void setValueSource(const QString &typeName, const QSharedPointer< const QQmlJSScope > &type)
void setPropertyName(const QString &propertyName)
void setAnnotations(const QList< QQmlJSAnnotation > &annotation)
void setIsList(bool isList)
QSharedPointer< const QQmlJSScope > type() const
QString typeName() const
void setTypeName(const QString &typeName)
void setIsWritable(bool isWritable)
void setAliasExpression(const QString &aliasString)
void setIndex(int index)
void setType(const QSharedPointer< const QQmlJSScope > &type)
QString propertyName() const
void setIsPointer(bool isPointer)
Tracks the types for the QmlCompiler.
void setIsInlineComponent(bool v)
static void resolveGeneralizedGroup(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
bool isComposite() const
void setIsComposite(bool v)
void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
bool isNameDeferred(const QString &name) const
void clearBaseType()
void setIsScript(bool v)
QHash< QString, QQmlJSMetaMethod > methods() const
Returns all methods visible from this scope including those of base types and extensions.
QString defaultPropertyName() const
bool isInCustomParserParent() const
void setAnnotations(const QList< QQmlJSAnnotation > &annotation)
static QQmlJSScope::Ptr create()
const QList< QQmlJSAnnotation > & annotations() const
QQmlJSScope::Ptr parentScope()
ScopeType scopeType() const
void setInternalName(const QString &internalName)
QString baseTypeName() const
QString internalName() const
static bool causesImplicitComponentWrapping(const QQmlJSMetaProperty &property, const QQmlJSScope::ConstPtr &assignedType)
Returns if assigning assignedType to property would require an implicit component wrapping.
void setIsSingleton(bool v)
void setScopeType(ScopeType type)
void addOwnProperty(const QQmlJSMetaProperty &prop)
bool isInlineComponent() const
void insertPropertyIdentifier(const QQmlJSMetaProperty &prop)
void setIsArrayScope(bool v)
static QTypeRevision resolveTypes(const Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
QVector< QQmlJSScope::Ptr > childScopes()
void setBaseTypeName(const QString &baseTypeName)
bool isFullyResolved() const
bool hasInterface(const QString &name) const
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
bool hasMethod(const QString &name) const
bool isPropertyRequired(const QString &name) const
void setInlineComponentName(const QString &inlineComponentName)
static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin)
void addOwnEnumeration(const QQmlJSMetaEnum &enumeration)
bool isArrayScope() const
QDeferredSharedPointer< const QQmlJSScope > ConstPtr
QQmlJSMetaProperty property(const QString &name) const
static ImportedScope< QQmlJSScope::ConstPtr > findType(const QString &name, const ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
QQmlJSScope::ConstPtr baseType() const
void addOwnMethod(const QQmlJSMetaMethod &method)
std::optional< QString > inlineComponentName() const
QHash< QString, QQmlJSMetaProperty > ownProperties() const
void addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
void setOwnDefaultPropertyName(const QString &name)
bool hasProperty(const QString &name) const
static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
QMultiHash< QString, QQmlJSMetaPropertyBinding > ownPropertyBindings() const
QQmlJS::SourceLocation sourceLocation() const
QString baseTypeError() const
void setFilePath(const QString &file)
QMultiHash< QString, QQmlJSMetaMethod > ownMethods() const
void setPropertyLocallyRequired(const QString &name, bool isRequired)
void setBaseTypeError(const QString &baseTypeError)
QString id(const QQmlJSScope::ConstPtr &scope, const QQmlJSScope::ConstPtr &referrer) const
bool signaturesAreEnforced() const
bool existsAnywhereInDocument(const QString &id) const
void setValueTypesAreAddressable(bool addressable)
void setComponentsAreBound(bool bound)
QQmlJSScope::ConstPtr scope(const QString &id, const QQmlJSScope::ConstPtr &referrer) const
void setSignaturesAreEnforced(bool enforced)
void insert(const QString &id, const QQmlJSScope::ConstPtr &scope)
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
PatternElement * patternElement
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
FormalParameterList * formals
SourceLocation firstSourceLocation() const override
FunctionExpression * asFunctionDefinition() override
virtual SourceLocation firstSourceLocation() const =0
TypeAnnotation * typeAnnotation
virtual void boundNames(BoundNames *names)
bool isVariableDeclaration() const
SourceLocation literalToken
QString toString() const
UiQualifiedId * qualifiedTypeNameId
UiObjectInitializer * initializer
SourceLocation firstSourceLocation() const override
UiArrayMemberList * members
SourceLocation firstSourceLocation() const override
UiQualifiedId * qualifiedTypeNameId
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
UiAnnotationList * annotations
UiPragmaValueList * values
SourceLocation firstSourceLocation() const override
UiParameterList * parameters
SourceLocation firstSourceLocation() const override
enum QQmlJS::AST::UiPublicMember::@695 type
SourceLocation firstSourceLocation() const override
SourceLocation identifierToken
SourceLocation firstSourceLocation() const override
SourceLocation firstSourceLocation() const override
VariableDeclarationList * next
SourceLocation firstSourceLocation() const override
\inmodule QtCore
Definition qqueue.h:14
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition qqueue.h:18
T dequeue()
Removes the head item in the queue and returns it.
Definition qqueue.h:19
void swap(QQueue< T > &other) noexcept
Definition qqueue.h:17
Definition qset.h:18
qsizetype size() const
Definition qset.h:50
bool remove(const T &value)
Definition qset.h:63
iterator end()
Definition qset.h:140
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
QChar front() const
Definition qstring.h:214
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString & append(QChar c)
Definition qstring.cpp:3227
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString & prepend(QChar c)
Definition qstring.h:411
\inmodule QtCore
\inmodule QtCore
Definition qurl.h:94
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
static const char * s_globalNames[]
QSet< QString >::iterator it
auto signal
@ Script_PropertyBinding
@ Script_ChangeHandler
@ Script_SignalHandler
Combined button and popup list for selecting options.
void tryGeneratingTranslationBindingBase(QStringView base, QQmlJS::AST::ArgumentList *args, RegisterMainString registerMainString, RegisterCommentString registerCommentString, RegisterContextString registerContextString, FinalizeTranslationData finalizeTranslationData)
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
@ QtWarningMsg
Definition qlogging.h:31
const char * typeName
GLint location
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLint components
GLuint index
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLuint object
[3]
GLenum type
GLboolean GLuint group
GLenum target
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum const GLint * param
GLuint name
GLsizei GLenum const void * indices
GLenum func
Definition qopenglext.h:663
const GLubyte * c
GLuint segment
GLuint GLuint * names
GLuint entry
GLenum array
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static qreal component(const QPointF &point, unsigned int i)
static QQmlAnyBinding createBinding(const QQmlProperty &prop, const QV4::CompiledData::Binding *binding, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QQmlRefPointer< QQmlContextData > &contextData, QObject *scopeObject)
Definition qqmlbind.cpp:708
static QString internalName(const QQmlJSScope::ConstPtr &scope)
void handleTranslationBinding(QQmlJSMetaPropertyBinding &binding, QStringView base, QQmlJS::AST::ArgumentList *args)
void setScopeName(QQmlJSScope::Ptr &scope, QQmlJSScope::ScopeType type, const QString &name)
QString getScopeName(const QQmlJSScope::ConstPtr &scope, QQmlJSScope::ScopeType type)
void handlePragmaValues(QQmlJS::AST::UiPragma *pragma, F &&assign)
static bool mayBeUnresolvedGeneralizedGroupedProperty(const QQmlJSScope::ConstPtr &scope)
QQmlJSImportVisitor::UnfinishedBinding createNonUniqueScopeBinding(QQmlJSScope::Ptr &scope, const QString &name, const QQmlJS::SourceLocation &srcLocation)
QString buildName(const Node *node)
static QQmlJSAnnotation::Value bindingToVariant(QQmlJS::AST::Statement *statement)
const QQmlJS::LoggerWarningId qmlUnqualified
const QQmlJS::LoggerWarningId qmlNonListProperty
const QQmlJS::LoggerWarningId qmlImport
const QQmlJS::LoggerWarningId qmlSignalParameters
const QQmlJS::LoggerWarningId qmlDuplicatedName
const QQmlJS::LoggerWarningId qmlTopLevelComponent
const QQmlJS::LoggerWarningId qmlUnusedImports
const QQmlJS::LoggerWarningId qmlSyntaxDuplicateIds
const QQmlJS::LoggerWarningId qmlWith
const QQmlJS::LoggerWarningId qmlCompiler
const QQmlJS::LoggerWarningId qmlUnresolvedType
const QQmlJS::LoggerWarningId qmlRequired
const QQmlJS::LoggerWarningId qmlDuplicatePropertyBinding
const QQmlJS::LoggerWarningId qmlMissingProperty
const QQmlJS::LoggerWarningId qmlUncreatableType
const QQmlJS::LoggerWarningId qmlRecursionDepthErrors
const QQmlJS::LoggerWarningId qmlDeprecated
const QQmlJS::LoggerWarningId qmlSyntaxIdQuotation
const QQmlJS::LoggerWarningId qmlMissingType
const QQmlJS::LoggerWarningId qmlDeferredPropertyId
const QQmlJS::LoggerWarningId qmlAliasCycle
const QQmlJS::LoggerWarningId qmlUnresolvedAlias
const QQmlJS::LoggerWarningId qmlMultilineStrings
const QQmlJS::LoggerWarningId qmlSyntax
const QQmlJS::LoggerWarningId qmlInheritanceCycle
const QQmlJS::LoggerWarningId qmlIncompatibleType
@ ScriptValue_Unknown
@ ScriptValue_Undefined
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:70
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QGraphicsItem * item
QDataWidgetMapper * mapper
[0]
view create()
QJSValueList args
\inmodule QtCore \reentrant
Definition qchar.h:17
bool contains(const AT &t) const noexcept
Definition qlist.h:44
QHash< QString, Value > bindings
std::variant< QString, double > Value
Entry entry(const Filter &filter) const
static Filter resourceFileFilter(const QString &file)
static Filter localFileFilter(const QString &file)
const QHash< QString, ImportedScope< ConstPtr > > & types() const
bool hasType(const QString &name) const
void addTypes(ContextualTypes &&types)
void setType(const QString &name, const ImportedScope< ConstPtr > &type)
ImportedScope< ConstPtr > type(const QString &name) const
bool isNullType(const QString &name) const
static void traverseFollowingQmlIrObjectStructure(const QQmlJSScope::Ptr &root, Action act)
static std::optional< QQmlJSFixSuggestion > didYouMean(const QString &userInput, QStringList candidates, QQmlJS::SourceLocation location)
static std::optional< QQmlJSMetaProperty > changeHandlerProperty(const QQmlJSScope::ConstPtr &scope, QStringView signalName)
static std::optional< QString > signalName(QStringView handlerName)