diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-31 11:26:09 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-04-04 18:51:23 +0200 |
commit | ca82086b0c4b12944b87c307011a870b34857076 (patch) | |
tree | 00ac7b2175bf2e2c2d5be3c04594d9c7511155bf | |
parent | 5f95610039f7077343815e2e0a6837b89ccfe9cd (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.h | 23 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 91 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor_p.h | 16 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 69 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 27 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypereader.cpp | 27 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypereader_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/cycleHead.qml | 3 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 2 |
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) { |