aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp2
-rw-r--r--src/qml/compiler/qv4compileddata_p.h3
-rw-r--r--src/qml/jsruntime/qv4engine.cpp24
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4script.cpp18
-rw-r--r--src/qml/qml/qqmldirparser.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp19
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp146
-rw-r--r--src/qml/qml/qqmltypeloader_p.h1
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.1.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.2.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp33
19 files changed, 215 insertions, 72 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index ed3b55c2c6..624e3c42e7 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -619,7 +619,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
if (!node->fileName.isNull()) {
uri = node->fileName.toString();
- if (uri.endsWith(QLatin1String(".js"))) {
+ if (uri.endsWith(QLatin1String(".js")) || uri.endsWith(QLatin1String(".mjs"))) {
import->type = QV4::CompiledData::Import::ImportScript;
} else {
import->type = QV4::CompiledData::Import::ImportFile;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index f0043cc6af..4e71bd5c27 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -822,7 +822,8 @@ struct Unit
StaticData = 0x2, // Unit data persistent in memory?
IsSingleton = 0x4,
IsSharedLibrary = 0x8, // .pragma shared?
- PendingTypeCompilation = 0x10 // the QML data structures present are incomplete and require type compilation
+ IsESModule = 0x10,
+ PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
};
quint32_le flags;
quint32_le stringTableSize;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 90c75b204d..14bc5f084e 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1682,6 +1682,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(boo
using namespace QV4::Compiler;
Compiler::Module compilerModule(debugMode);
+ compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
JSUnitGenerator jsGenerator(&compilerModule);
Codegen cg(&jsGenerator, /*strictMode*/true);
cg.generateFromModule(url.fileName(), url.toString(), sourceCode, moduleNode, &compilerModule);
@@ -1697,22 +1698,43 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(boo
void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit)
{
+ // Injection can happen from the QML type loader thread for example, but instantiation and
+ // evaluation must be limited to the ExecutionEngine's thread.
+ QMutexLocker moduleGuard(&moduleMutex);
modules.insert(moduleUnit->finalUrl(), moduleUnit);
}
+QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer) const
+{
+ QUrl url = QQmlTypeLoader::normalize(_url);
+ if (referrer)
+ url = referrer->finalUrl().resolved(url);
+
+ QMutexLocker moduleGuard(&moduleMutex);
+ auto existingModule = modules.find(url);
+ if (existingModule == modules.end())
+ return nullptr;
+ return *existingModule;
+}
+
QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer)
{
QUrl url = QQmlTypeLoader::normalize(_url);
if (referrer)
url = referrer->finalUrl().resolved(url);
+ QMutexLocker moduleGuard(&moduleMutex);
auto existingModule = modules.find(url);
if (existingModule != modules.end())
return *existingModule;
+ moduleGuard.unlock();
+
auto newModule = compileModule(url);
- if (newModule)
+ if (newModule) {
+ moduleGuard.relock();
modules.insert(url, newModule);
+ }
return newModule;
}
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 4cd7e40013..8312adee48 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -580,8 +580,10 @@ public:
QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url, const QString &sourceCode);
static QQmlRefPointer<CompiledData::CompilationUnit> compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList<QQmlJS::DiagnosticMessage> *diagnostics);
+ mutable QMutex moduleMutex;
QHash<QUrl, QQmlRefPointer<CompiledData::CompilationUnit>> modules;
void injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit);
+ QQmlRefPointer<CompiledData::CompilationUnit> moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const;
QQmlRefPointer<CompiledData::CompilationUnit> loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr);
#endif
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 37c4f27ca9..070c048c8f 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -185,23 +185,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
parser.parseProgram();
- QList<QQmlError> errors;
-
- const auto diagnosticMessages = parser.diagnosticMessages();
- for (const DiagnosticMessage &m : diagnosticMessages) {
- if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
- continue;
- }
-
- QQmlError error;
- error.setUrl(QUrl(fileName));
- error.setDescription(m.message);
- error.setLine(m.loc.startLine);
- error.setColumn(m.loc.startColumn);
- errors << error;
- }
-
+ QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(fileName, parser.diagnosticMessages());
if (!errors.isEmpty()) {
if (reportedErrors)
*reportedErrors << errors;
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 8c89cf0e61..d87bf433b8 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -272,7 +272,7 @@ bool QQmlDirParser::parse(const QString &source)
if (parseVersion(sections[1], &major, &minor)) {
const QString &fileName = sections[2];
- if (fileName.endsWith(QLatin1String(".js"))) {
+ if (fileName.endsWith(QLatin1String(".js")) || fileName.endsWith(QLatin1String(".mjs"))) {
// A 'js' extension indicates a namespaced script import
const Script entry(sections[0], fileName, major, minor);
_scripts.append(entry);
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 119120572c..e487aec4ab 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -2106,6 +2106,25 @@ void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError
dumpwarning(error);
}
+QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileName, const QList<DiagnosticMessage> &diagnosticMessages)
+{
+ QList<QQmlError> errors;
+ for (const DiagnosticMessage &m : diagnosticMessages) {
+ if (m.isWarning()) {
+ qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
+ continue;
+ }
+
+ QQmlError error;
+ error.setUrl(QUrl(fileName));
+ error.setDescription(m.message);
+ error.setLine(m.loc.startLine);
+ error.setColumn(m.loc.startColumn);
+ errors << error;
+ }
+ return errors;
+}
+
void QQmlEnginePrivate::cleanupScarceResources()
{
// iterate through the list and release them all.
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index da52e01793..f606896953 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -245,6 +245,8 @@ public:
inline static QQmlEngine *get(QQmlEnginePrivate *p);
inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
+ static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
+
static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
static void defineQtQuick2Module();
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 2aa64f350a..daa4604dca 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -51,6 +51,7 @@
#include <private/qqmltypecompiler_p.h>
#include <private/qqmlpropertyvalidator_p.h>
#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qv4module_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
@@ -2855,8 +2856,19 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
return m_value.value();
Q_ASSERT(parentCtxt && parentCtxt->engine);
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
QV4::ExecutionEngine *v4 = parentCtxt->engine->handle();
+
+ if (m_precompiledScript->unitData()->flags & QV4::CompiledData::Unit::IsESModule) {
+ m_loaded = true;
+
+ m_value.set(v4, m_precompiledScript->instantiate(v4));
+ if (!m_value.isNullOrUndefined())
+ m_precompiledScript->evaluate();
+
+ return m_value.value();
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
QV4::Scope scope(v4);
bool shared = m_precompiledScript->unitData()->flags & QV4::CompiledData::Unit::IsSharedLibrary;
@@ -2945,7 +2957,8 @@ void QQmlScriptData::clear()
}
QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
+ : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
+ , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
{
}
@@ -2979,9 +2992,6 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
return;
}
- QmlIR::Document irUnit(isDebugging());
-
- irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
QString error;
QString source = data.readAll(&error);
if (!error.isEmpty()) {
@@ -2989,31 +2999,47 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
return;
}
- QmlIR::ScriptDirectivesCollector collector(&irUnit);
- irUnit.jsParserEngine.setDirectives(&collector);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
- QList<QQmlError> errors;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(
- &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
- source, &errors);
- // No need to addref on unit, it's initial refcount is 1
- source.clear();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- if (!unit) {
- unit.adopt(new QV4::CompiledData::CompilationUnit);
- }
- irUnit.javaScriptCompilationUnit = unit;
+ if (m_isModule) {
+ QList<QQmlJS::DiagnosticMessage> diagnostics;
+ unit = QV4::ExecutionEngine::compileModule(isDebugging(), url(), source, &diagnostics);
+ QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ } else {
+ QmlIR::Document irUnit(isDebugging());
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(irUnit);
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
- if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) {
- QString errorString;
- if (!unit->saveToDisk(url(), &errorString)) {
- qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString;
+ QmlIR::ScriptDirectivesCollector collector(&irUnit);
+ irUnit.jsParserEngine.setDirectives(&collector);
+
+ QList<QQmlError> errors;
+ unit = QV4::Script::precompile(
+ &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors);
+ // No need to addref on unit, it's initial refcount is 1
+ source.clear();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ if (!unit) {
+ unit.adopt(new QV4::CompiledData::CompilationUnit);
+ }
+ irUnit.javaScriptCompilationUnit = unit;
+
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ qmlGenerator.generate(irUnit);
+
+ if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) {
+ QString errorString;
+ if (!unit->saveToDisk(url(), &errorString)) {
+ qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString;
+ }
}
}
@@ -3049,26 +3075,28 @@ void QQmlScriptBlob::done()
}
}
- m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
+ if (!m_isModule) {
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
- QSet<QString> ns;
+ QSet<QString> ns;
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const ScriptReference &script = m_scripts.at(scriptIndex);
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const ScriptReference &script = m_scripts.at(scriptIndex);
- m_scriptData->scripts.append(script.script);
+ m_scriptData->scripts.append(script.script);
- if (!script.nameSpace.isNull()) {
- if (!ns.contains(script.nameSpace)) {
- ns.insert(script.nameSpace);
- m_scriptData->typeNameCache->add(script.nameSpace);
+ if (!script.nameSpace.isNull()) {
+ if (!ns.contains(script.nameSpace)) {
+ ns.insert(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
+ }
}
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
+
+ m_importCache.populateCache(m_scriptData->typeNameCache);
}
m_scripts.clear();
-
- m_importCache.populateCache(m_scriptData->typeNameCache);
}
QString QQmlScriptBlob::stringAt(int index) const
@@ -3099,20 +3127,36 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Com
QQmlRefPointer<QV4::CompiledData::CompilationUnit> script = m_scriptData->m_precompiledScript;
- QList<QQmlError> errors;
- for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = script->importAt(i);
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
+ if (!m_isModule) {
+ QList<QQmlError> errors;
+ for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = script->importAt(i);
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return;
+ }
}
}
+
+ auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+
+ v4->injectModule(unit);
+
+ for (const QString &request: unit->moduleRequests()) {
+ if (v4->moduleForUrl(QUrl(request), unit.data()))
+ continue;
+
+ const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
+ addDependency(blob.data());
+ scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
+ }
}
QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 98ac4b1bc1..26090c6af7 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -589,6 +589,7 @@ private:
QList<ScriptReference> m_scripts;
QQmlRefPointer<QQmlScriptData> m_scriptData;
+ const bool m_isModule;
};
class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs
new file mode 100644
index 0000000000..c17a351216
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs
@@ -0,0 +1,4 @@
+
+export function ok() {
+ return true;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml
new file mode 100644
index 0000000000..cc988a6114
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "importJsModule.1.mjs" as JSModule
+
+Item {
+ property bool test: JSModule.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml
new file mode 100644
index 0000000000..0799585622
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import org.qtproject.PureESJsModule 1.0
+
+Item {
+ property bool test: ModuleAPI.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs
new file mode 100644
index 0000000000..41d2f391bf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs
@@ -0,0 +1,4 @@
+
+import { indirectOk } from "./importJsModule.3.mjs";
+
+export function ok() { return indirectOk(); }
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs
new file mode 100644
index 0000000000..3623dc6f4f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs
@@ -0,0 +1,4 @@
+export function indirectOk() { return true; }
+
+export * from "./importJsModule.3.indirect.mjs";
+
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml
new file mode 100644
index 0000000000..3b187205c7
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "importJsModule.3.mjs" as JSModule
+
+Item {
+ property bool test: JSModule.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs
new file mode 100644
index 0000000000..c17a351216
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs
@@ -0,0 +1,4 @@
+
+export function ok() {
+ return true;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir
new file mode 100644
index 0000000000..59b4740f75
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir
@@ -0,0 +1 @@
+ModuleAPI 1.0 API.mjs
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index f98233f153..97727c1794 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -39,6 +39,7 @@
#include <QQmlFileSelector>
#include <QFileSelector>
#include <QEasingCurve>
+#include <QScopeGuard>
#include <private/qqmlproperty_p.h>
#include <private/qqmlmetatype_p.h>
@@ -182,6 +183,8 @@ private slots:
void importIncorrectCase();
void importJs_data();
void importJs();
+ void importJsModule_data();
+ void importJsModule();
void explicitSelfImport();
void importInternalType();
@@ -3125,6 +3128,36 @@ void tst_qqmllanguage::importJs()
engine.setImportPathList(defaultImportPathList);
}
+void tst_qqmllanguage::importJsModule_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QTest::newRow("plainImport")
+ << "importJsModule.1.qml";
+
+ QTest::newRow("ImportQmlStyle")
+ << "importJsModule.2.qml";
+
+ QTest::newRow("plainImportWithCycle")
+ << "importJsModule.3.qml";
+}
+
+void tst_qqmllanguage::importJsModule()
+{
+ QFETCH(QString, file);
+
+ engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));
+ auto importPathGuard = qScopeGuard([this]{
+ engine.setImportPathList(defaultImportPathList);
+ });
+
+ QQmlComponent component(&engine, testFileUrl(file));
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QCOMPARE(object->property("test").toBool(),true);
+}
+
void tst_qqmllanguage::explicitSelfImport()
{
engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));