diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h index e19676d7ea..8a72c7a913 100644 --- a/src/qmlcompiler/qdeferredpointer_p.h +++ b/src/qmlcompiler/qdeferredpointer_p.h @@ -47,16 +47,25 @@ QT_BEGIN_NAMESPACE template -class QDeferredFactory -{ -public: - T create() const; - bool isValid() const; -}; +class QDeferredSharedPointer; template class QDeferredWeakPointer; +template +class QDeferredFactory +{ +public: + bool isValid() const; + +private: + friend class QDeferredSharedPointer; + friend class QDeferredWeakPointer; + friend class QDeferredSharedPointer; + friend class QDeferredWeakPointer; + void populate(const QSharedPointer &) const; +}; + template class QDeferredSharedPointer { @@ -179,7 +188,7 @@ private: if (Factory *f = factory()) { Factory localFactory; std::swap(localFactory, *f); // Swap before executing, to avoid recursion - const_cast &>(*m_data) = localFactory.create(); + localFactory.populate(m_data.template constCast>()); } } @@ -245,8 +254,8 @@ private: if (factory->isValid()) { Factory localFactory; std::swap(localFactory, *factory); // Swap before executing, to avoid recursion - const_cast &>(*(m_data.toStrongRef())) - = localFactory.create(); + localFactory.populate( + m_data.toStrongRef().template constCast>()); } } } diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp index c765a1c94e..14811c2aa2 100644 --- a/src/qmlcompiler/qqmljscompiler.cpp +++ b/src/qmlcompiler/qqmljscompiler.cpp @@ -645,7 +645,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 4f8a916940..5e1318fca2 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; @@ -116,10 +118,10 @@ 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->setFilePath(QFileInfo(m_logger->fileName()).absoluteFilePath()); @@ -127,6 +129,22 @@ void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QS 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) @@ -295,11 +313,6 @@ void QQmlJSImportVisitor::resolveAliasesAndIds() } } -QQmlJSScope::Ptr QQmlJSImportVisitor::result() const -{ - return m_exportedRootScope; -} - QString QQmlJSImportVisitor::implicitImportDirectory( const QString &localFile, QQmlJSResourceFileMapper *mapper) { @@ -1048,28 +1061,34 @@ 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, scope->sourceLocation()); + const QString message = QStringLiteral("%1 is part of an inheritance cycle: %2") + .arg(scope->internalName(), inheritenceCycle); + m_logger->log(message, Log_InheritanceCycle, scope->sourceLocation()); 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, scope->sourceLocation(), true, true, - QQmlJSUtils::didYouMean(scope->baseTypeName(), m_rootScopeImports.keys(), - scope->sourceLocation())); + if (newScope.isNull()) { + const QString error = scope->baseTypeError(); + const QString name = scope->baseTypeName(); + if (!error.isEmpty()) { + m_logger->log(error, Log_Import, scope->sourceLocation(), true, true); + } else if (!name.isEmpty()) { + m_logger->log( + name + QStringLiteral(" was not found. Did you add all import paths?"), + Log_Import, scope->sourceLocation(), true, true, + QQmlJSUtils::didYouMean(scope->baseTypeName(), m_rootScopeImports.keys(), + scope->sourceLocation())); + } } scope = newScope; @@ -1206,10 +1225,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( @@ -1223,7 +1243,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); } @@ -2118,7 +2138,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; @@ -2127,18 +2147,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; @@ -2152,9 +2171,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 69714ced36..e9347a49f0 100644 --- a/src/qmlcompiler/qqmljsimportvisitor_p.h +++ b/src/qmlcompiler/qqmljsimportvisitor_p.h @@ -61,12 +61,13 @@ struct QQmlJSResourceFileMapper; class Q_QMLCOMPILER_PRIVATE_EXPORT 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; } @@ -161,7 +162,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; @@ -226,6 +227,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; enum class LiteralOrScriptParseResult { Invalid, Script, Literal }; @@ -300,6 +302,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/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp index 83145e8b3e..e8ca914b04 100644 --- a/src/qmlcompiler/qqmljslinter.cpp +++ b/src/qmlcompiler/qqmljslinter.cpp @@ -311,7 +311,8 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename, m_logger->setFileName(m_useAbsolutePath ? info.absoluteFilePath() : filename); m_logger->setCode(code); m_logger->setSilent(silent || json); - QQmlJSImportVisitor v { &m_importer, m_logger.get(), + QQmlJSScope::Ptr target = QQmlJSScope::create(); + QQmlJSImportVisitor v { target, &m_importer, m_logger.get(), QQmlJSImportVisitor::implicitImportDirectory( m_logger->fileName(), m_importer.resourceFileMapper()), qmldirFiles }; diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index a13fa32790..5b23b247b3 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -92,23 +92,23 @@ 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 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(origin->m_scopeType, origin->m_parentScope); + QQmlJSScope::Ptr cloned = create(); *cloned = *origin; + if (QQmlJSScope::Ptr parent = cloned->parentScope()) + parent->m_childScopes.append(cloned); return cloned; } @@ -382,8 +382,9 @@ QTypeRevision QQmlJSScope::resolveType( const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context, QSet *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()) @@ -447,7 +448,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; @@ -457,7 +458,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: @@ -508,8 +509,10 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope:: if (it->type()) continue; Q_ASSERT(intType); // We need an "int" type to resolve enums - 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(); @@ -761,6 +764,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; @@ -792,7 +817,7 @@ bool QQmlJSScope::isResolved() const const bool nameIsEmpty = (m_scopeType == ScopeType::AttachedPropertyScope || m_scopeType == ScopeType::GroupedPropertyScope) ? m_internalName.isEmpty() - : m_baseTypeName.isEmpty(); + : m_baseTypeNameOrError.isEmpty(); if (nameIsEmpty) return true; if (m_baseType.scope.isNull()) @@ -865,31 +890,29 @@ bool QQmlJSScope::Export::isValid() const return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty(); } -QQmlJSScope QDeferredFactory::create() const +void QDeferredFactory::populate(const QSharedPointer &scope) const { QQmlJSTypeReader typeReader(m_importer, m_filePath); - QQmlJSScope::Ptr result = typeReader(); + typeReader(scope); m_importer->m_globalWarnings.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->isSingleton()) { + if (m_isSingleton && !scope->isSingleton()) { m_importer->m_globalWarnings.append( { QStringLiteral( "Type %1 declared as singleton in qmldir but missing pragma Singleton") - .arg(result->internalName()), + .arg(scope->internalName()), QtCriticalMsg, QQmlJS::SourceLocation() }); - result->setIsSingleton(true); - } else if (!m_isSingleton && result->isSingleton()) { + scope->setIsSingleton(true); + } else if (!m_isSingleton && scope->isSingleton()) { m_importer->m_globalWarnings.append( { QStringLiteral("Type %1 not declared as singleton in qmldir " "but using pragma Singleton") - .arg(result->internalName()), + .arg(scope->internalName()), QtCriticalMsg, QQmlJS::SourceLocation() }); - result->setIsSingleton(false); + scope->setIsSingleton(false); } - - return std::move(*result); } bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index da670f0c71..f68c5d0596 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -95,7 +95,8 @@ public: CustomParser = 0x10, Array = 0x20, InlineComponent = 0x40, - WrappedInImplicitComponent = 0x80 + WrappedInImplicitComponent = 0x80, + HasBaseTypeError = 0x100 }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAGS(Flags); @@ -241,8 +242,7 @@ public: UnnamedPropertyTarget // default property bindings, where property name is unspecified }; - static QQmlJSScope::Ptr create(ScopeType type = QQmlJSScope::QMLScope, - const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr()); + static QQmlJSScope::Ptr create() { return QSharedPointer(new QQmlJSScope); } static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin); static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope); @@ -256,6 +256,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 @@ -264,6 +266,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 ownMethods() const { return m_methods; } @@ -322,11 +325,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 ownProperties() const { return m_properties; } @@ -552,7 +559,7 @@ public: }; private: - QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr()); + QQmlJSScope() = default; QQmlJSScope(const QQmlJSScope &) = default; QQmlJSScope &operator=(const QQmlJSScope &) = default; @@ -587,7 +594,7 @@ private: QString m_filePath; 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. @@ -627,8 +634,6 @@ public: m_filePath(filePath), m_importer(importer) {} - QQmlJSScope create() const; - bool isValid() const { return !m_filePath.isEmpty() && m_importer != nullptr; @@ -645,6 +650,14 @@ public: } private: + friend class QDeferredSharedPointer; + friend class QDeferredSharedPointer; + friend class QDeferredWeakPointer; + friend class QDeferredWeakPointer; + + // Should only be called when lazy-loading the type in a deferred pointer. + void populate(const QSharedPointer &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 &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 &scope); QList 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/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index efe1dd18c9..6ebc069e22 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -483,7 +483,7 @@ void TestQmllint::dirtyQmlCode_data() QTest::newRow("inheritanceCycle") << QStringLiteral("Cycle1.qml") << Result { { Message { - QStringLiteral("Cycle2 is part of an inheritance cycle: Cycle2 -> Cycle3 " + QStringLiteral("Cycle1 is part of an inheritance cycle: Cycle2 -> Cycle3 " "-> Cycle1 -> Cycle2"), 2, 1 } } }; QTest::newRow("badQmldirImportAndDepend") diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp index ba75ea7e2d..ad4c29143b 100644 --- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp +++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp @@ -84,7 +84,8 @@ class tst_qqmljsscope : public QQmlDataTest logger.setFileName(url); logger.setCode(sourceCode); logger.setSilent(true); - QQmlJSImportVisitor visitor(&m_importer, &logger, dataDirectory()); + QQmlJSScope::Ptr target = QQmlJSScope::create(); + QQmlJSImportVisitor visitor(target, &m_importer, &logger, dataDirectory()); QQmlJSTypeResolver typeResolver { &m_importer }; typeResolver.init(&visitor, document.program); return visitor.result(); diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp index 213acb89f6..ba85bd8f4f 100644 --- a/tools/qmltc/qmltcvisitor.cpp +++ b/tools/qmltc/qmltcvisitor.cpp @@ -64,7 +64,8 @@ static bool isOrUnderComponent(QQmlJSScope::ConstPtr type) 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 } @@ -267,7 +268,7 @@ bool QmltcVisitor::visit(QQmlJS::AST::UiInlineComponent *component) void QmltcVisitor::endVisit(QQmlJS::AST::UiProgram *program) { QQmlJSImportVisitor::endVisit(program); - if (!m_exportedRootScope) // in case we failed badly + if (!rootScopeIsValid()) // in case we failed badly return; QHash> bindings;