QtQml: Clean up qmldir redirection
We need to perform the redirection before inserting imports into namespaces. Through the redirection we might discover a module that we have already imported before. In that case we must not import it again. Pick-to: 6.9 6.8 Fixes: QTBUG-133587 Change-Id: I47a279461763b5397137002a9e7c7d3bfc7ad15d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
6104332961
commit
f7e29f7d27
|
@ -769,13 +769,24 @@ bool QQmlImports::resolveType(
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
|
QQmlImportInstance *QQmlImportNamespace::findImportByModuleUri(
|
||||||
|
const QString &moduleUri, QTypeRevision version) const
|
||||||
{
|
{
|
||||||
for (QQmlImportInstance *import : imports) {
|
const auto end = imports.cend();
|
||||||
if (import->uri == uri)
|
const auto it = std::find_if(imports.cbegin(), end, [&](const QQmlImportInstance *import) {
|
||||||
return import;
|
return import->uri == moduleUri && import->version == version;
|
||||||
}
|
});
|
||||||
return nullptr;
|
return it == end ? nullptr : *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
QQmlImportInstance *QQmlImportNamespace::findImportByLocation(
|
||||||
|
const QString &location, QTypeRevision version) const
|
||||||
|
{
|
||||||
|
const auto end = imports.cend();
|
||||||
|
const auto it = std::find_if(imports.cbegin(), end, [&](const QQmlImportInstance *import) {
|
||||||
|
return import->url == location && import->version == version;
|
||||||
|
});
|
||||||
|
return it == end ? nullptr : *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
|
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
|
||||||
|
@ -920,8 +931,7 @@ void QQmlImports::registerBuiltinModuleTypes(
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QQmlImports::redirectQmldirContent(
|
QString QQmlImports::redirectQmldirContent(
|
||||||
QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir,
|
QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir)
|
||||||
QQmlImportInstance *inserted)
|
|
||||||
{
|
{
|
||||||
const QString preferredPath = qmldir->preferredPath();
|
const QString preferredPath = qmldir->preferredPath();
|
||||||
const QString url = preferredPath.startsWith(u':')
|
const QString url = preferredPath.startsWith(u':')
|
||||||
|
@ -935,9 +945,6 @@ QString QQmlImports::redirectQmldirContent(
|
||||||
if (redirected.hasContent() && !redirected.hasError())
|
if (redirected.hasContent() && !redirected.hasError())
|
||||||
*qmldir = std::move(redirected);
|
*qmldir = std::move(redirected);
|
||||||
|
|
||||||
if (const QString qmldirUri = qmldir->typeNamespace(); !qmldirUri.isEmpty())
|
|
||||||
inserted->uri = qmldirUri;
|
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,7 +998,7 @@ QString QQmlImports::resolvedUri(const QString &dir_arg, QQmlTypeLoader *typeLoa
|
||||||
return stableRelativePath;
|
return stableRelativePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTypeRevision QQmlImports::matchingQmldirVersion(
|
static QTypeRevision matchingQmldirVersion(
|
||||||
const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, QTypeRevision version,
|
const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, QTypeRevision version,
|
||||||
QList<QQmlError> *errors)
|
QList<QQmlError> *errors)
|
||||||
{
|
{
|
||||||
|
@ -1065,13 +1072,13 @@ QTypeRevision QQmlImports::matchingQmldirVersion(
|
||||||
|| (version.hasMinorVersion()
|
|| (version.hasMinorVersion()
|
||||||
&& (lowestMinorVersion > version.minorVersion()
|
&& (lowestMinorVersion > version.minorVersion()
|
||||||
|| highestMinorVersion < version.minorVersion())))) {
|
|| highestMinorVersion < version.minorVersion())))) {
|
||||||
errors->prepend(moduleNotFoundError(uri, version));
|
errors->prepend(QQmlImports::moduleNotFoundError(uri, version));
|
||||||
return QTypeRevision();
|
return QTypeRevision();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... otherwise, anything is valid.
|
// ... otherwise, anything is valid.
|
||||||
if (bestMajorVersion < 0)
|
if (bestMajorVersion < 0)
|
||||||
return validVersion();
|
return QQmlImports::validVersion();
|
||||||
|
|
||||||
return QTypeRevision::fromVersion(
|
return QTypeRevision::fromVersion(
|
||||||
bestMajorVersion,
|
bestMajorVersion,
|
||||||
|
@ -1132,9 +1139,47 @@ static QString getVersionInfo(QTypeRevision version) {
|
||||||
return version.isValid() ? QDebug::toString(version) : u"(latest)"_s;
|
return version.isValid() ? QDebug::toString(version) : u"(latest)"_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QTypeRevision matchingModuleVersionForLibraryImport(
|
||||||
|
const QString &uri, QTypeRevision version, QList<QQmlError> *errors)
|
||||||
|
{
|
||||||
|
const QTypeRevision matchingVersion = QQmlMetaType::matchingModuleVersion(uri, version);
|
||||||
|
if (!matchingVersion.isValid())
|
||||||
|
errors->prepend(QQmlImports::moduleNotFoundError(uri, relevantVersion(uri, version)));
|
||||||
|
return matchingVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QTypeRevision finalizeLibraryImport(
|
||||||
|
const QString &uri, QTypeRevision version, const QQmlTypeLoaderQmldirContent &qmldir,
|
||||||
|
QQmlImportInstance *inserted, QList<QQmlError> *errors)
|
||||||
|
{
|
||||||
|
// Ensure that we are actually providing something
|
||||||
|
const QTypeRevision matchingVersion = QQmlMetaType::matchingModuleVersion(uri, version);
|
||||||
|
if (matchingVersion.isValid())
|
||||||
|
return matchingVersion;
|
||||||
|
|
||||||
|
if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
|
||||||
|
if (qmldir.plugins().isEmpty()) {
|
||||||
|
if (!qmldir.imports().isEmpty())
|
||||||
|
return QQmlImports::validVersion(); // This is a pure redirection
|
||||||
|
if (qmldir.hasTypeInfo())
|
||||||
|
return QQmlImports::validVersion(); // A pure C++ module without plugin
|
||||||
|
}
|
||||||
|
errors->prepend(QQmlImports::moduleNotFoundError(uri, relevantVersion(uri, version)));
|
||||||
|
return QTypeRevision();
|
||||||
|
} else {
|
||||||
|
// Verify that the qmldir content is valid for this version
|
||||||
|
version = matchingQmldirVersion(qmldir, uri, version, errors);
|
||||||
|
if (!version.isValid())
|
||||||
|
return QTypeRevision();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(version.isValid());
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
QTypeRevision QQmlImports::addLibraryImport(
|
QTypeRevision QQmlImports::addLibraryImport(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
||||||
QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
|
QTypeRevision requestedVersion, const QString &qmldirIdentifier, const QString &qmldirUrl,
|
||||||
ImportFlags flags, quint16 precedence, QList<QQmlError> *errors)
|
ImportFlags flags, quint16 precedence, QList<QQmlError> *errors)
|
||||||
{
|
{
|
||||||
Q_ASSERT(typeLoader);
|
Q_ASSERT(typeLoader);
|
||||||
|
@ -1143,64 +1188,73 @@ QTypeRevision QQmlImports::addLibraryImport(
|
||||||
if (lcQmlImport().isDebugEnabled()) {
|
if (lcQmlImport().isDebugEnabled()) {
|
||||||
qCDebug(lcQmlImport)
|
qCDebug(lcQmlImport)
|
||||||
<< "addLibraryImport:" << qPrintable(baseUrl().toString())
|
<< "addLibraryImport:" << qPrintable(baseUrl().toString())
|
||||||
<< uri << "version" << getVersionInfo(version) << "as" << prefix;
|
<< uri << "version" << getVersionInfo(requestedVersion) << "as" << prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlImportNamespace *nameSpace = importNamespace(prefix);
|
QQmlImportNamespace *nameSpace = importNamespace(prefix);
|
||||||
Q_ASSERT(nameSpace);
|
Q_ASSERT(nameSpace);
|
||||||
|
|
||||||
|
const bool noQmldir = qmldirIdentifier.isEmpty();
|
||||||
|
const bool isIncomplete = (flags & QQmlImports::ImportIncomplete);
|
||||||
|
if (noQmldir || isIncomplete) {
|
||||||
|
QQmlImportInstance *inserted = addImportToNamespace(
|
||||||
|
nameSpace, uri, qmldirUrl, requestedVersion,
|
||||||
|
QV4::CompiledData::Import::ImportLibrary, errors,
|
||||||
|
precedence);
|
||||||
|
Q_ASSERT(inserted);
|
||||||
|
|
||||||
|
if (noQmldir && !isIncomplete) {
|
||||||
|
// No need to wait for the qmldir to become available if we're not supposed to use it.
|
||||||
|
if (!QQmlMetaType::typeModule(uri, requestedVersion))
|
||||||
|
QQmlMetaType::qmlRegisterModuleTypes(uri);
|
||||||
|
return matchingModuleVersionForLibraryImport(uri, requestedVersion, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validVersion(requestedVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
QQmlTypeLoaderQmldirContent qmldir;
|
||||||
|
if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors)) {
|
||||||
|
// qmldir had errors.
|
||||||
|
return QTypeRevision();
|
||||||
|
}
|
||||||
|
|
||||||
|
// qmldir is remote and can't be loaded synchronously, but we may already know the module.
|
||||||
|
if (!qmldir.hasContent())
|
||||||
|
return matchingModuleVersionForLibraryImport(uri, requestedVersion, errors);
|
||||||
|
|
||||||
|
// Load the plugin before redirecting. Otherwise we might not find the qmldir we're looking for.
|
||||||
|
const QTypeRevision importedVersion = importExtension(
|
||||||
|
typeLoader, uri, requestedVersion, &qmldir, errors);
|
||||||
|
if (!importedVersion.isValid())
|
||||||
|
return QTypeRevision();
|
||||||
|
|
||||||
|
QString resolvedUrl;
|
||||||
|
QString resolvedUri;
|
||||||
|
if (qmldir.hasRedirection()) {
|
||||||
|
resolvedUrl = redirectQmldirContent(typeLoader, &qmldir);
|
||||||
|
resolvedUri = qmldir.typeNamespace();
|
||||||
|
if (QQmlImportInstance *existing
|
||||||
|
= nameSpace->findImportByLocation(resolvedUrl, requestedVersion)) {
|
||||||
|
return finalizeLibraryImport(uri, importedVersion, qmldir, existing, errors);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolvedUrl = qmldirUrl;
|
||||||
|
resolvedUri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
QQmlImportInstance *inserted = addImportToNamespace(
|
QQmlImportInstance *inserted = addImportToNamespace(
|
||||||
nameSpace, uri, qmldirUrl, version,
|
nameSpace, resolvedUri, resolvedUrl, requestedVersion,
|
||||||
QV4::CompiledData::Import::ImportLibrary, errors,
|
QV4::CompiledData::Import::ImportLibrary, errors,
|
||||||
precedence);
|
precedence);
|
||||||
Q_ASSERT(inserted);
|
Q_ASSERT(inserted);
|
||||||
|
|
||||||
if (!(flags & QQmlImports::ImportIncomplete)) {
|
registerBuiltinModuleTypes(qmldir, importedVersion);
|
||||||
QQmlTypeLoaderQmldirContent qmldir;
|
|
||||||
|
|
||||||
if (!qmldirIdentifier.isEmpty()) {
|
if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
|
||||||
if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
|
return QTypeRevision();
|
||||||
return QTypeRevision();
|
|
||||||
|
|
||||||
if (qmldir.hasContent()) {
|
return finalizeLibraryImport(uri, importedVersion, qmldir, inserted, errors);
|
||||||
version = importExtension(typeLoader, uri, version, &qmldir, errors);
|
|
||||||
if (!version.isValid())
|
|
||||||
return QTypeRevision();
|
|
||||||
|
|
||||||
const QString resolvedUrl = qmldir.hasRedirection()
|
|
||||||
? redirectQmldirContent(typeLoader, &qmldir, inserted)
|
|
||||||
: qmldirUrl;
|
|
||||||
|
|
||||||
registerBuiltinModuleTypes(qmldir, version);
|
|
||||||
|
|
||||||
if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
|
|
||||||
return QTypeRevision();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that we are actually providing something
|
|
||||||
const QTypeRevision matchingVersion = QQmlMetaType::matchingModuleVersion(uri, version);
|
|
||||||
if (matchingVersion.isValid())
|
|
||||||
return matchingVersion;
|
|
||||||
|
|
||||||
if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
|
|
||||||
if (qmldir.plugins().isEmpty()) {
|
|
||||||
if (!qmldir.imports().isEmpty())
|
|
||||||
return validVersion(); // This is a pure redirection
|
|
||||||
if (qmldir.hasTypeInfo())
|
|
||||||
return validVersion(); // A pure C++ module without plugin
|
|
||||||
}
|
|
||||||
errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
|
|
||||||
return QTypeRevision();
|
|
||||||
} else if (qmldir.hasContent()) {
|
|
||||||
// Verify that the qmldir content is valid for this version
|
|
||||||
version = matchingQmldirVersion(qmldir, uri, version, errors);
|
|
||||||
if (!version.isValid())
|
|
||||||
return QTypeRevision();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validVersion(version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1226,7 +1280,7 @@ QTypeRevision QQmlImports::addLibraryImport(
|
||||||
*/
|
*/
|
||||||
QTypeRevision QQmlImports::addFileImport(
|
QTypeRevision QQmlImports::addFileImport(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
||||||
QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
|
QTypeRevision requestedVersion, ImportFlags flags, quint16 precedence, QString *localQmldir,
|
||||||
QList<QQmlError> *errors)
|
QList<QQmlError> *errors)
|
||||||
{
|
{
|
||||||
Q_ASSERT(typeLoader);
|
Q_ASSERT(typeLoader);
|
||||||
|
@ -1235,7 +1289,7 @@ QTypeRevision QQmlImports::addFileImport(
|
||||||
if (lcQmlImport().isDebugEnabled()) {
|
if (lcQmlImport().isDebugEnabled()) {
|
||||||
qCDebug(lcQmlImport)
|
qCDebug(lcQmlImport)
|
||||||
<< "addFileImport:" << qPrintable(baseUrl().toString())
|
<< "addFileImport:" << qPrintable(baseUrl().toString())
|
||||||
<< uri << "version" << getVersionInfo(version) << "as" << prefix;
|
<< uri << "version" << getVersionInfo(requestedVersion) << "as" << prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
|
if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
|
||||||
|
@ -1329,53 +1383,85 @@ QTypeRevision QQmlImports::addFileImport(
|
||||||
it != nameSpace->imports.constEnd(); ++it) {
|
it != nameSpace->imports.constEnd(); ++it) {
|
||||||
if ((*it)->url == url) {
|
if ((*it)->url == url) {
|
||||||
(*it)->implicitlyImported = true;
|
(*it)->implicitlyImported = true;
|
||||||
return validVersion(version);
|
return validVersion(requestedVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & QQmlImports::ImportIncomplete) && !qmldirIdentifier.isEmpty()) {
|
if ((flags & QQmlImports::ImportIncomplete) || qmldirIdentifier.isEmpty()) {
|
||||||
QQmlTypeLoaderQmldirContent qmldir;
|
QQmlImportInstance *inserted = addImportToNamespace(
|
||||||
if (!getQmldirContent(typeLoader, qmldirIdentifier, importUri, &qmldir, errors))
|
nameSpace, importUri, url, requestedVersion, QV4::CompiledData::Import::ImportFile,
|
||||||
return QTypeRevision();
|
errors, precedence);
|
||||||
|
Q_ASSERT(inserted);
|
||||||
|
return validVersion(requestedVersion);
|
||||||
|
}
|
||||||
|
|
||||||
if (qmldir.hasContent()) {
|
QQmlTypeLoaderQmldirContent qmldir;
|
||||||
// Prefer the qmldir URI. Unless it doesn't exist.
|
if (!getQmldirContent(typeLoader, qmldirIdentifier, importUri, &qmldir, errors))
|
||||||
const QString qmldirUri = qmldir.typeNamespace();
|
return QTypeRevision();
|
||||||
if (!qmldirUri.isEmpty())
|
|
||||||
importUri = qmldirUri;
|
|
||||||
|
|
||||||
QQmlImportInstance *inserted = addImportToNamespace(
|
if (!qmldir.hasContent()) {
|
||||||
nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
|
QQmlImportInstance *inserted = addImportToNamespace(
|
||||||
errors, precedence);
|
nameSpace, importUri, url, requestedVersion, QV4::CompiledData::Import::ImportFile,
|
||||||
Q_ASSERT(inserted);
|
errors, precedence);
|
||||||
|
Q_ASSERT(inserted);
|
||||||
|
return validVersion(requestedVersion);
|
||||||
|
}
|
||||||
|
|
||||||
version = importExtension(typeLoader, importUri, version, &qmldir, errors);
|
// Prefer the qmldir URI. Unless it doesn't exist.
|
||||||
if (!version.isValid())
|
const QString qmldirUri = qmldir.typeNamespace();
|
||||||
return QTypeRevision();
|
if (!qmldirUri.isEmpty())
|
||||||
|
importUri = qmldirUri;
|
||||||
|
|
||||||
if (qmldir.hasRedirection())
|
// Load the plugin before redirecting. Otherwise we might not find the qmldir we're looking for.
|
||||||
url = redirectQmldirContent(typeLoader, &qmldir, inserted);
|
const QTypeRevision importedVersion
|
||||||
|
= importExtension(typeLoader, importUri, requestedVersion, &qmldir, errors);
|
||||||
|
if (!importedVersion.isValid())
|
||||||
|
return QTypeRevision();
|
||||||
|
|
||||||
registerBuiltinModuleTypes(qmldir, version);
|
QString resolvedUrl;
|
||||||
|
if (qmldir.hasRedirection()) {
|
||||||
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
|
resolvedUrl = redirectQmldirContent(typeLoader, &qmldir);
|
||||||
return QTypeRevision();
|
importUri = qmldir.typeNamespace();
|
||||||
|
if (resolvedUrl != url) {
|
||||||
return validVersion(version);
|
if (QQmlImportInstance *existing
|
||||||
|
= nameSpace->findImportByLocation(resolvedUrl, requestedVersion)) {
|
||||||
|
// We've alraedy seen this import. No need to add another entry.
|
||||||
|
return validVersion(existing->version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
resolvedUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlImportInstance *inserted = addImportToNamespace(
|
QQmlImportInstance *inserted = addImportToNamespace(
|
||||||
nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
|
nameSpace, importUri, resolvedUrl, requestedVersion, QV4::CompiledData::Import::ImportFile,
|
||||||
errors, precedence);
|
errors, precedence);
|
||||||
Q_ASSERT(inserted);
|
Q_ASSERT(inserted);
|
||||||
return validVersion(version);
|
|
||||||
|
registerBuiltinModuleTypes(qmldir, importedVersion);
|
||||||
|
|
||||||
|
if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
|
||||||
|
return QTypeRevision();
|
||||||
|
|
||||||
|
Q_ASSERT(importedVersion.isValid());
|
||||||
|
return importedVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QTypeRevision qmldirContentError(const QString &uri, QList<QQmlError> *errors)
|
||||||
|
{
|
||||||
|
if (errors->isEmpty()) {
|
||||||
|
QQmlError error;
|
||||||
|
error.setDescription(QQmlTypeLoader::tr("Cannot update qmldir content for '%1'").arg(uri));
|
||||||
|
errors->prepend(error);
|
||||||
|
}
|
||||||
|
return QTypeRevision();
|
||||||
}
|
}
|
||||||
|
|
||||||
QTypeRevision QQmlImports::updateQmldirContent(
|
QTypeRevision QQmlImports::updateQmldirContent(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
|
||||||
const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors)
|
const QString &prefix, const QString &qmldirIdentifier, const QString &qmldirUrl,
|
||||||
|
QList<QQmlError> *errors)
|
||||||
{
|
{
|
||||||
Q_ASSERT(typeLoader);
|
Q_ASSERT(typeLoader);
|
||||||
Q_ASSERT(errors);
|
Q_ASSERT(errors);
|
||||||
|
@ -1387,48 +1473,61 @@ QTypeRevision QQmlImports::updateQmldirContent(
|
||||||
QQmlImportNamespace *nameSpace = importNamespace(prefix);
|
QQmlImportNamespace *nameSpace = importNamespace(prefix);
|
||||||
Q_ASSERT(nameSpace);
|
Q_ASSERT(nameSpace);
|
||||||
|
|
||||||
if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
|
QQmlImportInstance *import = nameSpace->findImportByModuleUri(uri, version);
|
||||||
QQmlTypeLoaderQmldirContent qmldir;
|
if (!import)
|
||||||
if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
|
return qmldirContentError(uri, errors);
|
||||||
return QTypeRevision();
|
|
||||||
|
|
||||||
if (qmldir.hasContent()) {
|
QQmlTypeLoaderQmldirContent qmldir;
|
||||||
QTypeRevision version = importExtension(
|
if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
|
||||||
typeLoader, uri, import->version, &qmldir, errors);
|
return QTypeRevision();
|
||||||
|
|
||||||
|
if (!qmldir.hasContent())
|
||||||
|
return qmldirContentError(uri, errors);
|
||||||
|
|
||||||
|
// Load the plugin before redirecting. Otherwise we might not find the qmldir we're looking for.
|
||||||
|
version = importExtension(typeLoader, uri, import->version, &qmldir, errors);
|
||||||
|
if (!version.isValid())
|
||||||
|
return QTypeRevision();
|
||||||
|
|
||||||
|
QString resolvedUrl;
|
||||||
|
if (qmldir.hasRedirection()) {
|
||||||
|
resolvedUrl = redirectQmldirContent(typeLoader, &qmldir);
|
||||||
|
if (resolvedUrl != import->url) {
|
||||||
|
if (QQmlImportInstance *existing
|
||||||
|
= nameSpace->findImportByLocation(resolvedUrl, import->version)) {
|
||||||
|
// We've re-discovered the same module via a different redirect.
|
||||||
|
// No need to import it again.
|
||||||
|
nameSpace->imports.removeOne(import);
|
||||||
|
delete import;
|
||||||
|
return validVersion(existing->version);
|
||||||
|
}
|
||||||
|
import->url = resolvedUrl;
|
||||||
|
}
|
||||||
|
import->uri = qmldir.typeNamespace();
|
||||||
|
} else {
|
||||||
|
resolvedUrl = qmldirUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerBuiltinModuleTypes(qmldir, version);
|
||||||
|
|
||||||
|
if (import->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors)) {
|
||||||
|
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
|
||||||
|
// The implicit import qmldir can be empty, and plugins have no extra versions
|
||||||
|
if (uri != QLatin1String(".")
|
||||||
|
&& !QQmlMetaType::matchingModuleVersion(import->uri, version).isValid()) {
|
||||||
|
errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
|
||||||
|
return QTypeRevision();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Verify that the qmldir content is valid for this version
|
||||||
|
version = matchingQmldirVersion(qmldir, import->uri, version, errors);
|
||||||
if (!version.isValid())
|
if (!version.isValid())
|
||||||
return QTypeRevision();
|
return QTypeRevision();
|
||||||
|
|
||||||
const QString resolvedUrl = qmldir.hasRedirection()
|
|
||||||
? redirectQmldirContent(typeLoader, &qmldir, import)
|
|
||||||
: qmldirUrl;
|
|
||||||
|
|
||||||
registerBuiltinModuleTypes(qmldir, version);
|
|
||||||
|
|
||||||
if (import->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors)) {
|
|
||||||
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
|
|
||||||
// The implicit import qmldir can be empty, and plugins have no extra versions
|
|
||||||
if (uri != QLatin1String(".") && !QQmlMetaType::matchingModuleVersion(uri, version).isValid()) {
|
|
||||||
errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
|
|
||||||
return QTypeRevision();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Verify that the qmldir content is valid for this version
|
|
||||||
version = matchingQmldirVersion(qmldir, uri, version, errors);
|
|
||||||
if (!version.isValid())
|
|
||||||
return QTypeRevision();
|
|
||||||
}
|
|
||||||
return validVersion(version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return validVersion(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors->isEmpty()) {
|
return qmldirContentError(uri, errors);
|
||||||
QQmlError error;
|
|
||||||
error.setDescription(QQmlTypeLoader::tr("Cannot update qmldir content for '%1'").arg(uri));
|
|
||||||
errors->prepend(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return QTypeRevision();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -91,7 +91,10 @@ public:
|
||||||
|
|
||||||
QList<QQmlImportInstance *> imports;
|
QList<QQmlImportInstance *> imports;
|
||||||
|
|
||||||
QQmlImportInstance *findImport(const QString &uri) const;
|
QQmlImportInstance *findImportByModuleUri(
|
||||||
|
const QString &moduleUri, QTypeRevision version) const;
|
||||||
|
QQmlImportInstance *findImportByLocation(
|
||||||
|
const QString &location, QTypeRevision version) const;
|
||||||
|
|
||||||
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
|
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
|
||||||
QTypeRevision *version_return, QQmlType* type_return,
|
QTypeRevision *version_return, QQmlType* type_return,
|
||||||
|
@ -163,17 +166,19 @@ public:
|
||||||
|
|
||||||
QTypeRevision addFileImport(
|
QTypeRevision addFileImport(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
||||||
QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
|
QTypeRevision requestedVersion, ImportFlags flags, quint16 precedence,
|
||||||
QList<QQmlError> *errors);
|
QString *localQmldir, QList<QQmlError> *errors);
|
||||||
|
|
||||||
QTypeRevision addLibraryImport(
|
QTypeRevision addLibraryImport(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
||||||
QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
|
QTypeRevision requestedVersion, const QString &qmldirIdentifier,
|
||||||
ImportFlags flags, quint16 precedence, QList<QQmlError> *errors);
|
const QString &qmldirUrl, ImportFlags flags, quint16 precedence,
|
||||||
|
QList<QQmlError> *errors);
|
||||||
|
|
||||||
QTypeRevision updateQmldirContent(
|
QTypeRevision updateQmldirContent(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
|
QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
|
||||||
const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
|
const QString &prefix, const QString &qmldirIdentifier, const QString &qmldirUrl,
|
||||||
|
QList<QQmlError> *errors);
|
||||||
|
|
||||||
void populateCache(QQmlTypeNameCache *cache) const;
|
void populateCache(QQmlTypeNameCache *cache) const;
|
||||||
|
|
||||||
|
@ -230,10 +235,6 @@ private:
|
||||||
|
|
||||||
QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
|
QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
|
||||||
|
|
||||||
static QTypeRevision matchingQmldirVersion(
|
|
||||||
const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri,
|
|
||||||
QTypeRevision version, QList<QQmlError> *errors);
|
|
||||||
|
|
||||||
QTypeRevision importExtension(
|
QTypeRevision importExtension(
|
||||||
QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
|
QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
|
||||||
const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
|
const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
|
||||||
|
@ -242,8 +243,7 @@ private:
|
||||||
const QQmlTypeLoaderQmldirContent &qmldir, QTypeRevision version);
|
const QQmlTypeLoaderQmldirContent &qmldir, QTypeRevision version);
|
||||||
|
|
||||||
QString redirectQmldirContent(
|
QString redirectQmldirContent(
|
||||||
QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir,
|
QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir);
|
||||||
QQmlImportInstance *inserted);
|
|
||||||
|
|
||||||
bool getQmldirContent(
|
bool getQmldirContent(
|
||||||
QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
|
QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
|
||||||
|
|
|
@ -831,7 +831,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
|
||||||
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
|
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
|
||||||
|
|
||||||
const QTypeRevision version = m_importCache->updateQmldirContent(
|
const QTypeRevision version = m_importCache->updateQmldirContent(
|
||||||
typeLoader(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors);
|
typeLoader(), import->uri, import->version, import->qualifier, qmldirIdentifier,
|
||||||
|
qmldirUrl, errors);
|
||||||
if (!version.isValid())
|
if (!version.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ qt_internal_add_test(tst_qmlcppcodegen
|
||||||
codegen_test_stringbuilderplugin
|
codegen_test_stringbuilderplugin
|
||||||
confused_test_module
|
confused_test_module
|
||||||
confused_test_moduleplugin
|
confused_test_moduleplugin
|
||||||
|
with_subdir_test_module
|
||||||
|
with_subdir_test_moduleplugin
|
||||||
DEFINES
|
DEFINES
|
||||||
QT_NO_CAST_FROM_ASCII
|
QT_NO_CAST_FROM_ASCII
|
||||||
)
|
)
|
||||||
|
@ -45,6 +47,8 @@ qt_internal_add_test(tst_qmlcppcodegen_interpreted
|
||||||
codegen_test_stringbuilderplugin
|
codegen_test_stringbuilderplugin
|
||||||
confused_test_module
|
confused_test_module
|
||||||
confused_test_moduleplugin
|
confused_test_moduleplugin
|
||||||
|
with_subdir_test_module
|
||||||
|
with_subdir_test_moduleplugin
|
||||||
DEFINES
|
DEFINES
|
||||||
QT_TEST_FORCE_INTERPRETER
|
QT_TEST_FORCE_INTERPRETER
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
add_subdirectory(Confused)
|
add_subdirectory(Confused)
|
||||||
|
add_subdirectory(WithSubDir)
|
||||||
|
|
||||||
set(cpp_sources
|
set(cpp_sources
|
||||||
ambiguous.h
|
ambiguous.h
|
||||||
|
@ -220,6 +221,7 @@ set(qml_files
|
||||||
methods.qml
|
methods.qml
|
||||||
modulePrefix.qml
|
modulePrefix.qml
|
||||||
moveRegVoid.qml
|
moveRegVoid.qml
|
||||||
|
multiRedirect.qml
|
||||||
multiforeign.qml
|
multiforeign.qml
|
||||||
multipleCtors.qml
|
multipleCtors.qml
|
||||||
namespaceWithEnum.qml
|
namespaceWithEnum.qml
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
qt_add_library(with_subdir_test_module STATIC)
|
||||||
|
qt_autogen_tools_initial_setup(with_subdir_test_module)
|
||||||
|
|
||||||
|
qt_policy(SET QTP0001 NEW)
|
||||||
|
qt_policy(SET QTP0004 NEW)
|
||||||
|
|
||||||
|
qt_add_qml_module(with_subdir_test_module
|
||||||
|
URI WithSubDir
|
||||||
|
VERSION 1.0
|
||||||
|
QML_FILES
|
||||||
|
qml/GreenRect.qml
|
||||||
|
qml/MyScript.js
|
||||||
|
|
||||||
|
# Hide it at compile time. Otherwise the "TestTypes" module may see it,
|
||||||
|
# but the "verify" module won't.
|
||||||
|
OUTPUT_DIRECTORY HiddenWithSubdir
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(with_subdir_test_module
|
||||||
|
PRIVATE Qt6::Qml
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_autogen_tools_initial_setup(with_subdir_test_moduleplugin)
|
|
@ -0,0 +1,6 @@
|
||||||
|
import QtQml
|
||||||
|
import WithSubDir
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
objectName: "green"
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
.pragma library
|
||||||
|
function hello() { console.log("World") }
|
|
@ -0,0 +1,7 @@
|
||||||
|
import QtQml
|
||||||
|
import WithSubDir
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
property GreenRect g: GreenRect {}
|
||||||
|
objectName: g.objectName
|
||||||
|
}
|
|
@ -187,6 +187,7 @@ private slots:
|
||||||
void multiDirectory();
|
void multiDirectory();
|
||||||
void multiForeign();
|
void multiForeign();
|
||||||
void multiLookup();
|
void multiLookup();
|
||||||
|
void multiRedirect();
|
||||||
void multipleCtors();
|
void multipleCtors();
|
||||||
void namespaceWithEnum();
|
void namespaceWithEnum();
|
||||||
void noBuiltinsImport();
|
void noBuiltinsImport();
|
||||||
|
@ -3804,6 +3805,18 @@ void tst_QmlCppCodegen::multiLookup()
|
||||||
QCOMPARE(quitSpy.size(), 1);
|
QCOMPARE(quitSpy.size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QmlCppCodegen::multiRedirect()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent component(&engine, QUrl(u"qrc:/qt/qml/TestTypes/multiRedirect.qml"_s));
|
||||||
|
QVERIFY2(!component.isError(), qPrintable(component.errorString()));
|
||||||
|
|
||||||
|
QScopedPointer<QObject> object(component.create());
|
||||||
|
QVERIFY(!object.isNull());
|
||||||
|
|
||||||
|
QCOMPARE(object->objectName(), u"green"_s);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QmlCppCodegen::multipleCtors()
|
void tst_QmlCppCodegen::multipleCtors()
|
||||||
{
|
{
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
|
|
Loading…
Reference in New Issue