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-05 21:57:19 +0200
commit9c91b35c076b5c7d16fe7499bbe490291d1a6bcf (patch)
treef721f95127677d4d76431d9e12aafb41934bbca6
parent3414e8ab16a42c8fd9e7c640a1e4787e4b3cb49c (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/qqmljscompiler.cpp3
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp93
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h12
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp74
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h35
-rw-r--r--src/qmlcompiler/qqmljstypereader.cpp27
-rw-r--r--src/qmlcompiler/qqmljstypereader_p.h2
-rw-r--r--src/qmllint/findwarnings.cpp8
-rw-r--r--src/qmllint/findwarnings_p.h5
-rw-r--r--src/qmllint/qqmllinter.cpp1
-rw-r--r--tests/auto/qml/qmllint/data/cycleHead.qml3
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp4
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp3
-rw-r--r--tools/qmltc/main.cpp3
-rw-r--r--tools/qmltc/prototype/visitor.cpp4
-rw-r--r--tools/qmltc/prototype/visitor.h3
-rw-r--r--tools/qmltc/qmltcvisitor.cpp3
18 files changed, 193 insertions, 113 deletions
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index 9bf67fb27f..674fb93204 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
@@ -157,7 +166,7 @@ private:
if (Factory *f = factory()) {
Factory localFactory;
std::swap(localFactory, *f); // 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/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index f9448f38ac..b0f3fd8f72 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -644,7 +644,8 @@ void QQmlJSAotCompiler::setDocument(
m_logger->setCode(irDocument->code);
m_unitGenerator = &irDocument->jsGenerator;
m_entireSourceCodeLines = irDocument->code.split(u'\n');
- QQmlJSImportVisitor visitor(m_importer, m_logger,
+ QQmlJSScope::Ptr target = QQmlJSScope::create();
+ QQmlJSImportVisitor visitor(target, m_importer, m_logger,
resourcePathInfo.canonicalPath() + u'/',
m_qmldirFiles);
m_typeResolver.init(&visitor, irDocument->program);
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index eae2d7c202..bcc948e0cd 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -74,15 +74,17 @@ inline QString getScopeName(const QQmlJSScope::ConstPtr &scope, QQmlJSScope::Sco
return scope->baseTypeName();
}
-QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
- const QString &implicitImportDirectory,
- const QStringList &qmldirFiles)
+QQmlJSImportVisitor::QQmlJSImportVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
+ const QString &implicitImportDirectory, const QStringList &qmldirFiles)
: m_implicitImportDirectory(implicitImportDirectory),
m_qmldirFiles(qmldirFiles),
- m_currentScope(QQmlJSScope::create(QQmlJSScope::JSFunctionScope)),
+ m_currentScope(QQmlJSScope::create()),
+ m_exportedRootScope(target),
m_importer(importer),
m_logger(logger)
{
+ m_currentScope->setScopeType(QQmlJSScope::JSFunctionScope);
Q_ASSERT(logger); // must be valid
m_globalScope = m_currentScope;
@@ -118,16 +120,32 @@ QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer, QQmlJSLogger
QQmlJSImportVisitor::~QQmlJSImportVisitor() = default;
-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)
@@ -278,11 +296,6 @@ void QQmlJSImportVisitor::resolveAliasesAndIds()
}
}
-QQmlJSScope::Ptr QQmlJSImportVisitor::result() const
-{
- return m_exportedRootScope;
-}
-
QString QQmlJSImportVisitor::implicitImportDirectory(
const QString &localFile, QQmlJSResourceFileMapper *mapper)
{
@@ -962,27 +975,32 @@ 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->logWarning(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->logWarning(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->logWarning(
- scope->baseTypeName()
- + QStringLiteral(" was not found. Did you add all import paths?"),
- Log_Import, scope->sourceLocation());
+ if (newScope.isNull()) {
+ const QString error = scope->baseTypeError();
+ const QString name = scope->baseTypeName();
+ if (!error.isEmpty()) {
+ m_logger->logWarning(error, Log_Import);
+ } else if (!name.isEmpty()) {
+ m_logger->logWarning(
+ name + QStringLiteral(" was not found. Did you add all import paths?"),
+ Log_Import, scope->sourceLocation());
+ }
}
scope = newScope;
@@ -1091,10 +1109,11 @@ 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;
- m_exportedRootScope->setIsSingleton(m_rootIsSingleton);
+ if (rootScopeIsValid()) {
+ enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
+ } else {
+ enterRootScope(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
+ m_currentScope->setIsSingleton(m_rootIsSingleton);
}
const QTypeRevision revision = QQmlJSScope::resolveTypes(
@@ -1108,7 +1127,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);
}
@@ -1982,7 +2001,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;
@@ -1991,18 +2010,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;
@@ -2016,9 +2034,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 2a469d4cad..bc926b2e1b 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -59,12 +59,13 @@ struct QQmlJSResourceFileMapper;
class QQmlJSImportVisitor : public QQmlJS::AST::Visitor
{
public:
- QQmlJSImportVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
+ QQmlJSImportVisitor(const QQmlJSScope::Ptr &target,
+ QQmlJSImporter *importer, QQmlJSLogger *logger,
const QString &implicitImportDirectory,
const QStringList &qmldirFiles = QStringList());
~QQmlJSImportVisitor();
- QQmlJSScope::Ptr result() const;
+ QQmlJSScope::Ptr result() const { return m_exportedRootScope; }
QQmlJSLogger *logger() { return m_logger; }
@@ -157,7 +158,7 @@ protected:
QStringList m_qmldirFiles;
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;
@@ -199,6 +200,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;
bool parseLiteralBinding(const QString name, const QQmlJS::AST::Statement *statement);
@@ -273,6 +275,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 14817b0d64..12bd770c2a 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -92,15 +92,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)
@@ -316,8 +325,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())
@@ -381,7 +391,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;
@@ -391,7 +401,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:
@@ -442,8 +452,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();
@@ -583,6 +595,28 @@ bool QQmlJSScope::isNameDeferred(const QString &name) const
return isDeferred;
}
+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;
@@ -616,7 +650,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();
}
QString QQmlJSScope::defaultPropertyName() const
@@ -682,18 +716,16 @@ 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(internalName());
- QQmlJSScope::resolveEnums(result, m_importer->builtinInternalNames().value(u"int"_qs).scope);
+ scope->setInternalName(internalName());
+ QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames().value(u"int"_qs).scope);
if (m_isSingleton)
- result->setIsSingleton(true);
-
- return std::move(*result);
+ scope->setIsSingleton(true);
}
bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index be278a6c7b..475cc50f3f 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -59,7 +59,6 @@ class QQmlJSImporter;
class QQmlJSScope
{
- Q_DISABLE_COPY(QQmlJSScope)
public:
QQmlJSScope(QQmlJSScope &&) = default;
QQmlJSScope &operator=(QQmlJSScope &&) = default;
@@ -94,7 +93,8 @@ public:
CustomParser = 0x10,
Array = 0x20,
InlineComponent = 0x40,
- WrappedInImplicitComponent = 0x80
+ WrappedInImplicitComponent = 0x80,
+ HasBaseTypeError = 0x100
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAGS(Flags);
@@ -179,8 +179,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()
@@ -193,6 +193,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
@@ -201,6 +203,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; }
@@ -256,11 +259,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; }
@@ -460,7 +467,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,
@@ -485,7 +494,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.
@@ -525,8 +534,6 @@ public:
m_filePath(filePath), m_importer(importer)
{}
- QQmlJSScope create() const;
-
bool isValid() const
{
return !m_filePath.isEmpty() && m_importer != nullptr;
@@ -543,6 +550,14 @@ public:
}
private:
+ friend class QDeferredSharedPointer<QQmlJSScope>;
+ friend class QDeferredSharedPointer<const QQmlJSScope>;
+ friend class QDeferredWeakPointer<QQmlJSScope>;
+ friend class QDeferredWeakPointer<const QQmlJSScope>;
+
+ // Should only be called when lazy-loading the type in a deferred pointer.
+ void populate(const QSharedPointer<QQmlJSScope> &scope) const;
+
QString m_filePath;
QQmlJSImporter *m_importer = nullptr;
bool m_isSingleton = false;
diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp
index ae3c0becfe..753fbe12f8 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,11 +70,11 @@ 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;
QQmlJSLogger logger;
logger.setFileName(m_file);
@@ -88,13 +82,10 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
logger.setSilent(true);
QQmlJSImportVisitor membersVisitor(
- m_importer, &logger,
+ scope, m_importer, &logger,
QQmlJSImportVisitor::implicitImportDirectory(m_file, m_importer->resourceFileMapper()));
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 4dcdc3dc7f..f4dd8ceb15 100644
--- a/src/qmlcompiler/qqmljstypereader_p.h
+++ b/src/qmlcompiler/qqmljstypereader_p.h
@@ -59,7 +59,7 @@ public:
, m_file(file)
{}
- QQmlJSScope::Ptr operator()();
+ bool operator()(const QSharedPointer<QQmlJSScope> &scope);
QList<QQmlJS::DiagnosticMessage> errors() const { return m_errors; }
private:
diff --git a/src/qmllint/findwarnings.cpp b/src/qmllint/findwarnings.cpp
index cd45f66541..a54868f6b4 100644
--- a/src/qmllint/findwarnings.cpp
+++ b/src/qmllint/findwarnings.cpp
@@ -43,11 +43,11 @@
QT_BEGIN_NAMESPACE
-FindWarningVisitor::FindWarningVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
- QStringList qmldirFiles,
- QList<QQmlJS::SourceLocation> comments)
+FindWarningVisitor::FindWarningVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
+ QStringList qmldirFiles, QList<QQmlJS::SourceLocation> comments)
: QQmlJSImportVisitor(
- importer, logger,
+ target, importer, logger,
implicitImportDirectory(logger->fileName(), importer->resourceFileMapper()),
qmldirFiles)
{
diff --git a/src/qmllint/findwarnings_p.h b/src/qmllint/findwarnings_p.h
index e0cf7aa1d3..74a1d43a6f 100644
--- a/src/qmllint/findwarnings_p.h
+++ b/src/qmllint/findwarnings_p.h
@@ -57,8 +57,9 @@ class FindWarningVisitor : public QQmlJSImportVisitor
{
Q_DISABLE_COPY_MOVE(FindWarningVisitor)
public:
- explicit FindWarningVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
- QStringList qmldirFiles, QList<QQmlJS::SourceLocation> comments);
+ explicit FindWarningVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
+ QStringList qmldirFiles, QList<QQmlJS::SourceLocation> comments);
~FindWarningVisitor() override = default;
bool check();
diff --git a/src/qmllint/qqmllinter.cpp b/src/qmllint/qqmllinter.cpp
index c372566d95..8325eda1be 100644
--- a/src/qmllint/qqmllinter.cpp
+++ b/src/qmllint/qqmllinter.cpp
@@ -207,6 +207,7 @@ bool QQmlLinter::lintFile(const QString &filename, const QString *fileContents,
m_logger->setCode(code);
m_logger->setSilent(silent || json);
FindWarningVisitor v {
+ QQmlJSScope::create(),
&m_importer,
m_logger.get(),
qmldirFiles,
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/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 31faaacc07..f0df1169b4 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -436,8 +436,8 @@ void TestQmllint::dirtyQmlCode_data()
<< QString("Warning: %1:5:35: Property \"weDontKnowIt\" "
"not found on type \"CustomPalette\"")
<< QString() << QString() << false;
- QTest::newRow("inheritanceCylce") << QStringLiteral("Cycle1.qml")
- << QString("Warning: %1: Cycle2 is part of an inheritance "
+ QTest::newRow("inheritanceCycle") << QStringLiteral("Cycle1.qml")
+ << QString("Warning: %1: Cycle1 is part of an inheritance "
"cycle: Cycle2 -> Cycle3 -> Cycle1 -> Cycle2")
<< QString() << QString() << false;
QTest::newRow("incompleteQmltypes3")
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index 69eb271984..75fb99c58c 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -87,7 +87,8 @@ class tst_qqmljsscope : public QQmlDataTest
logger.setFileName(url);
logger.setCode(sourceCode);
logger.setSilent(true);
- QQmlJSImportVisitor visitor(&importer, &logger, dataDirectory());
+ QQmlJSScope::Ptr target = QQmlJSScope::create();
+ QQmlJSImportVisitor visitor(target, &importer, &logger, dataDirectory());
QQmlJSTypeResolver typeResolver { &importer };
typeResolver.init(&visitor, document.program);
return visitor.result();
diff --git a/tools/qmltc/main.cpp b/tools/qmltc/main.cpp
index 5851f0d7ac..2fa8b64169 100644
--- a/tools/qmltc/main.cpp
+++ b/tools/qmltc/main.cpp
@@ -207,7 +207,8 @@ int main(int argc, char **argv)
logger.setCode(sourceCode);
setupLogger(logger);
- Qmltc::Visitor visitor(&importer, &logger,
+ QQmlJSScope::Ptr target = QQmlJSScope::create();
+ Qmltc::Visitor visitor(target, &importer, &logger,
QQmlJSImportVisitor::implicitImportDirectory(url, &mapper), qmldirFiles);
Qmltc::TypeResolver typeResolver { &importer };
typeResolver.init(visitor, document.program);
diff --git a/tools/qmltc/prototype/visitor.cpp b/tools/qmltc/prototype/visitor.cpp
index 307cb992ea..9aa3bbc63b 100644
--- a/tools/qmltc/prototype/visitor.cpp
+++ b/tools/qmltc/prototype/visitor.cpp
@@ -32,9 +32,9 @@
#include <QtCore/qfileinfo.h>
namespace Qmltc {
-Visitor::Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
+Visitor::Visitor(const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
const QString &implicitImportDirectory, const QStringList &qmltypesFiles)
- : QQmlJSImportVisitor(importer, logger, implicitImportDirectory, qmltypesFiles)
+ : QQmlJSImportVisitor(target, importer, logger, implicitImportDirectory, qmltypesFiles)
{
}
diff --git a/tools/qmltc/prototype/visitor.h b/tools/qmltc/prototype/visitor.h
index 730021b66c..5684e01c6c 100644
--- a/tools/qmltc/prototype/visitor.h
+++ b/tools/qmltc/prototype/visitor.h
@@ -45,7 +45,8 @@ namespace Qmltc {
class Visitor : public QQmlJSImportVisitor
{
public:
- Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger, const QString &implicitImportDirectory,
+ Visitor(const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger,
+ const QString &implicitImportDirectory,
const QStringList &qmltypesFiles = QStringList());
bool visit(QQmlJS::AST::UiInlineComponent *) override;
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 691496d7c7..04b75749aa 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -45,7 +45,8 @@ static QString uniqueNameFromPieces(const QStringList &pieces, QHash<QString, in
QmltcVisitor::QmltcVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
const QString &implicitImportDirectory, const QStringList &qmldirFiles)
- : QQmlJSImportVisitor(importer, logger, implicitImportDirectory, qmldirFiles)
+ : QQmlJSImportVisitor(
+ QQmlJSScope::create(), importer, logger, implicitImportDirectory, qmldirFiles)
{
m_qmlTypeNames.append(QFileInfo(logger->fileName()).baseName()); // put document root
}