Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Ensure JS files imported inside modules work correctly
When a module exports functionality provided by a script, ensure
that imported script modules inside that script resolve correctly.

Task-number: QTBUG-24596
Change-Id: I3885dcc56946423f0d7cf00afdcdfaa0cb11967a
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
  • Loading branch information
Matthew Vogt authored and Qt by Nokia committed Mar 19, 2012
1 parent 601c738 commit c5cd60a
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 22 deletions.
14 changes: 14 additions & 0 deletions src/qml/qml/qqmldirparser.cpp
Expand Up @@ -295,4 +295,18 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
}
#endif

QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
{
return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName)
.arg(component.majorVersion)
.arg(component.minorVersion));
}

QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script)
{
return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace)
.arg(script.majorVersion)
.arg(script.minorVersion));
}

QT_END_NAMESPACE
3 changes: 3 additions & 0 deletions src/qml/qml/qqmldirparser_p.h
Expand Up @@ -55,6 +55,7 @@

#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>

QT_BEGIN_NAMESPACE

Expand Down Expand Up @@ -160,6 +161,8 @@ class QQmlDirParser
typedef QList<QQmlDirParser::Component> QQmlDirComponents;
typedef QList<QQmlDirParser::Script> QQmlDirScripts;

QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
QDebug &operator<< (QDebug &, const QQmlDirParser::Script &);

QT_END_NAMESPACE

Expand Down
28 changes: 15 additions & 13 deletions src/qml/qml/qqmlimport.cpp
Expand Up @@ -117,7 +117,7 @@ class QQmlImportsPrivate {
QList<QQmlError> *errors);

QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
bool add(const QQmlDirComponents &qmldircomponentsnetwork,
QString add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors);
Expand Down Expand Up @@ -493,7 +493,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}

bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors)
Expand Down Expand Up @@ -540,7 +540,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
Expand All @@ -564,7 +564,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
Expand All @@ -586,7 +586,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(absolutePath).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
Expand All @@ -604,7 +604,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
errors->prepend(error);
}
return false;
return QString();
}
} else {
if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) {
Expand All @@ -619,14 +619,14 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
return false; // local import dirs must exist
return QString(); // local import dirs must exist
}
uri = resolvedUri(dir, database);
if (uri.endsWith(Slash))
uri.chop(1);
if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors))
return false;
return QString();
}
} else {
if (prefix.isEmpty()) {
Expand All @@ -642,7 +642,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
return false;
return QString();
}
}
}
Expand All @@ -669,7 +669,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
errors->prepend(error);
}
return false;
return QString();
}
}

Expand All @@ -686,7 +686,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
errors->prepend(error);
return false;
return QString();
}
}

Expand Down Expand Up @@ -716,7 +716,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,

s->imports.prepend(data);

return true;
return data.url;
}

bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
Expand Down Expand Up @@ -874,9 +874,11 @@ QQmlImportDatabase::~QQmlImportDatabase()
The \a prefix may be empty, in which case the import location is considered for
unqualified types.
Returns the resolved URL of the import on success.
The base URL must already have been set with Import::setBaseUrl().
*/
bool QQmlImports::addImport(QQmlImportDatabase *importDb,
QString QQmlImports::addImport(QQmlImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
Expand Down
2 changes: 1 addition & 1 deletion src/qml/qml/qqmlimport_p.h
Expand Up @@ -93,7 +93,7 @@ class Q_QML_EXPORT QQmlImports
QQmlType** type_return, QString* url_return,
int *version_major, int *version_minor) const;

bool addImport(QQmlImportDatabase *,
QString addImport(QQmlImportDatabase *,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
Expand Down
41 changes: 33 additions & 8 deletions src/qml/qml/qqmltypeloader.cpp
Expand Up @@ -1558,7 +1558,6 @@ void QQmlTypeData::dataReceived(const QByteArray &data)
ref.qualifier = import.qualifier;
ref.script = blob;
m_scripts << ref;

}
}

Expand Down Expand Up @@ -1657,8 +1656,8 @@ void QQmlTypeData::resolveTypes()
import.extractVersion(&vmaj, &vmin);

QList<QQmlError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
if (m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, qmldircomponentsnetwork, &errors).isNull()) {
QQmlError error;
if (errors.size()) {
error = errors.takeFirst();
Expand Down Expand Up @@ -1859,8 +1858,9 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
import.extractVersion(&vmaj, &vmin);

QList<QQmlError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, QQmlDirComponents(), &errors)) {
QString importUrl = m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, QQmlDirComponents(), &errors);
if (importUrl.isNull()) {
QQmlError error = errors.takeFirst();
// description should be set by addImport().
error.setUrl(m_imports.baseUrl());
Expand All @@ -1871,6 +1871,22 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
setError(errors);
return;
}

// Does this library contain any scripts?
QUrl libraryUrl(importUrl);
const QQmlDirParser *dirParser = typeLoader()->qmlDirParser(libraryUrl.path() + QLatin1String("qmldir"));
foreach (const QQmlDirParser::Script &script, dirParser->scripts()) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);

ScriptReference ref;
ref.location = import.location.start;
ref.qualifier = script.nameSpace;
ref.nameSpace = import.qualifier;
ref.script = blob;
m_scripts << ref;
}
}
}
}
Expand Down Expand Up @@ -1902,11 +1918,20 @@ void QQmlScriptBlob::done()
m_scriptData->urlString = finalUrlString();
m_scriptData->importCache = new QQmlTypeNameCache();

for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
QSet<QString> ns;

for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);

m_scriptData->scripts.append(script.script);
m_scriptData->importCache->add(script.qualifier, ii);

if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
ns.insert(script.nameSpace);
m_scriptData->importCache->add(script.nameSpace);
}
}
m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
}

m_imports.populateCache(m_scriptData->importCache, engine);
Expand Down
1 change: 1 addition & 0 deletions src/qml/qml/qqmltypeloader_p.h
Expand Up @@ -390,6 +390,7 @@ class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlDataBlob

QQmlScript::Location location;
QString qualifier;
QString nameSpace;
QQmlScriptBlob *script;
};

Expand Down
13 changes: 13 additions & 0 deletions tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
@@ -0,0 +1,13 @@
import QtQuick 2.0

import com.nokia.JsModule 1.0
import com.nokia.JsModule 1.0 as RenamedModule
import "testJsModuleImport.js" as TestJsModuleImport

QtObject {
id: testQtObject

property string importedScriptStringValue: ScriptAPI.greeting();
property string renamedScriptStringValue: RenamedModule.ScriptAPI.greeting();
property string reimportedScriptStringValue: TestJsModuleImport.importedValue();
}
@@ -0,0 +1,5 @@
.import com.nokia.JsModule 1.0 as JsModule

function importedValue() {
return JsModule.ScriptAPI.greeting();
}
@@ -0,0 +1,5 @@
var major = 1
var minor = 0

function greeting() { return "Hello" }

@@ -0,0 +1 @@
ScriptAPI 1.0 ScriptAPI.js
14 changes: 14 additions & 0 deletions tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
Expand Up @@ -254,6 +254,9 @@ void tst_qqmlecmascript::initTestCase()
{
QQmlDataTest::initTestCase();
registerTypes();

QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
engine.addImportPath(dataDir);
}

void tst_qqmlecmascript::assignBasicTypes()
Expand Down Expand Up @@ -3298,6 +3301,17 @@ void tst_qqmlecmascript::importScripts_data()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
<< (QVariantList() << QVariant(20));

QTest::newRow("import module which exports a script")
<< testFileUrl("jsimport/testJsImport.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("importedScriptStringValue")
<< QLatin1String("renamedScriptStringValue")
<< QLatin1String("reimportedScriptStringValue"))
<< (QVariantList() << QVariant(QString("Hello"))
<< QVariant(QString("Hello"))
<< QVariant(QString("Hello")));
}

void tst_qqmlecmascript::importScripts()
Expand Down

0 comments on commit c5cd60a

Please sign in to comment.