aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljsscope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlcompiler/qqmljsscope.cpp')
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp513
1 files changed, 334 insertions, 179 deletions
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index e3d8bafeb3..535134072f 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -1,10 +1,13 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#include "qqmljscontextualtypes_p.h"
#include "qqmljsscope_p.h"
#include "qqmljstypereader_p.h"
#include "qqmljsimporter_p.h"
#include "qqmljsutils_p.h"
+#include "qqmlsa.h"
+#include "qqmlsa_p.h"
#include <QtCore/qqueue.h>
#include <QtCore/qsharedpointer.h>
@@ -26,13 +29,20 @@ QT_BEGIN_NAMESPACE
Multiple QQmlJSScope objects might be created for the same conceptual type, except when reused
due to extensive caching. Two QQmlJSScope objects are considered equal when they are backed
by the same implementation, that is, they have the same internalName.
- The qualifiedName of the QQmlJSScope for a type imported from multiple modules will contain the
- name of one of the modules that imported it, which is not unique and might change depending
- on the caching in .
*/
using namespace Qt::StringLiterals;
+QQmlJSScope::QQmlJSScope(const QString &internalName) : QQmlJSScope{}
+{
+ m_internalName = internalName;
+}
+
+QQmlJSScope::Ptr QQmlJSScope::create(const QString &internalName)
+{
+ return QSharedPointer<QQmlJSScope>(new QQmlJSScope(internalName));
+}
+
void QQmlJSScope::reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
{
if (const QQmlJSScope::Ptr parent = childScope->m_parentScope.toStrongRef())
@@ -53,16 +63,25 @@ QQmlJSScope::Ptr QQmlJSScope::clone(const ConstPtr &origin)
return cloned;
}
+/*!
+\internal
+Return all the JavaScript identifiers defined in the current scope.
+*/
+QHash<QString, QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifiers() const
+{
+ return m_jsIdentifiers;
+}
+
void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
{
- Q_ASSERT(m_scopeType != QQmlJSScope::QMLScope);
+ Q_ASSERT(m_scopeType != QQmlSA::ScopeType::QMLScope);
if (identifier.kind == JavaScriptIdentifier::LexicalScoped
- || identifier.kind == JavaScriptIdentifier::Injected
- || m_scopeType == QQmlJSScope::JSFunctionScope) {
+ || identifier.kind == JavaScriptIdentifier::Injected
+ || m_scopeType == QQmlSA::ScopeType::JSFunctionScope) {
m_jsIdentifiers.insert(name, identifier);
} else {
auto targetScope = parentScope();
- while (targetScope->m_scopeType != QQmlJSScope::JSFunctionScope)
+ while (targetScope->m_scopeType != QQmlSA::ScopeType::JSFunctionScope)
targetScope = targetScope->parentScope();
targetScope->m_jsIdentifiers.insert(name, identifier);
}
@@ -71,17 +90,13 @@ void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdenti
void QQmlJSScope::insertPropertyIdentifier(const QQmlJSMetaProperty &property)
{
addOwnProperty(property);
- QQmlJSMetaMethod method(property.propertyName() + u"Changed"_s, u"void"_s);
- method.setMethodType(QQmlJSMetaMethod::Signal);
+ QQmlJSMetaMethod method(
+ QQmlSignalNames::propertyNameToChangedSignalName(property.propertyName()), u"void"_s);
+ method.setMethodType(QQmlJSMetaMethodType::Signal);
method.setIsImplicitQmlPropertyChangeSignal(true);
addOwnMethod(method);
}
-bool QQmlJSScope::isIdInCurrentScope(const QString &id) const
-{
- return isIdInCurrentQmlScopes(id) || isIdInCurrentJSScopes(id);
-}
-
bool QQmlJSScope::hasMethod(const QString &name) const
{
return QQmlJSUtils::searchBaseAndExtensionTypes(
@@ -133,7 +148,7 @@ QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const
return results;
}
-QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name, QQmlJSMetaMethod::Type type) const
+QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name, QQmlJSMetaMethodType type) const
{
QList<QQmlJSMetaMethod> results;
@@ -157,15 +172,19 @@ bool QQmlJSScope::hasEnumeration(const QString &name) const
this, [&](const QQmlJSScope *scope) { return scope->m_enumerations.contains(name); });
}
+bool QQmlJSScope::hasOwnEnumerationKey(const QString &name) const
+{
+ for (const auto &e : m_enumerations) {
+ if (e.keys().contains(name))
+ return true;
+ }
+ return false;
+}
+
bool QQmlJSScope::hasEnumerationKey(const QString &name) const
{
- return QQmlJSUtils::searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
- for (const auto &e : scope->m_enumerations) {
- if (e.keys().contains(name))
- return true;
- }
- return false;
- });
+ return QQmlJSUtils::searchBaseAndExtensionTypes(
+ this, [&](const QQmlJSScope *scope) { return scope->hasOwnEnumerationKey(name); });
}
QQmlJSMetaEnum QQmlJSScope::enumeration(const QString &name) const
@@ -199,6 +218,36 @@ QHash<QString, QQmlJSMetaEnum> QQmlJSScope::enumerations() const
return results;
}
+QString QQmlJSScope::augmentedInternalName() const
+{
+ using namespace Qt::StringLiterals;
+
+ switch (m_semantics) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ break;
+ case AccessSemantics::None:
+ // If we got a namespace, it might still be a regular type, exposed as namespace.
+ // We may need to travel the inheritance chain all the way up to QObject to
+ // figure this out, since all other types may be exposed the same way.
+ for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) {
+ switch (base->accessSemantics()) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ return m_internalName;
+ case AccessSemantics::None:
+ break;
+ }
+ }
+ break;
+ }
+ return m_internalName;
+}
+
QString QQmlJSScope::prettyName(QAnyStringView name)
{
const auto internal = "$internal$."_L1;
@@ -221,47 +270,6 @@ QString QQmlJSScope::prettyName(QAnyStringView name)
}
/*!
- Returns if assigning \a assignedType to \a property would require an
- implicit component wrapping.
- */
-bool QQmlJSScope::causesImplicitComponentWrapping(const QQmlJSMetaProperty &property,
- const QQmlJSScope::ConstPtr &assignedType)
-{
- // See QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents()
- // for the logic in qqmltypecompiler
-
- // Note: unlike findAndRegisterImplicitComponents() we do not check whether
- // the property type is *derived* from QQmlComponent at some point because
- // this is actually meaningless (and in the case of QQmlComponent::create()
- // gets rejected in QQmlPropertyValidator): if the type is not a
- // QQmlComponent, we have a type mismatch because of assigning a Component
- // object to a non-Component property
- const bool propertyVerdict = property.type()->internalName() == u"QQmlComponent";
-
- const bool assignedTypeVerdict = [&assignedType]() {
- // Note: nonCompositeBaseType covers the case when assignedType itself
- // is non-composite
- auto cppBase = nonCompositeBaseType(assignedType);
- Q_ASSERT(cppBase); // any QML type has (or must have) a C++ base type
-
- // See isUsableComponent() in qqmltypecompiler.cpp: along with checking
- // whether a type has a QQmlComponent static meta object (which we
- // substitute here with checking the first non-composite base for being
- // a QQmlComponent), it also excludes QQmlAbstractDelegateComponent
- // subclasses from implicit wrapping
- if (cppBase->internalName() == u"QQmlComponent")
- return false;
- for (; cppBase; cppBase = cppBase->baseType()) {
- if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
- return false;
- }
- return true;
- }();
-
- return propertyVerdict && assignedTypeVerdict;
-}
-
-/*!
\internal
Returns true if the scope is the outermost element of a separate Component
Either because it has been implicitly wrapped, e.g. due to an assignment to
@@ -281,42 +289,12 @@ bool QQmlJSScope::isComponentRootElement() const {
return base->internalName() == u"QQmlComponent";
}
-bool QQmlJSScope::isIdInCurrentQmlScopes(const QString &id) const
-{
- if (m_scopeType == QQmlJSScope::QMLScope)
- return m_properties.contains(id) || m_methods.contains(id) || m_enumerations.contains(id);
-
- const auto qmlScope = findCurrentQMLScope(parentScope());
- return qmlScope->m_properties.contains(id)
- || qmlScope->m_methods.contains(id)
- || qmlScope->m_enumerations.contains(id);
-}
-
-bool QQmlJSScope::isIdInCurrentJSScopes(const QString &id) const
-{
- if (m_scopeType != QQmlJSScope::QMLScope && m_jsIdentifiers.contains(id))
- return true;
-
- for (auto jsScope = parentScope(); jsScope; jsScope = jsScope->parentScope()) {
- if (jsScope->m_scopeType != QQmlJSScope::QMLScope && jsScope->m_jsIdentifiers.contains(id))
- return true;
- }
-
- return false;
-}
-
-bool QQmlJSScope::isIdInjectedFromSignal(const QString &id) const
-{
- const auto found = findJSIdentifier(id);
- return found.has_value() && found->kind == JavaScriptIdentifier::Injected;
-}
-
std::optional<QQmlJSScope::JavaScriptIdentifier>
-QQmlJSScope::findJSIdentifier(const QString &id) const
+QQmlJSScope::jsIdentifier(const QString &id) const
{
for (const auto *scope = this; scope; scope = scope->parentScope().data()) {
- if (scope->m_scopeType == QQmlJSScope::JSFunctionScope
- || scope->m_scopeType == QQmlJSScope::JSLexicalScope) {
+ if (scope->m_scopeType == QQmlSA::ScopeType::JSFunctionScope
+ || scope->m_scopeType == QQmlSA::ScopeType::JSLexicalScope) {
auto it = scope->m_jsIdentifiers.find(id);
if (it != scope->m_jsIdentifiers.end())
return *it;
@@ -326,8 +304,17 @@ QQmlJSScope::findJSIdentifier(const QString &id) const
return std::optional<JavaScriptIdentifier>{};
}
+std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifier(const QString &id) const
+{
+ auto it = m_jsIdentifiers.find(id);
+ if (it != m_jsIdentifiers.end())
+ return *it;
+
+ return std::optional<JavaScriptIdentifier>{};
+}
+
static QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>
-qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &contextualTypes)
+qFindInlineComponents(QStringView typeName, const QQmlJS::ContextualTypes &contextualTypes)
{
const int separatorIndex = typeName.lastIndexOf(u'.');
// do not crash in typeName.sliced() when it starts or ends with an '.'.
@@ -363,8 +350,16 @@ qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &
return {};
}
+/*! \internal
+ * Finds a type in contextualTypes with given name.
+ * If a type is found, then its name is inserted into usedTypes (when provided).
+ * If contextualTypes has mode INTERNAl, then namespace resolution for enums is
+ * done (eg for Qt::Alignment).
+ * If contextualTypes has mode QML, then inline component resolution is done
+ * ("qmlFileName.IC" is correctly resolved from qmlFileName).
+ */
QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
- const QString &name, const QQmlJSScope::ContextualTypes &contextualTypes,
+ const QString &name, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
const auto useType = [&]() {
@@ -397,7 +392,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
};
switch (contextualTypes.context()) {
- case ContextualTypes::INTERNAL: {
+ case QQmlJS::ContextualTypes::INTERNAL: {
if (const auto listType = findListType(u"QList<"_s, u">"_s);
listType.scope && !listType.scope->isReferenceType()) {
return listType;
@@ -427,7 +422,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
break;
}
- case ContextualTypes::QML: {
+ case QQmlJS::ContextualTypes::QML: {
// look after inline components
const auto inlineComponent = qFindInlineComponents(name, contextualTypes);
if (inlineComponent.scope) {
@@ -445,7 +440,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
}
QTypeRevision QQmlJSScope::resolveType(
- const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
+ const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &context,
QSet<QString> *usedTypes)
{
if (self->accessSemantics() == AccessSemantics::Sequence
@@ -469,6 +464,7 @@ QTypeRevision QQmlJSScope::resolveType(
if (self->accessSemantics() == AccessSemantics::Sequence) {
// All sequence types are implicitly extended by JS Array.
self->setExtensionTypeName(u"Array"_s);
+ self->setExtensionIsJavaScript(true);
self->m_extensionType = context.arrayType();
}
} else {
@@ -495,37 +491,47 @@ QTypeRevision QQmlJSScope::resolveType(
}
}
- for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
- const QString returnTypeName = it->returnTypeName();
- if (!it->returnType() && !returnTypeName.isEmpty()) {
- const auto returnType = findType(returnTypeName, context, usedTypes);
- it->setReturnType(returnType.scope);
- }
-
- auto parameters = it->parameters();
- for (int i = 0, length = parameters.size(); i < length; ++i) {
- auto &parameter = parameters[i];
- if (const QString typeName = parameter.typeName();
- !parameter.type() && !typeName.isEmpty()) {
- const auto type = findType(typeName, context, usedTypes);
- if (type.scope && type.scope->isReferenceType())
- parameter.setIsPointer(true);
- parameter.setType({ type.scope });
+ const auto resolveParameter = [&](QQmlJSMetaParameter &parameter) {
+ if (const QString typeName = parameter.typeName();
+ !parameter.type() && !typeName.isEmpty()) {
+ auto type = findType(typeName, context, usedTypes);
+ if (type.scope && parameter.isList()) {
+ type.scope = type.scope->listType();
+ parameter.setIsList(false);
+ parameter.setIsPointer(false);
+ parameter.setTypeName(type.scope ? type.scope->internalName() : QString());
+ } else if (type.scope && type.scope->isReferenceType()) {
+ parameter.setIsPointer(true);
}
+ parameter.setType({ type.scope });
}
+ };
+ for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
+ auto returnValue = it->returnValue();
+ resolveParameter(returnValue);
+ it->setReturnValue(returnValue);
+
+ auto parameters = it->parameters();
+ for (int i = 0, length = parameters.size(); i < length; ++i)
+ resolveParameter(parameters[i]);
it->setParameters(parameters);
}
+ for (auto it = self->m_jsIdentifiers.begin(); it != self->m_jsIdentifiers.end(); ++it) {
+ if (it->typeName)
+ it->scope = findType(it->typeName.value(), context, usedTypes).scope;
+ }
+
return baseType.revision;
}
void QQmlJSScope::updateChildScope(
const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
- const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
+ const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
switch (childScope->scopeType()) {
- case QQmlJSScope::GroupedPropertyScope:
+ case QQmlSA::ScopeType::GroupedPropertyScope:
QQmlJSUtils::searchBaseAndExtensionTypes(
self.data(), [&](const QQmlJSScope *type, QQmlJSScope::ExtensionKind mode) {
if (mode == QQmlJSScope::ExtensionNamespace)
@@ -541,7 +547,7 @@ void QQmlJSScope::updateChildScope(
return false;
});
break;
- case QQmlJSScope::AttachedPropertyScope:
+ case QQmlSA::ScopeType::AttachedPropertyScope:
if (const auto attachedBase = findType(
childScope->internalName(), contextualTypes, usedTypes).scope) {
childScope->m_baseType.scope = attachedBase->attachedType();
@@ -556,7 +562,7 @@ void QQmlJSScope::updateChildScope(
template<typename Resolver, typename ChildScopeUpdater>
static QTypeRevision resolveTypesInternal(
Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self,
- const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
+ const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
// NB: constness ensures no detach
@@ -570,13 +576,13 @@ static QTypeRevision resolveTypesInternal(
}
QTypeRevision QQmlJSScope::resolveTypes(
- const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
const auto resolveAll = [](const QQmlJSScope::Ptr &self,
- const QQmlJSScope::ContextualTypes &contextualTypes,
+ const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes) {
- resolveEnums(self, contextualTypes.intType());
+ resolveEnums(self, contextualTypes, usedTypes);
resolveList(self, contextualTypes.arrayType());
return resolveType(self, contextualTypes, usedTypes);
};
@@ -584,12 +590,35 @@ QTypeRevision QQmlJSScope::resolveTypes(
}
void QQmlJSScope::resolveNonEnumTypes(
- const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
}
+static QString flagStorage(const QString &underlyingType)
+{
+ // All numeric types are builtins. Therefore we can exhaustively check the internal names.
+
+ if (underlyingType == u"uint"
+ || underlyingType == u"quint8"
+ || underlyingType == u"ushort"
+ || underlyingType == u"ulonglong") {
+ return u"uint"_s;
+ }
+
+ if (underlyingType == u"int"
+ || underlyingType == u"qint8"
+ || underlyingType == u"short"
+ || underlyingType == u"longlong") {
+ return u"int"_s;
+ }
+
+ // Will fail to resolve and produce an error on usage.
+ // It's harmless if you never use the enum.
+ return QString();
+}
+
/*!
\internal
Resolves all enums of self.
@@ -601,20 +630,28 @@ void QQmlJSScope::resolveNonEnumTypes(
resolveEnums() will create a QQmlJSMetaEnum copy for the alias in case the 'self'-scope already
does not have an enum called like the alias.
*/
-void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType)
+void QQmlJSScope::resolveEnums(
+ const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
{
// temporary hash to avoid messing up m_enumerations while iterators are active on it
QHash<QString, QQmlJSMetaEnum> toBeAppended;
- for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end;
- ++it) {
+ for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end; ++it) {
if (it->type())
continue;
- Q_ASSERT(intType); // We need an "int" type to resolve enums
QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
reparent(self, enumScope);
- enumScope->m_scopeType = EnumScope;
- enumScope->setBaseTypeName(QStringLiteral("int"));
- enumScope->m_baseType.scope = intType;
+ enumScope->m_scopeType = QQmlSA::ScopeType::EnumScope;
+
+ QString typeName = it->typeName();
+ if (typeName.isEmpty())
+ typeName = QStringLiteral("int");
+ else if (it->isFlag())
+ typeName = flagStorage(typeName);
+ enumScope->setBaseTypeName(typeName);
+ const auto type = findType(typeName, contextualTypes, usedTypes);
+ enumScope->m_baseType = { type.scope, type.revision };
+
enumScope->m_semantics = AccessSemantics::Value;
enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
if (QString alias = it->alias(); !alias.isEmpty()
@@ -656,9 +693,9 @@ void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::C
const QQmlJSImportedScope element = {self, QTypeRevision()};
const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
- QQmlJSScope::ContextualTypes contextualTypes(
- QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
- QQmlJSScope::ConstPtr(), arrayType);
+ QQmlJS::ContextualTypes contextualTypes(
+ QQmlJS::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
+ arrayType);
QQmlJSScope::resolveTypes(listType, contextualTypes);
Q_ASSERT(listType->valueType() == self);
@@ -667,7 +704,7 @@ void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::C
void QQmlJSScope::resolveGeneralizedGroup(
const Ptr &self, const ConstPtr &baseType,
- const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
+ const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
Q_ASSERT(baseType);
// Generalized group properties are always composite,
@@ -682,7 +719,7 @@ void QQmlJSScope::resolveGeneralizedGroup(
QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope)
{
auto qmlScope = scope;
- while (qmlScope && qmlScope->m_scopeType != QQmlJSScope::QMLScope)
+ while (qmlScope && qmlScope->m_scopeType != QQmlSA::ScopeType::QMLScope)
qmlScope = qmlScope->parentScope();
return qmlScope;
}
@@ -790,8 +827,21 @@ bool QQmlJSScope::isPropertyLocallyRequired(const QString &name) const
return m_requiredPropertyNames.contains(name);
}
-static_assert(QTypeInfo<QQmlJSScope::QmlIRCompatibilityBindingData>::isRelocatable,
- "We really want T to be relocatable as it improves QList<T> performance");
+void QQmlJSScope::addOwnPropertyBinding(const QQmlJSMetaPropertyBinding &binding, BindingTargetSpecifier specifier)
+{
+ Q_ASSERT(binding.sourceLocation().isValid());
+ m_propertyBindings.insert(binding.propertyName(), binding);
+
+ // NB: insert() prepends \a binding to the list of bindings, but we need
+ // append, so rotate
+ using iter = typename QMultiHash<QString, QQmlJSMetaPropertyBinding>::iterator;
+ QPair<iter, iter> r = m_propertyBindings.equal_range(binding.propertyName());
+ std::rotate(r.first, std::next(r.first), r.second);
+
+ // additionally store bindings in the QmlIR compatible order
+ addOwnPropertyBindingInQmlIROrder(binding, specifier);
+ Q_ASSERT(m_propertyBindings.size() == m_propertyBindingsArray.size());
+}
void QQmlJSScope::addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding,
BindingTargetSpecifier specifier)
@@ -803,6 +853,9 @@ void QQmlJSScope::addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBind
// * bindings to default properties (which are not explicitly mentioned in
// binding expression) are inserted by source location's offset
+ static_assert(QTypeInfo<QQmlJSScope::QmlIRCompatibilityBindingData>::isRelocatable,
+ "We really want T to be relocatable as it improves QList<T> performance");
+
switch (specifier) {
case BindingTargetSpecifier::SimplePropertyTarget: {
m_propertyBindingsArray.emplaceFront(binding.propertyName(),
@@ -941,22 +994,6 @@ bool QQmlJSScope::isNameDeferred(const QString &name) const
return isDeferred;
}
-QString QQmlJSScope::qualifiedNameFrom(const QString &moduleName, const QString &typeName,
- const QTypeRevision &firstRevision,
- const QTypeRevision &lastRevision)
-{
- QString qualifiedName =
- u"%1/%2 %3.%4"_s.arg(moduleName, typeName)
- .arg(firstRevision.hasMajorVersion() ? firstRevision.majorVersion() : 0)
- .arg(firstRevision.hasMinorVersion() ? firstRevision.minorVersion() : 0);
- if (firstRevision != lastRevision) {
- qualifiedName += u"-%1.%2"_s
- .arg(lastRevision.hasMajorVersion() ? lastRevision.majorVersion() : 0)
- .arg(lastRevision.hasMinorVersion() ? lastRevision.minorVersion() : 0);
- }
- return qualifiedName;
-}
-
void QQmlJSScope::setBaseTypeName(const QString &baseTypeName)
{
m_flags.setFlag(HasBaseTypeError, false);
@@ -974,6 +1011,22 @@ void QQmlJSScope::setBaseTypeError(const QString &baseTypeError)
m_baseTypeNameOrError = baseTypeError;
}
+/*!
+\internal
+The name of the module is only saved in the QmlComponent. Iterate through the parent scopes until
+the QmlComponent or the root is reached to find out the module name of the component in which `this`
+resides.
+*/
+QString QQmlJSScope::moduleName() const
+{
+ for (const QQmlJSScope *it = this; it; it = it->parentScope().get()) {
+ const QString name = it->ownModuleName();
+ if (!name.isEmpty())
+ return name;
+ }
+ return {};
+}
+
QString QQmlJSScope::baseTypeError() const
{
return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
@@ -1011,6 +1064,22 @@ QQmlJSScope::ConstPtr QQmlJSScope::attachedType() const
return ptr;
}
+QQmlJSScope::AnnotatedScope QQmlJSScope::extensionType() const
+{
+ if (!m_extensionType)
+ return { m_extensionType, NotExtension };
+ if (m_flags & ExtensionIsJavaScript)
+ return { m_extensionType, ExtensionJavaScript };
+ if (m_flags & ExtensionIsNamespace)
+ return { m_extensionType, ExtensionNamespace };
+ return { m_extensionType, ExtensionType };
+}
+
+void QQmlJSScope::addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
+{
+ m_runtimeFunctionIndices.emplaceBack(index);
+}
+
bool QQmlJSScope::isResolved() const
{
const bool nameIsEmpty = (m_scopeType == ScopeType::AttachedPropertyScope
@@ -1060,21 +1129,6 @@ bool QQmlJSScope::isFullyResolved() const
return baseResolved;
}
-QQmlJSScope::Import::Import(QString prefix, QString name, QTypeRevision version, bool isFile,
- bool isDependency) :
- m_prefix(std::move(prefix)),
- m_name(std::move(name)),
- m_version(version),
- m_isFile(isFile),
- m_isDependency(isDependency)
-{
-}
-
-bool QQmlJSScope::Import::isValid() const
-{
- return !m_name.isEmpty();
-}
-
QQmlJSScope::Export::Export(
QString package, QString type, QTypeRevision version, QTypeRevision revision)
: m_package(std::move(package))
@@ -1089,15 +1143,29 @@ bool QQmlJSScope::Export::isValid() const
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
+QDeferredFactory<QQmlJSScope>::QDeferredFactory(QQmlJSImporter *importer, const QString &filePath,
+ const TypeReader &typeReader)
+ : m_filePath(filePath),
+ m_importer(importer),
+ m_typeReader(typeReader ? typeReader
+ : [](QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate) {
+ QQmlJSTypeReader defaultTypeReader(importer, filePath);
+ defaultTypeReader(scopeToPopulate);
+ return defaultTypeReader.errors();
+ })
+{
+}
+
void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
- scope->setQualifiedName(m_qualifiedName);
- scope->setModuleName(m_moduleName);
- QQmlJSTypeReader typeReader(m_importer, m_filePath);
- typeReader(scope);
- m_importer->m_globalWarnings.append(typeReader.errors());
+ scope->setOwnModuleName(m_moduleName);
+
+ QList<QQmlJS::DiagnosticMessage> errors = m_typeReader(m_importer, m_filePath, scope);
+ m_importer->m_globalWarnings.append(errors);
+
scope->setInternalName(internalName());
- QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames().intType());
+ QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames());
QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
if (m_isSingleton && !scope->isSingleton()) {
@@ -1117,6 +1185,15 @@ void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &
}
}
+/*!
+ \internal
+ Checks whether \a derived type can be assigned to this type. Returns \c
+ true if the type hierarchy of \a derived contains a type equal to this.
+
+ \note Assigning \a derived to "QVariant" or "QJSValue" is always possible and
+ the function returns \c true in this case. In addition any "QObject" based \a derived type
+ can be assigned to a this type if that type is derived from "QQmlComponent".
+ */
bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
{
if (!derived)
@@ -1156,6 +1233,10 @@ bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
return isListProperty() && valueType()->canAssign(derived);
}
+/*!
+ \internal
+ Checks whether this type or its parents have a custom parser.
+*/
bool QQmlJSScope::isInCustomParserParent() const
{
for (const auto *scope = this; scope; scope = scope->parentScope().get()) {
@@ -1191,13 +1272,22 @@ QQmlJSScope::InlineComponentOrDocumentRootName QQmlJSScope::enclosingInlineCompo
return RootDocumentNameType();
}
+QVector<QQmlJSScope::ConstPtr> QQmlJSScope::childScopes() const
+{
+ QVector<QQmlJSScope::ConstPtr> result;
+ result.reserve(m_childScopes.size());
+ for (const auto &child : m_childScopes)
+ result.append(child);
+ return result;
+}
+
/*!
\internal
Returns true if the current type is creatable by checking all the required base classes.
"Uncreatability" is only inherited from base types for composite types (in qml) and not for non-composite types (c++).
- For the exact definition:
- A type is uncreatable if and only if one of its composite base type or its first non-composite base type matches
+For the exact definition:
+A type is uncreatable if and only if one of its composite base type or its first non-composite base type matches
following criteria:
\list
\li the base type is a singleton, or
@@ -1209,7 +1299,8 @@ QQmlJSScope::InlineComponentOrDocumentRootName QQmlJSScope::enclosingInlineCompo
bool QQmlJSScope::isCreatable() const
{
auto isCreatableNonRecursive = [](const QQmlJSScope *scope) {
- return scope->hasCreatableFlag() && !scope->isSingleton() && scope->scopeType() == QMLScope;
+ return scope->hasCreatableFlag() && !scope->isSingleton()
+ && scope->scopeType() == QQmlSA::ScopeType::QMLScope;
};
for (const QQmlJSScope* scope = this; scope; scope = scope->baseType().get()) {
@@ -1225,4 +1316,68 @@ bool QQmlJSScope::isCreatable() const
// no uncreatable bases found
return false;
}
+
+bool QQmlJSScope::isStructured() const
+{
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) {
+ if (!scope->isComposite())
+ return scope->hasStructuredFlag();
+ }
+ return false;
+}
+
+QQmlSA::Element QQmlJSScope::createQQmlSAElement(const ConstPtr &ptr)
+{
+ QQmlSA::Element element;
+ *reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = ptr;
+ return element;
+}
+
+QQmlSA::Element QQmlJSScope::createQQmlSAElement(ConstPtr &&ptr)
+{
+ QQmlSA::Element element;
+ *reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = std::move(ptr);
+ return element;
+}
+
+const QQmlJSScope::ConstPtr &QQmlJSScope::scope(const QQmlSA::Element &element)
+{
+ return *reinterpret_cast<const QQmlJSScope::ConstPtr *>(element.m_data);
+}
+
+QTypeRevision
+QQmlJSScope::nonCompositeBaseRevision(const ImportedScope<QQmlJSScope::ConstPtr> &scope)
+{
+ for (auto base = scope; base.scope;
+ base = { base.scope->m_baseType.scope, base.scope->m_baseType.revision }) {
+ if (!base.scope->isComposite())
+ return base.revision;
+ }
+ return {};
+}
+
+/*!
+ \internal
+ Checks whether \a otherScope is the same type as this.
+
+ In addition to checking whether the scopes are identical, we also cover duplicate scopes with
+ the same internal name.
+ */
+bool QQmlJSScope::isSameType(const ConstPtr &otherScope) const
+{
+ return this == otherScope.get()
+ || (!this->internalName().isEmpty()
+ && this->internalName() == otherScope->internalName());
+}
+
+bool QQmlJSScope::inherits(const ConstPtr &base) const
+{
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) {
+ if (scope->isSameType(base))
+ return true;
+ }
+ return false;
+}
+
+
QT_END_NAMESPACE