QML: Load qmldir-imports also for the implicit import
Since we load plugins and C++ based types, too, we should just load the dependent imports as well. Otherwise this is rather confusing. Fixes: QTBUG-101752 Change-Id: I5bd8afa22e5f16141ef8b47c1a40d3ba8698106c Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
5a57bd47fb
commit
aff516954d
|
@ -248,7 +248,7 @@ public:
|
|||
|
||||
QTypeRevision addFileImport(
|
||||
const QString &uri, const QString &prefix, QTypeRevision version, uint flags,
|
||||
QQmlImportDatabase *database, QList<QQmlError> *errors);
|
||||
QQmlImportDatabase *database, QString *localQmldir, QList<QQmlError> *errors);
|
||||
|
||||
QTypeRevision updateQmldirContent(const QString &uri, const QString &prefix,
|
||||
const QString &qmldirIdentifier, const QString& qmldirUrl,
|
||||
|
@ -1395,7 +1395,7 @@ QTypeRevision QQmlImportsPrivate::addLibraryImport(
|
|||
|
||||
QTypeRevision QQmlImportsPrivate::addFileImport(
|
||||
const QString& uri, const QString &prefix, QTypeRevision version, uint flags,
|
||||
QQmlImportDatabase *database, QList<QQmlError> *errors)
|
||||
QQmlImportDatabase *database, QString *localQmldir, QList<QQmlError> *errors)
|
||||
{
|
||||
if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
|
||||
QQmlError error;
|
||||
|
@ -1446,8 +1446,11 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
|
|||
if (importUri.endsWith(Slash))
|
||||
importUri.chop(1);
|
||||
|
||||
if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty())
|
||||
if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
|
||||
qmldirIdentifier = localFileOrQrc;
|
||||
if (localQmldir)
|
||||
*localQmldir = qmldirIdentifier;
|
||||
}
|
||||
|
||||
} else if (nameSpace->prefix.isEmpty() && !(flags & QQmlImports::ImportIncomplete)) {
|
||||
|
||||
|
@ -1566,7 +1569,8 @@ QTypeRevision QQmlImportsPrivate::updateQmldirContent(const QString &uri, const
|
|||
|
||||
Additionally, this will add the import with lowest instead of highest precedence.
|
||||
*/
|
||||
QTypeRevision QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors)
|
||||
QTypeRevision QQmlImports::addImplicitImport(
|
||||
QQmlImportDatabase *importDb, QString *localQmldir, QList<QQmlError> *errors)
|
||||
{
|
||||
Q_ASSERT(errors);
|
||||
|
||||
|
@ -1574,7 +1578,7 @@ QTypeRevision QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList
|
|||
|
||||
uint flags = ImportImplicit | (!isLocal(baseUrl()) ? ImportIncomplete : 0);
|
||||
return d->addFileImport(QLatin1String("."), QString(), QTypeRevision(), flags,
|
||||
importDb, errors);
|
||||
importDb, localQmldir, errors);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1624,7 +1628,7 @@ QTypeRevision QQmlImports::addFileImport(
|
|||
<< "addFileImport:" << qPrintable(baseUrl().toString())
|
||||
<< uri << version << "as" << prefix;
|
||||
|
||||
return d->addFileImport(uri, prefix, version, flags, importDb, errors);
|
||||
return d->addFileImport(uri, prefix, version, flags, importDb, nullptr, errors);
|
||||
}
|
||||
|
||||
QTypeRevision QQmlImports::addLibraryImport(
|
||||
|
|
|
@ -162,7 +162,7 @@ public:
|
|||
= QQmlType::AnyRegistrationType) const;
|
||||
|
||||
QTypeRevision addImplicitImport(
|
||||
QQmlImportDatabase *importDb, QList<QQmlError> *errors);
|
||||
QQmlImportDatabase *importDb, QString *localQmldir, QList<QQmlError> *errors);
|
||||
|
||||
bool addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType);
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <private/qqmlscriptblob_p.h>
|
||||
#include <private/qqmlscriptdata_p.h>
|
||||
#include <private/qqmltypecompiler_p.h>
|
||||
#include <private/qqmltypeloaderqmldircontent_p.h>
|
||||
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qcryptographichash.h>
|
||||
|
@ -187,7 +188,8 @@ bool QQmlTypeData::tryLoadFromDiskCache()
|
|||
&& !import->version.hasMajorVersion()
|
||||
&& !import->version.hasMinorVersion()) {
|
||||
QList<QQmlError> errors;
|
||||
auto pendingImport = std::make_shared<PendingImport>(this, import);
|
||||
auto pendingImport = std::make_shared<PendingImport>(
|
||||
this, import, QQmlImports::ImportImplicit);
|
||||
if (!fetchQmldir(qmldirUrl, pendingImport, 1, &errors)) {
|
||||
setError(errors);
|
||||
return false;
|
||||
|
@ -556,7 +558,21 @@ bool QQmlTypeData::loadImplicitImport()
|
|||
// This will also trigger the loading of the qmldir and the import of any native
|
||||
// types from available plugins.
|
||||
QList<QQmlError> implicitImportErrors;
|
||||
m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
|
||||
QString localQmldir;
|
||||
m_importCache.addImplicitImport(importDatabase, &localQmldir, &implicitImportErrors);
|
||||
|
||||
// When loading with QQmlImports::ImportImplicit, the imports are _appended_ to the namespace
|
||||
// in the order they are loaded. Therefore, the addImplicitImport above gets the highest
|
||||
// precedence. This is in contrast to normal priority imports. Those are _prepended_ in the
|
||||
// order they are loaded.
|
||||
if (!localQmldir.isEmpty()) {
|
||||
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
|
||||
const QList<QQmlDirParser::Import> moduleImports
|
||||
= QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
|
||||
+ qmldir.imports();
|
||||
loadDependentImports(moduleImports, QString(), QTypeRevision(),
|
||||
QQmlImports::ImportImplicit, &implicitImportErrors);
|
||||
}
|
||||
|
||||
if (!implicitImportErrors.isEmpty()) {
|
||||
setError(implicitImportErrors);
|
||||
|
|
|
@ -481,13 +481,15 @@ void QQmlTypeLoader::shutdownThread()
|
|||
m_thread->shutdown();
|
||||
}
|
||||
|
||||
QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
|
||||
QQmlTypeLoader::Blob::PendingImport::PendingImport(
|
||||
QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import, uint flags)
|
||||
: uri(blob->stringAt(import->uriIndex))
|
||||
, qualifier(blob->stringAt(import->qualifierIndex))
|
||||
, type(static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
|
||||
, location(import->location)
|
||||
, flags(flags)
|
||||
, version(import->version)
|
||||
{
|
||||
type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type));
|
||||
uri = blob->stringAt(import->uriIndex);
|
||||
qualifier = blob->stringAt(import->qualifierIndex);
|
||||
version = import->version;
|
||||
location = import->location;
|
||||
}
|
||||
|
||||
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
|
||||
|
@ -535,7 +537,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
|
|||
if (version.hasMajorVersion())
|
||||
import->version = version;
|
||||
|
||||
if (!loadImportDependencies(import, qmldirIdentifier, errors))
|
||||
if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
|
||||
return false;
|
||||
|
||||
import->priority = 0;
|
||||
|
@ -563,11 +565,11 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
|
|||
bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, uint flags,
|
||||
QList<QQmlError> *errors)
|
||||
{
|
||||
return addImport(std::make_shared<PendingImport>(this, import), flags, errors);
|
||||
return addImport(std::make_shared<PendingImport>(this, import, flags), errors);
|
||||
}
|
||||
|
||||
bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr import, uint flags,
|
||||
QList<QQmlError> *errors)
|
||||
bool QQmlTypeLoader::Blob::addImport(
|
||||
QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
|
||||
{
|
||||
Q_ASSERT(errors);
|
||||
|
||||
|
@ -592,7 +594,7 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
// This is a local library import
|
||||
const QTypeRevision actualVersion = m_importCache.addLibraryImport(
|
||||
importDatabase, import->uri, import->qualifier,
|
||||
import->version, qmldirFilePath, qmldirUrl, flags, errors);
|
||||
import->version, qmldirFilePath, qmldirUrl, import->flags, errors);
|
||||
if (!actualVersion.isValid())
|
||||
return false;
|
||||
|
||||
|
@ -600,7 +602,12 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
if (actualVersion.hasMajorVersion())
|
||||
import->version = actualVersion;
|
||||
|
||||
if (!loadImportDependencies(import, qmldirFilePath, errors))
|
||||
if (!loadImportDependencies(
|
||||
import, qmldirFilePath,
|
||||
(import->flags & QQmlImports::ImportImplicit)
|
||||
? QQmlImports::ImportImplicit
|
||||
: QQmlImports::ImportLowPrecedence,
|
||||
errors))
|
||||
return false;
|
||||
|
||||
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
|
||||
|
@ -652,7 +659,7 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
|
||||
if (!m_importCache.addLibraryImport(
|
||||
importDatabase, import->uri, import->qualifier, import->version,
|
||||
QString(), QString(), flags, errors).isValid()) {
|
||||
QString(), QString(), import->flags, errors).isValid()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -672,7 +679,8 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
// Add this library and request the possible locations for it
|
||||
const QTypeRevision version = m_importCache.addLibraryImport(
|
||||
importDatabase, import->uri, import->qualifier, import->version,
|
||||
QString(), QString(), flags | QQmlImports::ImportIncomplete, errors);
|
||||
QString(), QString(), import->flags | QQmlImports::ImportIncomplete,
|
||||
errors);
|
||||
|
||||
if (!version.isValid())
|
||||
return false;
|
||||
|
@ -704,7 +712,7 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
} else {
|
||||
Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile);
|
||||
|
||||
bool incomplete = false;
|
||||
uint flags = 0;
|
||||
|
||||
QUrl importUrl(import->uri);
|
||||
QString path = importUrl.path();
|
||||
|
@ -713,11 +721,11 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
QUrl qmldirUrl = finalUrl().resolved(importUrl);
|
||||
if (!QQmlImports::isLocal(qmldirUrl)) {
|
||||
// This is a remote file; the import is currently incomplete
|
||||
incomplete = true;
|
||||
flags = QQmlImports::ImportIncomplete;
|
||||
}
|
||||
|
||||
const QTypeRevision version = m_importCache.addFileImport(
|
||||
importDatabase, import->uri, import->qualifier, import->version, incomplete,
|
||||
importDatabase, import->uri, import->qualifier, import->version, flags,
|
||||
errors);
|
||||
if (!version.isValid())
|
||||
return false;
|
||||
|
@ -726,7 +734,7 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
if (version.hasMajorVersion())
|
||||
import->version = version;
|
||||
|
||||
if (incomplete) {
|
||||
if (flags & QQmlImports::ImportIncomplete) {
|
||||
if (!fetchQmldir(qmldirUrl, import, 1, errors))
|
||||
return false;
|
||||
}
|
||||
|
@ -753,31 +761,60 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
|
|||
}
|
||||
}
|
||||
|
||||
bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors)
|
||||
bool QQmlTypeLoader::Blob::loadDependentImports(
|
||||
const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
|
||||
QTypeRevision version, uint flags, QList<QQmlError> *errors)
|
||||
{
|
||||
for (const auto &import : imports) {
|
||||
if (import.flags & QQmlDirParser::Import::Optional)
|
||||
continue;
|
||||
auto dependencyImport = std::make_shared<PendingImport>();
|
||||
dependencyImport->uri = import.module;
|
||||
dependencyImport->qualifier = qualifier;
|
||||
dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
|
||||
? version : import.version;
|
||||
dependencyImport->flags = flags;
|
||||
|
||||
qCDebug(lcQmlImport)
|
||||
<< "loading dependent import" << dependencyImport->uri << "version"
|
||||
<< dependencyImport->version << "as" << dependencyImport->qualifier;
|
||||
|
||||
if (!addImport(dependencyImport, errors)) {
|
||||
QQmlError error;
|
||||
error.setDescription(
|
||||
QString::fromLatin1(
|
||||
"Failed to load dependent import \"%1\" version %2.%3")
|
||||
.arg(dependencyImport->uri)
|
||||
.arg(dependencyImport->version.majorVersion())
|
||||
.arg(dependencyImport->version.minorVersion()));
|
||||
errors->append(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QQmlTypeLoader::Blob::loadImportDependencies(
|
||||
PendingImportPtr currentImport, const QString &qmldirUri, uint flags,
|
||||
QList<QQmlError> *errors)
|
||||
{
|
||||
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
|
||||
const QList<QQmlDirParser::Import> implicitImports
|
||||
= QQmlMetaType::moduleImports(currentImport->uri, currentImport->version)
|
||||
+ qmldir.imports();
|
||||
for (const auto &implicitImport : implicitImports) {
|
||||
if (implicitImport.flags & QQmlDirParser::Import::Optional)
|
||||
continue;
|
||||
auto dependencyImport = std::make_shared<PendingImport>();
|
||||
dependencyImport->uri = implicitImport.module;
|
||||
dependencyImport->qualifier = currentImport->qualifier;
|
||||
dependencyImport->version = (implicitImport.flags & QQmlDirParser::Import::Auto)
|
||||
? currentImport->version : implicitImport.version;
|
||||
if (!addImport(dependencyImport, QQmlImports::ImportLowPrecedence, errors)) {
|
||||
QQmlError error;
|
||||
error.setDescription(
|
||||
QString::fromLatin1(
|
||||
"Failed to load dependencies for module \"%1\" version %2.%3")
|
||||
.arg(currentImport->uri)
|
||||
.arg(currentImport->version.majorVersion())
|
||||
.arg(currentImport->version.minorVersion()));
|
||||
errors->append(error);
|
||||
return false;
|
||||
}
|
||||
if (!loadDependentImports(
|
||||
implicitImports, currentImport->qualifier, currentImport->version,
|
||||
flags, errors)) {
|
||||
QQmlError error;
|
||||
error.setDescription(
|
||||
QString::fromLatin1(
|
||||
"Failed to load dependencies for module \"%1\" version %2.%3")
|
||||
.arg(currentImport->uri)
|
||||
.arg(currentImport->version.majorVersion())
|
||||
.arg(currentImport->version.minorVersion()));
|
||||
errors->append(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -93,26 +93,27 @@ public:
|
|||
|
||||
struct PendingImport
|
||||
{
|
||||
QV4::CompiledData::Import::ImportType type = QV4::CompiledData::Import::ImportType::ImportLibrary;
|
||||
|
||||
QString uri;
|
||||
QString qualifier;
|
||||
|
||||
QTypeRevision version;
|
||||
|
||||
QV4::CompiledData::Import::ImportType type
|
||||
= QV4::CompiledData::Import::ImportType::ImportLibrary;
|
||||
QV4::CompiledData::Location location;
|
||||
|
||||
uint flags = 0;
|
||||
int priority = 0;
|
||||
|
||||
QTypeRevision version;
|
||||
|
||||
PendingImport() = default;
|
||||
PendingImport(Blob *blob, const QV4::CompiledData::Import *import);
|
||||
PendingImport(Blob *blob, const QV4::CompiledData::Import *import, uint flags);
|
||||
};
|
||||
using PendingImportPtr = std::shared_ptr<PendingImport>;
|
||||
|
||||
protected:
|
||||
bool addImport(const QV4::CompiledData::Import *import, uint flags,
|
||||
QList<QQmlError> *errors);
|
||||
bool addImport(PendingImportPtr import, uint flags, QList<QQmlError> *errors);
|
||||
bool addImport(PendingImportPtr import, QList<QQmlError> *errors);
|
||||
|
||||
bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors);
|
||||
bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors);
|
||||
|
@ -124,9 +125,14 @@ public:
|
|||
|
||||
void dependencyComplete(QQmlDataBlob *) override;
|
||||
|
||||
bool loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors);
|
||||
bool loadImportDependencies(
|
||||
PendingImportPtr currentImport, const QString &qmldirUri, uint flags,
|
||||
QList<QQmlError> *errors);
|
||||
|
||||
protected:
|
||||
bool loadDependentImports(
|
||||
const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
|
||||
QTypeRevision version, uint flags, QList<QQmlError> *errors);
|
||||
virtual QString stringAt(int) const { return QString(); }
|
||||
|
||||
bool isDebugging() const;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import QtQml
|
||||
Rectangle { // from the implicit import itself, taking precedence over its dependencies
|
||||
Item {} // from a dependency of the implicit import
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import QtQml
|
||||
Item {
|
||||
objectName: "notARectangle"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
module Something
|
||||
import QtQuick
|
||||
A 1.0 A.qml
|
||||
Rectangle 1.0 B.qml
|
|
@ -62,6 +62,7 @@ private slots:
|
|||
void preferResourcePath();
|
||||
void invalidFileImport_data();
|
||||
void invalidFileImport();
|
||||
void implicitWithDependencies();
|
||||
};
|
||||
|
||||
void tst_QQmlImport::cleanup()
|
||||
|
@ -137,6 +138,16 @@ void tst_QQmlImport::invalidFileImport()
|
|||
"but not absolute paths or resource paths.").arg(import)));
|
||||
}
|
||||
|
||||
void tst_QQmlImport::implicitWithDependencies()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine, testFileUrl("implicitWithDependencies/A.qml"));
|
||||
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
|
||||
QScopedPointer<QObject> o(component.create());
|
||||
QVERIFY(!o.isNull());
|
||||
QCOMPARE(o->objectName(), QStringLiteral("notARectangle"));
|
||||
}
|
||||
|
||||
void tst_QQmlImport::testDesignerSupported()
|
||||
{
|
||||
QQuickView *window = new QQuickView();
|
||||
|
|
Loading…
Reference in New Issue