aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-12-17 14:23:55 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-01-21 14:23:08 +0100
commitcb4e0c119607a48e1f5e0cea9273afd914c15b25 (patch)
tree4717b75e129bc26bbb1b792092038a6c223617ae /src/qmlcompiler
parentdab5656d38a3d53c2d81b20e9bb8bc162edf7716 (diff)
QmlCompiler: Respect revisions
The only place where revisions matter is at the boundary between composite and non-composite types. The revision of the first composite type inherited from determines which members of all composite ancestors are available. Therefore, store the revision together with the base type and pass it through the imports to have it available. Then use it to check availability of methods and properties. The test exposes two further problems, which are fixed, too: 1. If no method is found to call, we need to generate an error in the type propagator. We don't know what the call will result in, after all, and the code generator should reject it. 2. We need to check the right scopes for hasOwnMethod(). Otherwise we might not find methods that are available. Fixes: QTBUG-99128 Change-Id: I4c320b8dfb490b140d7b8c16e6b638b32f156faa Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit e19d48d07310708e56cb379124dff193c1a7fa71)
Diffstat (limited to 'src/qmlcompiler')
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp61
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h8
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp36
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h4
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp127
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h86
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp18
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader_p.h2
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp7
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp57
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h7
11 files changed, 253 insertions, 160 deletions
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index 3e90c27736..a0d4a78fc9 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -176,7 +176,8 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
mo = qmlComponents.insert(it->fileName, {imported, QList<QQmlJSScope::Export>() });
}
- mo->exports.append(QQmlJSScope::Export(reader.typeNamespace(), it.key(), it->version));
+ mo->exports.append(QQmlJSScope::Export(
+ reader.typeNamespace(), it.key(), it->version, QTypeRevision()));
}
for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
result.objects.insert(it.key(), it.value());
@@ -209,7 +210,8 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
mo = result.scripts.insert(script.fileName, { localFile2ScopeTree(filePath), {} });
mo->exports.append(QQmlJSScope::Export(
- reader.typeNamespace(), script.nameSpace, script.version));
+ reader.typeNamespace(), script.nameSpace,
+ script.version, QTypeRevision()));
}
return result;
}
@@ -245,14 +247,21 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
const QString anonPrefix = QStringLiteral("$anonymous$");
QHash<QString, QList<QQmlJSScope::Export>> seenExports;
- const auto insertExports = [&](const QQmlJSExportedScope &val) {
+ const auto insertExports = [&](const QQmlJSExportedScope &val, const QString &cppName) {
+ QQmlJSScope::Export bestExport;
+
// Resolve conflicting qmlNames within an import
for (const auto &valExport : val.exports) {
- const QString name = prefixedName(importDescription.prefix(), valExport.type());
+ const QString qmlName = prefixedName(importDescription.prefix(), valExport.type());
if (!isVersionAllowed(valExport, importDescription))
continue;
- const auto it = types->qmlNames.constFind(name);
+ // Even if the QML name is overridden by some other type, we still want
+ // to insert the C++ type, with the highest revision available.
+ if (!bestExport.isValid() || valExport.version() > bestExport.version())
+ bestExport = valExport;
+
+ const auto it = types->qmlNames.constFind(qmlName);
if (it != types->qmlNames.constEnd()) {
// The same set of exports can declare the same name multiple times for different
@@ -260,13 +269,13 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
// it again after having inserted successfully once.
// However, it can also declare *different* names. Then we need to do the whole
// thing again.
- if (*it == val.scope)
+ if (it->scope == val.scope && it->revision == valExport.version())
continue;
- const auto existingExports = seenExports.value(name);
+ const auto existingExports = seenExports.value(qmlName);
enum { LowerVersion, SameVersion, HigherVersion } seenVersion = LowerVersion;
for (const QQmlJSScope::Export &entry : existingExports) {
- if (entry.type() != name || !isVersionAllowed(entry, importDescription))
+ if (entry.type() != qmlName || !isVersionAllowed(entry, importDescription))
continue;
if (valExport.version() < entry.version()) {
@@ -285,7 +294,7 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
m_warnings.append({
QStringLiteral("Ambiguous type detected. "
"%1 %2.%3 is defined multiple times.")
- .arg(name)
+ .arg(qmlName)
.arg(valExport.version().majorVersion())
.arg(valExport.version().minorVersion()),
QtCriticalMsg,
@@ -293,7 +302,7 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
});
// Remove the name. We don't know which one to use.
- types->qmlNames.remove(name);
+ types->qmlNames.remove(qmlName);
continue;
}
case HigherVersion:
@@ -301,39 +310,40 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
}
}
- types->qmlNames.insert(name, val.scope);
-
- // We replace the exports for name, as the new set is clearly superior when we get here.
- seenExports.insert(name, val.exports);
+ types->qmlNames.insert(qmlName, { val.scope, valExport.version() });
+ seenExports[qmlName].append(valExport);
}
+
+ if (bestExport.isValid())
+ types->cppNames.insert(cppName, { val.scope, bestExport.revision() });
};
if (!importDescription.prefix().isEmpty())
types->qmlNames.insert(importDescription.prefix(), {}); // Empty type means "this is the prefix"
for (auto it = import.scripts.begin(); it != import.scripts.end(); ++it) {
- types->cppNames.insert(prefixedName(anonPrefix, internalName(it->scope)), it->scope);
// You cannot have a script without an export
Q_ASSERT(!it->exports.isEmpty());
- insertExports(*it);
+ insertExports(*it, prefixedName(anonPrefix, internalName(it->scope)));
}
// add objects
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
const auto &val = it.value();
- const QString name = isComposite(val.scope)
+ const QString cppName = isComposite(val.scope)
? prefixedName(anonPrefix, internalName(val.scope))
: internalName(val.scope);
- types->cppNames.insert(name, val.scope);
if (val.exports.isEmpty()) {
// Insert an unresolvable dummy name
types->qmlNames.insert(
prefixedName(importDescription.prefix(), prefixedName(
- anonPrefix, internalName(val.scope))), val.scope);
+ anonPrefix, internalName(val.scope))),
+ { val.scope, QTypeRevision() });
+ types->cppNames.insert(cppName, { val.scope, QTypeRevision() });
} else {
- insertExports(val);
+ insertExports(val, cppName);
}
}
@@ -366,7 +376,7 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
// only happen when enumerations are involved, thus the strategy is to
// resolve enumerations (which can potentially create new child scopes)
// before resolving the type fully
- const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.value(u"int"_qs);
+ const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.value(u"int"_qs).scope;
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
if (!it->scope.factory())
QQmlJSScope::resolveEnums(it->scope, intType);
@@ -648,8 +658,9 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
for (const auto &entry : resources) {
const QString name = QFileInfo(entry.resourcePath).baseName();
if (name.front().isUpper()) {
- types.qmlNames.insert(prefixedName(prefix, name),
- localFile2ScopeTree(entry.filePath));
+ types.qmlNames.insert(
+ prefixedName(prefix, name),
+ { localFile2ScopeTree(entry.filePath), QTypeRevision() });
}
}
} else {
@@ -673,7 +684,7 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
continue; // Non-uppercase names cannot be imported anyway.
types.qmlNames.insert(prefixedName(prefix, QFileInfo(it.filePath()).baseName()),
- localFile2ScopeTree(it.filePath()));
+ { localFile2ScopeTree(it.filePath()), QTypeRevision() });
}
importHelper(directory, &types, QString(), QTypeRevision(), false, true);
@@ -694,7 +705,7 @@ void QQmlJSImporter::setImportPaths(const QStringList &importPaths)
QQmlJSScope::ConstPtr QQmlJSImporter::jsGlobalObject() const
{
- return m_builtins.cppNames[u"GlobalObject"_qs];
+ return m_builtins.cppNames[u"GlobalObject"_qs].scope;
}
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h
index 429d8dfe5a..e30b41ab1e 100644
--- a/src/qmlcompiler/qqmljsimporter_p.h
+++ b/src/qmlcompiler/qqmljsimporter_p.h
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
class QQmlJSImporter
{
public:
- using ImportedTypes = QHash<QString, QQmlJSScope::ConstPtr>;
+ using ImportedTypes = QHash<QString, QQmlJSImportedScope>;
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper)
: m_importPaths(importPaths)
@@ -91,15 +91,15 @@ private:
struct AvailableTypes
{
- AvailableTypes(QHash<QString, QQmlJSScope::ConstPtr> builtins)
+ AvailableTypes(ImportedTypes builtins)
: cppNames(std::move(builtins))
{}
// C++ names used in qmltypes files for non-composite types
- QHash<QString, QQmlJSScope::ConstPtr> cppNames;
+ ImportedTypes cppNames;
// Names the importing component sees, including any prefixes
- QHash<QString, QQmlJSScope::ConstPtr> qmlNames;
+ ImportedTypes qmlNames;
};
struct Import {
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 399d9622de..4eedacc60c 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -557,7 +557,7 @@ void QQmlJSImportVisitor::processPropertyTypes()
auto property = type.scope->ownProperty(type.name);
- if (const auto propertyType = m_rootScopeImports.value(property.typeName())) {
+ if (const auto propertyType = m_rootScopeImports.value(property.typeName()).scope) {
property.setType(propertyType);
type.scope->addOwnProperty(property);
} else {
@@ -1095,20 +1095,23 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
if (!m_exportedRootScope)
m_exportedRootScope = m_currentScope;
+ const QTypeRevision revision = QQmlJSScope::resolveTypes(
+ m_currentScope, m_rootScopeImports, &m_usedTypes);
if (m_nextIsInlineComponent) {
m_currentScope->setIsInlineComponent(true);
- m_rootScopeImports.insert(m_inlineComponentName.toString(), m_currentScope);
+ m_rootScopeImports.insert(
+ m_inlineComponentName.toString(), { m_currentScope, revision });
m_nextIsInlineComponent = false;
}
} else {
enterEnvironmentNonUnique(QQmlJSScope::GroupedPropertyScope, superType,
definition->firstSourceLocation());
Q_ASSERT(m_exportedRootScope);
+ QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
}
m_currentScope->setAnnotations(parseAnnotations(definition->annotations));
- QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
addDefaultProperties();
if (m_currentScope->scopeType() == QQmlJSScope::QMLScope)
m_qmlTypes.append(m_currentScope);
@@ -1185,7 +1188,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
}
} else {
const auto name = publicMember->memberType->name.toString();
- if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].isNull()) {
+ if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].scope.isNull()) {
if (m_importTypeLocationMap.contains(name))
m_usedTypes.insert(name);
}
@@ -1195,7 +1198,9 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
prop.setIsList(publicMember->typeModifier == QLatin1String("list"));
prop.setIsWritable(!publicMember->isReadonly());
prop.setAliasExpression(aliasExpr);
- const auto type = isAlias ? QQmlJSScope::ConstPtr() : m_rootScopeImports.value(typeName);
+ const auto type = isAlias
+ ? QQmlJSScope::ConstPtr()
+ : m_rootScopeImports.value(typeName).scope;
if (type) {
prop.setType(type);
const QString internalName = type->internalName();
@@ -1341,7 +1346,7 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::ClassExpression *)
// ### TODO: add warning about suspicious translation binding when returning false?
static std::optional<QQmlJSMetaPropertyBinding>
handleTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args,
- const QHash<QString, QQmlJSScope::ConstPtr> &rootScopeImports,
+ const QQmlJSImporter::ImportedTypes &rootScopeImports,
const QQmlJS::SourceLocation &location)
{
std::optional<QQmlJSMetaPropertyBinding> maybeBinding = std::nullopt;
@@ -1354,12 +1359,15 @@ handleTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args,
auto finalizeBinding = [&](QV4::CompiledData::Binding::ValueType type,
QV4::CompiledData::TranslationData) {
QQmlJSMetaPropertyBinding binding(location);
- if (type == QV4::CompiledData::Binding::Type_Translation)
+ if (type == QV4::CompiledData::Binding::Type_Translation) {
binding.setTranslation(mainString);
- else if (type == QV4::CompiledData::Binding::Type_TranslationById)
+ } else if (type == QV4::CompiledData::Binding::Type_TranslationById) {
binding.setTranslationId(mainString);
- else
- binding.setLiteral(QQmlJSMetaPropertyBinding::StringLiteral, u"string"_qs, mainString.toString(), rootScopeImports[u"string"_qs]);
+ } else {
+ binding.setLiteral(
+ QQmlJSMetaPropertyBinding::StringLiteral, u"string"_qs,
+ mainString.toString(), rootScopeImports[u"string"_qs].scope);
+ }
maybeBinding = binding;
};
QmlIR::tryGeneratingTranslationBindingBase(base, args, registerMainString, discardCommentString, finalizeBinding);
@@ -1454,7 +1462,7 @@ bool QQmlJSImportVisitor::parseLiteralBinding(const QString name,
Q_ASSERT(m_rootScopeImports.contains(literalType)); // built-ins must contain support for all literal bindings
QQmlJSMetaPropertyBinding binding(exprStatement->expression->firstSourceLocation(), name);
- binding.setLiteral(bindingType, literalType, value, m_rootScopeImports[literalType]);
+ binding.setLiteral(bindingType, literalType, value, m_rootScopeImports[literalType].scope);
m_currentScope->addOwnPropertyBinding(binding);
@@ -1655,7 +1663,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
const QString actualPrefix = prefix.isEmpty()
? QFileInfo(entry.resourcePath).baseName()
: prefix;
- m_rootScopeImports.insert(actualPrefix, scope);
+ m_rootScopeImports.insert(actualPrefix, { scope, QTypeRevision() });
addImportLocation(actualPrefix);
} else {
@@ -1679,7 +1687,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
} else if (path.isFile()) {
const auto scope = m_importer->importFile(path.canonicalFilePath());
const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix;
- m_rootScopeImports.insert(actualPrefix, scope);
+ m_rootScopeImports.insert(actualPrefix, { scope, QTypeRevision() });
addImportLocation(actualPrefix);
}
@@ -2014,7 +2022,7 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::FieldMemberExpression *fieldMemb
{
const QString name = fieldMember->name.toString();
if (m_importTypeLocationMap.contains(name)) {
- if (auto it = m_rootScopeImports.find(name); it != m_rootScopeImports.end() && !*(it))
+ if (auto it = m_rootScopeImports.find(name); it != m_rootScopeImports.end() && !it->scope)
m_usedTypes.insert(name);
}
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 065746b53a..65124b20c1 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -68,7 +68,7 @@ public:
QQmlJSLogger *logger() { return m_logger; }
- QHash<QString, QQmlJSScope::ConstPtr> imports() const { return m_rootScopeImports; }
+ QQmlJSImporter::ImportedTypes imports() const { return m_rootScopeImports; }
QQmlJSScopesById addressableScopes() const { return m_scopesById; }
QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> signalHandlers() const
{
@@ -158,7 +158,7 @@ protected:
QQmlJSScope::Ptr m_exportedRootScope;
QQmlJSScope::ConstPtr m_globalScope;
QQmlJSScopesById m_scopesById;
- QHash<QString, QQmlJSScope::ConstPtr> m_rootScopeImports;
+ QQmlJSImporter::ImportedTypes m_rootScopeImports;
QList<QQmlJSScope::ConstPtr> m_qmlTypes;
// We need to record the locations as IR locations because those contain less data.
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index aac85c8834..44c22c82e4 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -281,10 +281,9 @@ QQmlJSScope::findJSIdentifier(const QString &id) const
return std::optional<JavaScriptIdentifier>{};
}
-QQmlJSScope::ConstPtr
-QQmlJSScope::findType(const QString &name,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
+ const QString &name, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
{
auto type = contextualTypes.constFind(name);
@@ -299,42 +298,43 @@ QQmlJSScope::findType(const QString &name,
const QString outerTypeName = name.left(colonColon);
const auto outerType = contextualTypes.constFind(outerTypeName);
if (outerType != contextualTypes.constEnd()) {
- for (const auto &innerType : qAsConst((*outerType)->m_childScopes)) {
+ for (const auto &innerType : qAsConst(outerType->scope->m_childScopes)) {
if (innerType->m_internalName == name) {
if (usedTypes != nullptr)
usedTypes->insert(name);
- return innerType;
+ return { innerType, outerType->revision };
}
}
}
}
- return QQmlJSScope::ConstPtr();
+ return {};
}
-void QQmlJSScope::resolveType(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+QTypeRevision QQmlJSScope::resolveType(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
+ QSet<QString> *usedTypes)
{
- if (!self->m_baseType && !self->m_baseTypeName.isEmpty())
- self->m_baseType = findType(self->m_baseTypeName, contextualTypes, usedTypes);
+ const auto baseType = findType(self->m_baseTypeName, context, usedTypes);
+ if (!self->m_baseType.scope && !self->m_baseTypeName.isEmpty())
+ self->m_baseType = { baseType.scope, baseType.revision };
if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
- self->m_attachedType = findType(self->m_attachedTypeName, contextualTypes, usedTypes);
+ self->m_attachedType = findType(self->m_attachedTypeName, context, usedTypes).scope;
if (!self->m_valueType && !self->m_valueTypeName.isEmpty())
- self->m_valueType = findType(self->m_valueTypeName, contextualTypes, usedTypes);
+ self->m_valueType = findType(self->m_valueTypeName, context, usedTypes).scope;
if (!self->m_extensionType && !self->m_extensionTypeName.isEmpty())
- self->m_extensionType = findType(self->m_extensionTypeName, contextualTypes, usedTypes);
+ self->m_extensionType = findType(self->m_extensionTypeName, context, usedTypes).scope;
for (auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
const QString typeName = it->typeName();
if (it->type() || typeName.isEmpty())
continue;
- if (const auto type = findType(typeName, contextualTypes, usedTypes)) {
- it->setType(type);
+ if (const auto type = findType(typeName, context, usedTypes); type.scope) {
+ it->setType(type.scope);
continue;
}
@@ -345,8 +345,10 @@ void QQmlJSScope::resolveType(const QQmlJSScope::Ptr &self,
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())
- it->setReturnType(findType(returnTypeName, contextualTypes, usedTypes));
+ if (!it->returnType() && !returnTypeName.isEmpty()) {
+ const auto returnType = findType(returnTypeName, context, usedTypes);
+ it->setReturnType(returnType.scope);
+ }
const auto paramTypeNames = it->parameterTypeNames();
QList<QSharedPointer<const QQmlJSScope>> paramTypes = it->parameterTypes();
@@ -356,24 +358,28 @@ void QQmlJSScope::resolveType(const QQmlJSScope::Ptr &self,
for (int i = 0, length = paramTypes.length(); i < length; ++i) {
auto &paramType = paramTypes[i];
const auto paramTypeName = paramTypeNames[i];
- if (!paramType && !paramTypeName.isEmpty())
- paramType = findType(paramTypeName, contextualTypes, usedTypes);
+ if (!paramType && !paramTypeName.isEmpty()) {
+ const auto type = findType(paramTypeName, context, usedTypes);
+ paramType = type.scope;
+ }
}
it->setParameterTypes(paramTypes);
}
+
+ return baseType.revision;
}
-void QQmlJSScope::updateChildScope(const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+void QQmlJSScope::updateChildScope(
+ const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
switch (childScope->scopeType()) {
case QQmlJSScope::GroupedPropertyScope:
searchBaseAndExtensionTypes(self.data(), [&](const QQmlJSScope *type) {
const auto propertyIt = type->m_properties.find(childScope->internalName());
if (propertyIt != type->m_properties.end()) {
- childScope->m_baseType = QQmlJSScope::ConstPtr(propertyIt->type());
+ childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
childScope->m_baseTypeName = propertyIt->typeName();
return true;
}
@@ -381,9 +387,9 @@ void QQmlJSScope::updateChildScope(const QQmlJSScope::Ptr &childScope, const QQm
});
break;
case QQmlJSScope::AttachedPropertyScope:
- if (const auto attachedBase =
- findType(childScope->internalName(), contextualTypes, usedTypes)) {
- childScope->m_baseType = attachedBase->attachedType();
+ if (const auto attachedBase = findType(
+ childScope->internalName(), contextualTypes, usedTypes).scope) {
+ childScope->m_baseType.scope = attachedBase->attachedType();
childScope->m_baseTypeName = attachedBase->attachedTypeName();
}
break;
@@ -393,37 +399,37 @@ void QQmlJSScope::updateChildScope(const QQmlJSScope::Ptr &childScope, const QQm
}
template<typename Resolver, typename ChildScopeUpdater>
-static void resolveTypesInternal(Resolver resolve, ChildScopeUpdater update,
- const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+static QTypeRevision resolveTypesInternal(
+ Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
- resolve(self, contextualTypes, usedTypes);
+ const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
// NB: constness ensures no detach
- const QVector<QQmlJSScope::Ptr> childScopes = self->childScopes();
+ const auto childScopes = self->childScopes();
for (auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
- const QQmlJSScope::Ptr childScope = *it;
+ const auto childScope = *it;
update(childScope, self, contextualTypes, usedTypes);
resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes); // recursion
}
+ return revision;
}
-void QQmlJSScope::resolveTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+QTypeRevision QQmlJSScope::resolveTypes(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
{
const auto resolveAll = [](const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
+ const QQmlJSScope::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes) {
- resolveEnums(self, findType(u"int"_qs, contextualTypes, usedTypes));
- resolveType(self, contextualTypes, usedTypes);
+ resolveEnums(self, findType(u"int"_qs, contextualTypes, usedTypes).scope);
+ return resolveType(self, contextualTypes, usedTypes);
};
- resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
+ return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
}
-void QQmlJSScope::resolveNonEnumTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+void QQmlJSScope::resolveNonEnumTypes(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
{
resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
}
@@ -437,22 +443,22 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::
continue;
auto enumScope = QQmlJSScope::create(EnumScope, self);
enumScope->m_baseTypeName = QStringLiteral("int");
- enumScope->m_baseType = intType;
+ enumScope->m_baseType.scope = intType;
enumScope->m_semantics = AccessSemantics::Value;
enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
- it->setType(ConstPtr(enumScope));
+ it->setType(QQmlJSScope::ConstPtr(enumScope));
}
}
-void QQmlJSScope::resolveGeneralizedGroup(const Ptr &self, const ConstPtr &baseType,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+void QQmlJSScope::resolveGeneralizedGroup(
+ const Ptr &self, const ConstPtr &baseType,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
// Generalized group properties are always composite,
// which means we expect contextualTypes to be QML names.
Q_ASSERT(self->isComposite());
- self->m_baseType = baseType;
+ self->m_baseType.scope = baseType;
resolveNonEnumTypes(self, contextualTypes, usedTypes);
}
@@ -606,10 +612,10 @@ bool QQmlJSScope::isResolved() const
{
if (m_scopeType == ScopeType::AttachedPropertyScope
|| m_scopeType == ScopeType::GroupedPropertyScope) {
- return m_internalName.isEmpty() || !m_baseType.isNull();
+ return m_internalName.isEmpty() || !m_baseType.scope.isNull();
}
- return m_baseTypeName.isEmpty() || !m_baseType.isNull();
+ return m_baseTypeName.isEmpty() || !m_baseType.scope.isNull();
}
QString QQmlJSScope::defaultPropertyName() const
@@ -661,10 +667,12 @@ bool QQmlJSScope::Import::isValid() const
return !m_name.isEmpty();
}
-QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
- m_package(std::move(package)),
- m_type(std::move(type)),
- m_version(version)
+QQmlJSScope::Export::Export(
+ QString package, QString type, QTypeRevision version, QTypeRevision revision)
+ : m_package(std::move(package))
+ , m_type(std::move(type))
+ , m_version(std::move(version))
+ , m_revision(std::move(revision))
{
}
@@ -679,7 +687,7 @@ QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const
QQmlJSScope::Ptr result = typeReader();
m_importer->m_warnings.append(typeReader.errors());
result->setInternalName(internalName());
- QQmlJSScope::resolveEnums(result, m_importer->builtinInternalNames().value(u"int"_qs));
+ QQmlJSScope::resolveEnums(result, m_importer->builtinInternalNames().value(u"int"_qs).scope);
if (m_isSingleton)
result->setIsSingleton(true);
@@ -695,7 +703,8 @@ bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
bool isBaseComponent = causesImplicitComponentWrapping();
QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
- for (auto scope = derived; !scope.isNull() && !seen.hasSeen(scope); scope = scope->baseType()) {
+ for (auto scope = derived; !scope.isNull() && !seen.hasSeen(scope);
+ scope = scope->baseType()) {
if (isSameType(scope))
return true;
if (isBaseComponent && scope->internalName() == u"QObject"_qs)
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 7728407a0d..be278a6c7b 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -136,20 +136,36 @@ public:
class Export {
public:
Export() = default;
- Export(QString package, QString type, const QTypeRevision &version);
+ Export(QString package, QString type, QTypeRevision version, QTypeRevision revision);
bool isValid() const;
QString package() const { return m_package; }
QString type() const { return m_type; }
QTypeRevision version() const { return m_version; }
+ QTypeRevision revision() const { return m_revision; }
private:
QString m_package;
QString m_type;
QTypeRevision m_version;
+ QTypeRevision m_revision;
};
+ template<typename Pointer>
+ struct ExportedScope {
+ Pointer scope;
+ QList<QQmlJSScope::Export> exports;
+ };
+
+ template<typename Pointer>
+ struct ImportedScope {
+ Pointer scope;
+ QTypeRevision revision;
+ };
+
+ using ContextualTypes = QHash<QString, ImportedScope<ConstPtr>>;
+
struct JavaScriptIdentifier
{
enum Kind {
@@ -242,8 +258,9 @@ public:
// relevant base class (in the hierarchy starting from QObject) of a C++ type.
void setBaseTypeName(const QString &baseTypeName) { m_baseTypeName = baseTypeName; }
QString baseTypeName() const { return m_baseTypeName; }
- QQmlJSScope::ConstPtr baseType() const { return m_baseType; }
- void clearBaseType() { m_baseType = QQmlJSScope::WeakConstPtr(); }
+ QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; }
+ QTypeRevision baseTypeRevision() const { return m_baseType.revision; }
+ void clearBaseType() { m_baseType = {}; }
void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(prop.propertyName(), prop); }
QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; }
@@ -360,18 +377,18 @@ public:
return result;
}
- static void resolveTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes = nullptr);
- static void resolveNonEnumTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes = nullptr);
- static void resolveEnums(const QQmlJSScope::Ptr &self,
- const QQmlJSScope::ConstPtr &intType);
- static void resolveGeneralizedGroup(const QQmlJSScope::Ptr &self,
- const QQmlJSScope::ConstPtr &baseType,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes = nullptr);
+ static QTypeRevision resolveTypes(
+ const Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static void resolveNonEnumTypes(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static void resolveEnums(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType);
+ static void resolveGeneralizedGroup(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType,
+ const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
{
@@ -392,6 +409,16 @@ public:
return {};
}
+ static QTypeRevision 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.
@@ -435,15 +462,15 @@ public:
private:
QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr());
- static QQmlJSScope::ConstPtr
- findType(const QString &name, const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes = nullptr);
- static void resolveType(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes);
- static void updateChildScope(const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes);
+ static ImportedScope<QQmlJSScope::ConstPtr> findType(
+ const QString &name, const ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static QTypeRevision resolveType(
+ const QQmlJSScope::Ptr &self, const ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes);
+ static void updateChildScope(
+ const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes);
QHash<QString, JavaScriptIdentifier> m_jsIdentifiers;
@@ -459,7 +486,10 @@ private:
QString m_fileName;
QString m_internalName;
QString m_baseTypeName;
- QQmlJSScope::WeakConstPtr m_baseType;
+
+ // We only need the revision for the base type as inheritance is
+ // the only relation between two types where the revisions matter.
+ ImportedScope<QQmlJSScope::WeakConstPtr> m_baseType;
ScopeType m_scopeType = QMLScope;
QStringList m_interfaceNames;
@@ -518,10 +548,8 @@ private:
bool m_isSingleton = false;
};
-struct QQmlJSExportedScope {
- QQmlJSScope::Ptr scope;
- QList<QQmlJSScope::Export> exports;
-};
+using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
+using QQmlJSImportedScope = QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>;
struct QQmlJSTypeInfo
{
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
index 4dff082fbd..63a552e293 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp
+++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
@@ -193,6 +193,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
QQmlJSScope::Ptr scope = QQmlJSScope::create();
QList<QQmlJSScope::Export> exports;
+ UiScriptBinding *metaObjectRevisions = nullptr;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
auto *component = cast<UiObjectDefinition *>(member);
@@ -226,7 +227,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
} else if (name == QLatin1String("interfaces")) {
readInterfaces(script, scope);
} else if (name == QLatin1String("exportMetaObjectRevisions")) {
- checkMetaObjectRevisions(script, exports);
+ metaObjectRevisions = script;
} else if (name == QLatin1String("attachedType")) {
scope->setOwnAttachedTypeName(readStringBinding(script));
} else if (name == QLatin1String("valueType")) {
@@ -278,6 +279,8 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
return;
}
+ if (metaObjectRevisions)
+ checkMetaObjectRevisions(metaObjectRevisions, &exports);
m_objects->insert(scope->internalName(), {scope, exports});
}
@@ -655,7 +658,7 @@ QList<QQmlJSScope::Export> QQmlJSTypeDescriptionReader::readExports(UiScriptBind
QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
// ### relocatable exports where package is empty?
- exports.append(QQmlJSScope::Export(package, name, version));
+ exports.append(QQmlJSScope::Export(package, name, version, version));
}
return exports;
@@ -685,7 +688,7 @@ void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast, const QQm
}
void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
- UiScriptBinding *ast, const QList<QQmlJSScope::Export> &exports)
+ UiScriptBinding *ast, QList<QQmlJSScope::Export> *exports)
{
Q_ASSERT(ast);
@@ -708,7 +711,7 @@ void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
}
int exportIndex = 0;
- const int exportCount = exports.size();
+ const int exportCount = exports->size();
for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
if (!numberLit) {
@@ -732,14 +735,17 @@ void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
const QTypeRevision metaObjectVersion
= QTypeRevision::fromEncodedVersion(metaObjectRevision);
- const QTypeRevision exportVersion = exports[exportIndex].version();
+ const QQmlJSScope::Export &entry = exports->at(exportIndex);
+ const QTypeRevision exportVersion = entry.version();
if (metaObjectVersion != exportVersion) {
addWarning(numberLit->firstSourceLocation(),
- tr("Meta object revision and export version differ, ignoring the revision.\n"
+ tr("Meta object revision and export version differ.\n"
"Revision %1 corresponds to version %2.%3; it should be %4.%5.")
.arg(metaObjectRevision)
.arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
.arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
+ (*exports)[exportIndex] = QQmlJSScope::Export(entry.package(), entry.type(),
+ exportVersion, metaObjectVersion);
}
}
}
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader_p.h b/src/qmlcompiler/qqmljstypedescriptionreader_p.h
index f3c4ec9a93..647271c2e6 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader_p.h
+++ b/src/qmlcompiler/qqmljstypedescriptionreader_p.h
@@ -80,7 +80,7 @@ private:
QList<QQmlJSScope::Export> readExports(QQmlJS::AST::UiScriptBinding *ast);
void readInterfaces(QQmlJS::AST::UiScriptBinding *ast, const QQmlJSScope::Ptr &scope);
void checkMetaObjectRevisions(
- QQmlJS::AST::UiScriptBinding *ast, const QList<QQmlJSScope::Export> &exports);
+ QQmlJS::AST::UiScriptBinding *ast, QList<QQmlJSScope::Export> *exports);
QStringList readStringList(QQmlJS::AST::UiScriptBinding *ast);
void readDeferredNames(QQmlJS::AST::UiScriptBinding *ast, const QQmlJSScope::Ptr &scope);
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index bcdea1d785..f4ddc2d8e0 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -883,14 +883,17 @@ void QQmlJSTypePropagator::generate_CallPossiblyDirectEval(int argc, int argv)
void QQmlJSTypePropagator::propagateScopeLookupCall(const QString &functionName, int argc, int argv)
{
- if (QQmlJSScope::ConstPtr scope = QQmlJSScope::findCurrentQMLScope(m_function->qmlScope)) {
- const auto methods = scope->methods(functionName);
+ const QQmlJSRegisterContent resolvedContent
+ = m_typeResolver->scopedType(m_function->qmlScope, functionName);
+ if (resolvedContent.isMethod()) {
+ const auto methods = resolvedContent.method();
if (!methods.isEmpty()) {
propagateCall(methods, argc, argv);
return;
}
}
+ setError(u"method %1 cannot be resolved."_qs.arg(functionName));
m_state.accumulatorOut = m_typeResolver->globalType(m_typeResolver->jsValueType());
setError(u"Cannot find function '%1'"_qs.arg(functionName));
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 22254c3477..f872526d6b 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -65,18 +65,18 @@ static bool searchBaseAndExtensionTypes(const QQmlJSScope::ConstPtr type, const
QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
{
- const QHash<QString, QQmlJSScope::ConstPtr> builtinTypes = importer->builtinInternalNames();
- m_voidType = builtinTypes[u"void"_qs];
- m_realType = builtinTypes[u"double"_qs];
- m_floatType = builtinTypes[u"float"_qs];
- m_intType = builtinTypes[u"int"_qs];
- m_boolType = builtinTypes[u"bool"_qs];
- m_stringType = builtinTypes[u"QString"_qs];
- m_urlType = builtinTypes[u"QUrl"_qs];
- m_dateTimeType = builtinTypes[u"QDateTime"_qs];
- m_variantListType = builtinTypes[u"QVariantList"_qs];
- m_varType = builtinTypes[u"QVariant"_qs];
- m_jsValueType = builtinTypes[u"QJSValue"_qs];
+ const QQmlJSImporter::ImportedTypes builtinTypes = importer->builtinInternalNames();
+ m_voidType = builtinTypes[u"void"_qs].scope;
+ m_realType = builtinTypes[u"double"_qs].scope;
+ m_floatType = builtinTypes[u"float"_qs].scope;
+ m_intType = builtinTypes[u"int"_qs].scope;
+ m_boolType = builtinTypes[u"bool"_qs].scope;
+ m_stringType = builtinTypes[u"QString"_qs].scope;
+ m_urlType = builtinTypes[u"QUrl"_qs].scope;
+ m_dateTimeType = builtinTypes[u"QDateTime"_qs].scope;
+ m_variantListType = builtinTypes[u"QVariantList"_qs].scope;
+ m_varType = builtinTypes[u"QVariant"_qs].scope;
+ m_jsValueType = builtinTypes[u"QJSValue"_qs].scope;
QQmlJSScope::Ptr jsPrimitiveType = QQmlJSScope::create();
jsPrimitiveType->setInternalName(u"QJSPrimitiveValue"_qs);
@@ -171,7 +171,7 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::scopeForId(
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeFromAST(QQmlJS::AST::Type *type) const
{
- return m_imports[QmlIR::IRBuilder::asString(type->typeId)];
+ return m_imports[QmlIR::IRBuilder::asString(type->typeId)].scope;
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeForConst(QV4::ReturnedValue rv) const
@@ -581,6 +581,23 @@ static bool isAssignedToDefaultProperty(const QQmlJSScope::ConstPtr &parent,
return false;
}
+static bool isRevisionAllowed(int memberRevision, const QQmlJSScope::ConstPtr &scope)
+{
+ Q_ASSERT(scope->isComposite());
+ const QTypeRevision revision = QTypeRevision::fromEncodedVersion(memberRevision);
+
+ // If the memberRevision is either invalid or 0.0, then everything is allowed.
+ if (!revision.isValid() || revision == QTypeRevision::zero())
+ return true;
+
+ const QTypeRevision typeRevision = QQmlJSScope::nonCompositeBaseRevision(
+ {scope->baseType(), scope->baseTypeRevision()});
+
+ // If the revision is not valid, we haven't found a non-composite base type.
+ // There is nothing we can say about the property then.
+ return typeRevision.isValid() && typeRevision >= revision;
+}
+
QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr &scope,
const QString &name) const
{
@@ -595,6 +612,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
base, [&](const QQmlJSScope::ConstPtr &found, BaseOrExtension mode) {
if (found->hasOwnProperty(name)) {
QQmlJSMetaProperty prop = found->ownProperty(name);
+ if (!isRevisionAllowed(prop.revision(), scope))
+ return false;
if (m_parentMode == UseDocumentParent
&& name == base->parentPropertyName()) {
QQmlJSScope::ConstPtr baseParent = base->parentScope();
@@ -609,8 +628,16 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
return true;
}
- if (scope->hasOwnMethod(name)) {
- const auto methods = scope->ownMethods(name);
+ if (found->hasOwnMethod(name)) {
+ auto methods = found->ownMethods(name);
+ for (auto it = methods.begin(); it != methods.end();) {
+ if (!isRevisionAllowed(it->revision(), scope))
+ it = methods.erase(it);
+ else
+ ++it;
+ }
+ if (methods.isEmpty())
+ return false;
result = QQmlJSRegisterContent::create(
jsValueType(), methods, scopeContentVariant(mode, true), scope);
return true;
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index a59ffd6e37..96f19a8b33 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -41,6 +41,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmljsimporter_p.h>
#include <private/qqmljslogger_p.h>
#include <private/qqmljsregistercontent_p.h>
#include <private/qqmljsscope_p.h>
@@ -89,10 +90,10 @@ public:
bool isPrefix(const QString &name) const
{
- return m_imports.contains(name) && !m_imports[name];
+ return m_imports.contains(name) && !m_imports[name].scope;
}
- QQmlJSScope::ConstPtr typeForName(const QString &name) const { return m_imports[name]; }
+ QQmlJSScope::ConstPtr typeForName(const QString &name) const { return m_imports[name].scope; }
QQmlJSScope::ConstPtr typeFromAST(QQmlJS::AST::Type *type) const;
QQmlJSScope::ConstPtr typeForConst(QV4::ReturnedValue rv) const;
QQmlJSRegisterContent typeForBinaryOperation(QSOperator::Op oper,
@@ -171,7 +172,7 @@ protected:
QQmlJSScopesById m_objectsById;
QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> m_objectsByLocation;
- QHash<QString, QQmlJSScope::ConstPtr> m_imports;
+ QQmlJSImporter::ImportedTypes m_imports;
QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
ParentMode m_parentMode = UseParentProperty;