aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-03-31 11:26:09 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-04-04 18:51:23 +0200
commitca82086b0c4b12944b87c307011a870b34857076 (patch)
tree00ac7b2175bf2e2c2d5be3c04594d9c7511155bf
parent5f95610039f7077343815e2e0a6837b89ccfe9cd (diff)
Avoid copying QQmlJSScope
The factory should populate the pre-existing scope rather than copy it into place. This way we can detect inheritance cycles involving the pre-existing scope. However, now we may detect the inheritance cycles earlier, when resolving the types inside the lazy loading. We have the right pointers available there now, after all. Therefore, add a way to propagate base type errors out of the factory. When clearing the base type, we can now give a reason for that. When checking the inheritance cycles we retrieve that reason and log it. We also remove the special casing of the ScopeType property of QQmlJSScope. There is no real reason to set it in the ctor. As we delay the population of QQmlJSScope now, we have to set it later. Task-number: QTBUG-102153 Change-Id: I49cf6e20f59fbdb6ed98a82040b3b159676f5975 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit aea732d607dbcc7ba2c86244ca1ab9086bb28ca6)
-rw-r--r--src/qmlcompiler/qdeferredpointer_p.h23
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp91
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h16
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp69
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h27
-rw-r--r--src/qmlcompiler/qqmljstypereader.cpp27
-rw-r--r--src/qmlcompiler/qqmljstypereader_p.h2
-rw-r--r--tests/auto/qml/qmllint/data/cycleHead.qml3
-rw-r--r--tools/qmllint/findwarnings.cpp2
9 files changed, 165 insertions, 95 deletions
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index 25dd953e0f..125c24c3d0 100644
--- a/src/qmlcompiler/qdeferredpointer_p.h
+++ b/src/qmlcompiler/qdeferredpointer_p.h
@@ -45,15 +45,24 @@
QT_BEGIN_NAMESPACE
template<typename T>
+class QDeferredSharedPointer;
+
+template<typename T>
+class QDeferredWeakPointer;
+
+template<typename T>
class QDeferredFactory
{
public:
- T create() const;
bool isValid() const;
-};
-template<typename T>
-class QDeferredWeakPointer;
+private:
+ friend class QDeferredSharedPointer<const T>;
+ friend class QDeferredWeakPointer<const T>;
+ friend class QDeferredSharedPointer<T>;
+ friend class QDeferredWeakPointer<T>;
+ void populate(const QSharedPointer<T> &) const;
+};
template<typename T>
class QDeferredSharedPointer
@@ -149,7 +158,7 @@ private:
if (m_factory && m_factory->isValid()) {
Factory localFactory;
std::swap(localFactory, *m_factory); // Swap before executing, to avoid recursion
- const_cast<std::remove_const_t<T> &>(*m_data) = localFactory.create();
+ localFactory.populate(m_data.template constCast<std::remove_const_t<T>>());
}
}
@@ -229,8 +238,8 @@ private:
if (factory->isValid()) {
Factory localFactory;
std::swap(localFactory, *factory); // Swap before executing, to avoid recursion
- const_cast<std::remove_const_t<T> &>(*(m_data.toStrongRef()))
- = localFactory.create();
+ localFactory.populate(
+ m_data.toStrongRef().template constCast<std::remove_const_t<T>>());
}
}
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 413bc67806..22c744125d 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -69,19 +69,21 @@ inline QString getScopeName(const QQmlJSScope::ConstPtr &scope, QQmlJSScope::Sco
return scope->baseTypeName();
}
-QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer,
- const QString &implicitImportDirectory,
- const QStringList &qmltypesFiles, const QString &fileName,
- const QString &code, bool silent)
+QQmlJSImportVisitor::QQmlJSImportVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer,
+ const QString &implicitImportDirectory, const QStringList &qmltypesFiles,
+ const QString &fileName, const QString &code, bool silent)
: m_implicitImportDirectory(implicitImportDirectory),
m_code(code),
m_filePath(fileName),
m_rootId(u"<id>"_qs),
m_qmltypesFiles(qmltypesFiles),
- m_currentScope(QQmlJSScope::create(QQmlJSScope::JSFunctionScope)),
+ m_currentScope(QQmlJSScope::create()),
+ m_exportedRootScope(target),
m_importer(importer),
m_logger(fileName, code, silent)
{
+ m_currentScope->setScopeType(QQmlJSScope::JSFunctionScope);
m_globalScope = m_currentScope;
m_currentScope->setIsComposite(true);
@@ -111,16 +113,32 @@ QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer,
m_currentScope->insertJSIdentifier(jsGlobVar, globalJavaScript);
}
-void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
- const QQmlJS::SourceLocation &location)
+void QQmlJSImportVisitor::populateCurrentScope(
+ QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
{
- m_currentScope = QQmlJSScope::create(type, m_currentScope);
+ m_currentScope->setScopeType(type);
setScopeName(m_currentScope, type, name);
m_currentScope->setIsComposite(true);
m_currentScope->setSourceLocation(location);
m_scopesByIrLocation.insert({ location.startLine, location.startColumn }, m_currentScope);
}
+void QQmlJSImportVisitor::enterRootScope(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
+{
+ QQmlJSScope::reparent(m_currentScope, m_exportedRootScope);
+ m_currentScope = m_exportedRootScope;
+ populateCurrentScope(type, name, location);
+}
+
+void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location)
+{
+ QQmlJSScope::Ptr newScope = QQmlJSScope::create();
+ QQmlJSScope::reparent(m_currentScope, newScope);
+ m_currentScope = std::move(newScope);
+ populateCurrentScope(type, name, location);
+}
+
bool QQmlJSImportVisitor::enterEnvironmentNonUnique(QQmlJSScope::ScopeType type,
const QString &name,
const QQmlJS::SourceLocation &location)
@@ -240,11 +258,6 @@ void QQmlJSImportVisitor::resolveAliases()
}
}
-QQmlJSScope::Ptr QQmlJSImportVisitor::result() const
-{
- return m_exportedRootScope;
-}
-
QString QQmlJSImportVisitor::implicitImportDirectory(
const QString &localFile, QQmlJSResourceFileMapper *mapper)
{
@@ -811,26 +824,31 @@ void QQmlJSImportVisitor::breakInheritanceCycles(const QQmlJSScope::Ptr &origina
if (scopes.contains(scope)) {
QString inheritenceCycle;
for (const auto &seen : qAsConst(scopes)) {
- if (!inheritenceCycle.isEmpty())
- inheritenceCycle.append(QLatin1String(" -> "));
inheritenceCycle.append(seen->baseTypeName());
+ inheritenceCycle.append(QLatin1String(" -> "));
}
+ inheritenceCycle.append(scopes.first()->baseTypeName());
- m_logger.log(QStringLiteral("%1 is part of an inheritance cycle: %2")
- .arg(scope->internalName())
- .arg(inheritenceCycle),
- Log_InheritanceCycle);
+ const QString message = QStringLiteral("%1 is part of an inheritance cycle: %2")
+ .arg(scope->internalName(), inheritenceCycle);
+ m_logger.log(message, Log_InheritanceCycle);
originalScope->clearBaseType();
+ originalScope->setBaseTypeError(message);
break;
}
scopes.append(scope);
const auto newScope = scope->baseType();
- if (newScope.isNull() && !scope->baseTypeName().isEmpty()) {
- m_logger.log(scope->baseTypeName()
- + QStringLiteral(" was not found. Did you add all import paths?"),
- Log_Import);
+ if (newScope.isNull()) {
+ const QString error = scope->baseTypeError();
+ const QString name = scope->baseTypeName();
+ if (!error.isEmpty()) {
+ m_logger.log(error, Log_Import);
+ } else if (!name.isEmpty()) {
+ m_logger.log(name + QStringLiteral(" was not found. Did you add all import paths?"),
+ Log_Import);
+ }
}
scope = newScope;
@@ -939,9 +957,10 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
Q_ASSERT(!superType.isEmpty());
if (superType.front().isUpper()) {
- enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
- if (!m_exportedRootScope)
- m_exportedRootScope = m_currentScope;
+ if (rootScopeIsValid())
+ enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
+ else
+ enterRootScope(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
const QTypeRevision revision = QQmlJSScope::resolveTypes(
m_currentScope, m_rootScopeImports, &m_usedTypes);
@@ -954,7 +973,7 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
} else {
enterEnvironmentNonUnique(QQmlJSScope::GroupedPropertyScope, superType,
definition->firstSourceLocation());
- Q_ASSERT(m_exportedRootScope);
+ Q_ASSERT(rootScopeIsValid());
QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
}
@@ -1615,7 +1634,7 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
bool QQmlJSImportVisitor::visit(ExportDeclaration *)
{
- Q_ASSERT(!m_exportedRootScope.isNull());
+ Q_ASSERT(rootScopeIsValid());
Q_ASSERT(m_exportedRootScope != m_globalScope);
Q_ASSERT(m_currentScope == m_globalScope);
m_currentScope = m_exportedRootScope;
@@ -1624,18 +1643,17 @@ bool QQmlJSImportVisitor::visit(ExportDeclaration *)
void QQmlJSImportVisitor::endVisit(ExportDeclaration *)
{
- Q_ASSERT(!m_exportedRootScope.isNull());
+ Q_ASSERT(rootScopeIsValid());
m_currentScope = m_exportedRootScope->parentScope();
Q_ASSERT(m_currentScope == m_globalScope);
}
bool QQmlJSImportVisitor::visit(ESModule *module)
{
- enterEnvironment(QQmlJSScope::JSLexicalScope, QStringLiteral("module"),
- module->firstSourceLocation());
- Q_ASSERT(m_exportedRootScope.isNull());
- m_exportedRootScope = m_currentScope;
- m_exportedRootScope->setIsScript(true);
+ Q_ASSERT(!rootScopeIsValid());
+ enterRootScope(
+ QQmlJSScope::JSLexicalScope, QStringLiteral("module"), module->firstSourceLocation());
+ m_currentScope->setIsScript(true);
importBaseModules();
leaveEnvironment();
return true;
@@ -1649,9 +1667,10 @@ void QQmlJSImportVisitor::endVisit(ESModule *)
bool QQmlJSImportVisitor::visit(Program *)
{
Q_ASSERT(m_globalScope == m_currentScope);
- Q_ASSERT(m_exportedRootScope.isNull());
- m_exportedRootScope = m_currentScope;
+ Q_ASSERT(!rootScopeIsValid());
+ *m_exportedRootScope = std::move(*QQmlJSScope::clone(m_currentScope));
m_exportedRootScope->setIsScript(true);
+ m_currentScope = m_exportedRootScope;
importBaseModules();
return true;
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 981ce7fc7e..a3e7e5e34d 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -55,10 +55,13 @@ struct QQmlJSResourceFileMapper;
class QQmlJSImportVisitor : public QQmlJS::AST::Visitor
{
public:
- QQmlJSImportVisitor(QQmlJSImporter *importer, const QString &implicitImportDirectory,
- const QStringList &qmltypesFiles = QStringList(), const QString &fileName = QString(), const QString &code = QString(), bool silent = true);
+ QQmlJSImportVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer,
+ const QString &implicitImportDirectory,
+ const QStringList &qmltypesFiles = QStringList(), const QString &fileName = QString(),
+ const QString &code = QString(), bool silent = true);
- QQmlJSScope::Ptr result() const;
+ QQmlJSScope::Ptr result() const { return m_exportedRootScope; }
// TODO: Should be superseded by accessing the logger instead
QList<QQmlJS::DiagnosticMessage> errors() const { return m_logger.warnings() + m_logger.errors(); }
@@ -144,7 +147,7 @@ protected:
QStringList m_qmltypesFiles;
QQmlJSScope::Ptr m_currentScope;
QQmlJSScope::Ptr m_savedBindingOuterScope;
- QQmlJSScope::Ptr m_exportedRootScope;
+ const QQmlJSScope::Ptr m_exportedRootScope;
QQmlJSScope::ConstPtr m_globalScope;
QQmlJSScopesById m_scopesById;
QQmlJSImporter::ImportedTypes m_rootScopeImports;
@@ -185,6 +188,7 @@ protected:
void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
+ bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
QQmlJSLogger m_logger;
@@ -265,6 +269,10 @@ private:
const QString &what,
const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc);
+ void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location);
+ void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location);
};
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 8311ccb57d..c817cd61be 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -93,15 +93,24 @@ static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check
return false;
}
-QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
- : m_parentScope(parentScope), m_scopeType(type) {}
-
-QQmlJSScope::Ptr QQmlJSScope::create(ScopeType type, const QQmlJSScope::Ptr &parentScope)
+void QQmlJSScope::reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
{
- QSharedPointer<QQmlJSScope> childScope(new QQmlJSScope{type, parentScope});
+ if (const QQmlJSScope::Ptr parent = childScope->m_parentScope.toStrongRef())
+ parent->m_childScopes.removeOne(childScope);
if (parentScope)
- parentScope->m_childScopes.push_back(childScope);
- return childScope;
+ parentScope->m_childScopes.append(childScope);
+ childScope->m_parentScope = parentScope;
+}
+
+QQmlJSScope::Ptr QQmlJSScope::clone(const ConstPtr &origin)
+{
+ if (origin.isNull())
+ return QQmlJSScope::Ptr();
+ QQmlJSScope::Ptr cloned = create();
+ *cloned = *origin;
+ if (QQmlJSScope::Ptr parent = cloned->parentScope())
+ parent->m_childScopes.append(cloned);
+ return cloned;
}
void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
@@ -300,8 +309,9 @@ QTypeRevision QQmlJSScope::resolveType(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
QSet<QString> *usedTypes)
{
- const auto baseType = findType(self->m_baseTypeName, context, usedTypes);
- if (!self->m_baseType.scope && !self->m_baseTypeName.isEmpty())
+ const QString baseTypeName = self->baseTypeName();
+ const auto baseType = findType(baseTypeName, context, usedTypes);
+ if (!self->m_baseType.scope && !baseTypeName.isEmpty())
self->m_baseType = { baseType.scope, baseType.revision };
if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
@@ -365,7 +375,7 @@ void QQmlJSScope::updateChildScope(
const auto propertyIt = type->m_properties.find(childScope->internalName());
if (propertyIt != type->m_properties.end()) {
childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
- childScope->m_baseTypeName = propertyIt->typeName();
+ childScope->setBaseTypeName(propertyIt->typeName());
return true;
}
return false;
@@ -375,7 +385,7 @@ void QQmlJSScope::updateChildScope(
if (const auto attachedBase = findType(
childScope->internalName(), contextualTypes, usedTypes).scope) {
childScope->m_baseType.scope = attachedBase->attachedType();
- childScope->m_baseTypeName = attachedBase->attachedTypeName();
+ childScope->setBaseTypeName(attachedBase->attachedTypeName());
}
break;
default:
@@ -426,8 +436,10 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::
++it) {
if (it->type())
continue;
- auto enumScope = QQmlJSScope::create(EnumScope, self);
- enumScope->m_baseTypeName = QStringLiteral("int");
+ QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
+ reparent(self, enumScope);
+ enumScope->m_scopeType = EnumScope;
+ enumScope->setBaseTypeName(QStringLiteral("int"));
enumScope->m_baseType.scope = intType;
enumScope->m_semantics = AccessSemantics::Value;
enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
@@ -539,6 +551,28 @@ bool QQmlJSScope::hasInterface(const QString &name) const
this, [&](const QQmlJSScope *scope) { return scope->m_interfaceNames.contains(name); });
}
+void QQmlJSScope::setBaseTypeName(const QString &baseTypeName)
+{
+ m_flags.setFlag(HasBaseTypeError, false);
+ m_baseTypeNameOrError = baseTypeName;
+}
+
+QString QQmlJSScope::baseTypeName() const
+{
+ return m_flags.testFlag(HasBaseTypeError) ? QString() : m_baseTypeNameOrError;
+}
+
+void QQmlJSScope::setBaseTypeError(const QString &baseTypeError)
+{
+ m_flags.setFlag(HasBaseTypeError);
+ m_baseTypeNameOrError = baseTypeError;
+}
+
+QString QQmlJSScope::baseTypeError() const
+{
+ return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
+}
+
QString QQmlJSScope::attachedTypeName() const
{
QString name;
@@ -572,7 +606,7 @@ bool QQmlJSScope::isResolved() const
return m_internalName.isEmpty() || !m_baseType.scope.isNull();
}
- return m_baseTypeName.isEmpty() || !m_baseType.scope.isNull();
+ return m_baseTypeNameOrError.isEmpty() || !m_baseType.scope.isNull();
}
bool QQmlJSScope::isFullyResolved() const
@@ -603,13 +637,12 @@ bool QQmlJSScope::Export::isValid() const
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
-QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const
+void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
QQmlJSTypeReader typeReader(m_importer, m_filePath);
- QQmlJSScope::Ptr result = typeReader();
+ typeReader(scope);
m_importer->m_warnings.append(typeReader.errors());
- result->setInternalName(QFileInfo(m_filePath).baseName());
- return std::move(*result);
+ scope->setInternalName(QFileInfo(m_filePath).baseName());
}
bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index a0d3fed84c..e0d75dd2dc 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -67,7 +67,7 @@ public:
m_filePath(filePath), m_importer(importer)
{}
- QQmlJSScope create() const;
+ void populate(const QSharedPointer<QQmlJSScope> &scope) const;
bool isValid() const
{
@@ -81,7 +81,6 @@ private:
class QQmlJSScope
{
- Q_DISABLE_COPY(QQmlJSScope)
public:
QQmlJSScope(QQmlJSScope &&) = default;
QQmlJSScope &operator=(QQmlJSScope &&) = default;
@@ -116,7 +115,8 @@ public:
CustomParser = 0x10,
Array = 0x20,
InlineComponent = 0x40,
- WrappedInImplicitComponent = 0x80
+ WrappedInImplicitComponent = 0x80,
+ HasBaseTypeError = 0x100
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAGS(Flags);
@@ -167,8 +167,8 @@ public:
QQmlJS::SourceLocation location;
};
- static QQmlJSScope::Ptr create(ScopeType type = QQmlJSScope::QMLScope,
- const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr());
+ static QQmlJSScope::Ptr create() { return QSharedPointer<QQmlJSScope>(new QQmlJSScope); }
+ static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin);
static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope);
QQmlJSScope::Ptr parentScope()
@@ -181,6 +181,8 @@ public:
return QQmlJSScope::WeakConstPtr(m_parentScope).toStrongRef();
}
+ static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope);
+
void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier);
// inserts property as qml identifier as well as the corresponding
@@ -189,6 +191,7 @@ public:
bool isIdInCurrentScope(const QString &id) const;
ScopeType scopeType() const { return m_scopeType; }
+ void setScopeType(ScopeType type) { m_scopeType = type; }
void addOwnMethod(const QQmlJSMetaMethod &method) { m_methods.insert(method.methodName(), method); }
QMultiHash<QString, QQmlJSMetaMethod> ownMethods() const { return m_methods; }
@@ -234,11 +237,15 @@ public:
// If isComposite(), this is the QML/JS name of the prototype. Otherwise it's the
// 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; }
+ void setBaseTypeName(const QString &baseTypeName);
+ QString baseTypeName() const;
+
QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; }
QTypeRevision baseTypeRevision() const { return m_baseType.revision; }
+
void clearBaseType() { m_baseType = {}; }
+ void setBaseTypeError(const QString &baseTypeError);
+ QString baseTypeError() const;
void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(prop.propertyName(), prop); }
QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; }
@@ -423,7 +430,9 @@ public:
bool isInCustomParserParent() const;
private:
- QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr());
+ QQmlJSScope() = default;
+ QQmlJSScope(const QQmlJSScope &) = default;
+ QQmlJSScope &operator=(const QQmlJSScope &) = default;
static ImportedScope<QQmlJSScope::ConstPtr> findType(
const QString &name, const ContextualTypes &contextualTypes,
@@ -448,7 +457,7 @@ private:
QString m_fileName;
QString m_internalName;
- QString m_baseTypeName;
+ QString m_baseTypeNameOrError;
// We only need the revision for the base type as inheritance is
// the only relation between two types where the revisions matter.
diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp
index c91b9f6c66..d7e6999bcd 100644
--- a/src/qmlcompiler/qqmljstypereader.cpp
+++ b/src/qmlcompiler/qqmljstypereader.cpp
@@ -40,13 +40,13 @@
QT_BEGIN_NAMESPACE
-QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
+bool QQmlJSTypeReader::operator ()(const QSharedPointer<QQmlJSScope> &scope)
{
using namespace QQmlJS::AST;
const QFileInfo info { m_file };
- QString baseName = info.baseName();
- const QString scopeName = baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
- : baseName;
+ const QString baseName = info.baseName();
+ scope->setInternalName(baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName);
QQmlJS::Engine engine;
QQmlJS::Lexer lexer(&engine);
@@ -55,16 +55,10 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
const bool isESModule = lowerSuffix == QLatin1String("mjs");
const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
- auto errorResult = [&](){
- QQmlJSScope::Ptr result = QQmlJSScope::create(
- isJavaScript ? QQmlJSScope::JSLexicalScope : QQmlJSScope::QMLScope);
- result->setInternalName(scopeName);
- return result;
- };
QFile file(m_file);
if (!file.open(QFile::ReadOnly))
- return errorResult();
+ return false;
QString code = QString::fromUtf8(file.readAll());
file.close();
@@ -76,22 +70,19 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
: parser.parseProgram())
: parser.parse();
if (!success)
- return errorResult();
+ return false;
QQmlJS::AST::Node *rootNode = parser.rootNode();
if (!rootNode)
- return errorResult();
+ return false;
QQmlJSImportVisitor membersVisitor(
- m_importer,
+ scope, m_importer,
QQmlJSImportVisitor::implicitImportDirectory(
m_file, m_importer->resourceFileMapper()),
m_qmltypesFiles, m_file, code);
rootNode->accept(&membersVisitor);
- auto result = membersVisitor.result();
- Q_ASSERT(result);
- result->setInternalName(scopeName);
- return result;
+ return true;
}
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljstypereader_p.h b/src/qmlcompiler/qqmljstypereader_p.h
index 08c4ff782b..8094f0d9b1 100644
--- a/src/qmlcompiler/qqmljstypereader_p.h
+++ b/src/qmlcompiler/qqmljstypereader_p.h
@@ -61,7 +61,7 @@ public:
, m_qmltypesFiles(qmltypesFiles)
{}
- QQmlJSScope::Ptr operator()();
+ bool operator()(const QSharedPointer<QQmlJSScope> &scope);
QList<QQmlJS::DiagnosticMessage> errors() const { return m_errors; }
private:
diff --git a/tests/auto/qml/qmllint/data/cycleHead.qml b/tests/auto/qml/qmllint/data/cycleHead.qml
index 3cc5e9acdf..080eab381f 100644
--- a/tests/auto/qml/qmllint/data/cycleHead.qml
+++ b/tests/auto/qml/qmllint/data/cycleHead.qml
@@ -2,5 +2,6 @@ import Cycle
import QtQuick
Item {
- MenuItem {}
+ property MenuItem item: a
+ MenuItem { id: a }
}
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 41d4c1809e..d4b5e39383 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -156,7 +156,7 @@ bool FindWarningVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
FindWarningVisitor::FindWarningVisitor(QQmlJSImporter *importer, QStringList qmltypesFiles,
QString code, QList<QQmlJS::SourceLocation> comments,
QString fileName, bool silent)
- : QQmlJSImportVisitor(importer,
+ : QQmlJSImportVisitor(QQmlJSScope::create(), importer,
implicitImportDirectory(fileName, importer->resourceFileMapper()),
qmltypesFiles, fileName, code, silent)
{