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. Pick-to: 6.2 6.3 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>
This commit is contained in:
parent
6eaef57cd1
commit
aea732d607
|
@ -47,16 +47,25 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
|
||||
template<typename T>
|
||||
class QDeferredFactory
|
||||
{
|
||||
public:
|
||||
T create() const;
|
||||
bool isValid() const;
|
||||
};
|
||||
class QDeferredSharedPointer;
|
||||
|
||||
template<typename T>
|
||||
class QDeferredWeakPointer;
|
||||
|
||||
template<typename T>
|
||||
class QDeferredFactory
|
||||
{
|
||||
public:
|
||||
bool isValid() const;
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -179,7 +188,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>>());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,8 +254,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>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,29 +1061,35 @@ 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?"),
|
||||
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()) {
|
||||
if (rootScopeIsValid()) {
|
||||
enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
|
||||
if (!m_exportedRootScope) {
|
||||
m_exportedRootScope = m_currentScope;
|
||||
m_exportedRootScope->setIsSingleton(m_rootIsSingleton);
|
||||
} 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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<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(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<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())
|
||||
|
@ -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<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_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
|
||||
|
|
|
@ -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<QQmlJSScope>(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<QString, QQmlJSMetaMethod> 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<QString, QQmlJSMetaProperty> 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<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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -2,5 +2,6 @@ import Cycle
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
MenuItem {}
|
||||
property MenuItem item: a
|
||||
MenuItem { id: a }
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<QQmlJSScope::ConstPtr, QList<QQmlJSMetaPropertyBinding>> bindings;
|
||||
|
|
Loading…
Reference in New Issue