Clean up file/error handling in the type loader

Fold the functionality of reading QFile contents via QQmlFile into
QQmlDataBlob::Data. This reduces the dependency on QQmlFile - which is
scheduled for removal - and it makes it possible in the future to avoid
reading the file altogether if we have a cached compilation unit on
disk.

Change-Id: Ieeaf52b6fb1d25665cd3c3b196819e25aba3dd15
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Simon Hausmann 2016-06-17 13:21:07 +02:00
parent 8a33d37006
commit 156d10e165
5 changed files with 62 additions and 66 deletions

View File

@ -445,6 +445,14 @@ void QQmlDataBlob::setError(const QQmlCompileError &error)
setError(e);
}
void QQmlDataBlob::setError(const QString &description)
{
QQmlError e;
e.setDescription(description);
e.setUrl(finalUrl());
setError(e);
}
/*!
Wait for \a blob to become complete or to error. If \a blob is already
complete or in error, or this blob is already complete, this has no effect.
@ -1091,13 +1099,9 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
QML_MEMORY_SCOPE_URL(blob->m_url);
if (QQmlFile::isSynchronous(blob->m_url)) {
QQmlFile file(m_engine, blob->m_url);
if (file.isError()) {
QQmlError error;
error.setUrl(blob->m_url);
error.setDescription(file.error());
blob->setError(error);
const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
if (!QQml_isFileCaseCorrect(fileName)) {
blob->setError(QLatin1String("File name case mismatch"));
return;
}
@ -1105,7 +1109,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, 1.);
setData(blob, &file);
setData(blob, fileName);
} else {
#ifndef QT_NO_NETWORK
@ -1225,11 +1229,11 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
setData(blob, d);
}
void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::Data d;
d.d = file;
d.d = &fileName;
setData(blob, d);
}
@ -2122,11 +2126,7 @@ void QQmlTypeData::done()
QQmlType *type = QQmlMetaType::qmlType(url(), true);
if (!isError() && type && type->isCompositeSingleton() && !m_isSingleton) {
QString typeName = type->qmlTypeName();
QQmlError error;
error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
error.setUrl(finalUrl());
setError(error);
setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
}
// Compile component
@ -2170,7 +2170,12 @@ bool QQmlTypeData::loadImplicitImport()
void QQmlTypeData::dataReceived(const Data &data)
{
QString code = QString::fromUtf8(data.data(), data.size());
QString error;
QString code = QString::fromUtf8(data.readAll(&error));
if (!error.isEmpty()) {
setError(error);
return;
}
QQmlEngine *qmlEngine = typeLoader()->engine();
m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
@ -2699,7 +2704,12 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit
void QQmlScriptBlob::dataReceived(const Data &data)
{
QString source = QString::fromUtf8(data.data(), data.size());
QString error;
QString source = QString::fromUtf8(data.readAll(&error));
if (!error.isEmpty()) {
setError(error);
return;
}
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
QmlIR::Document irUnit(v4->debugger != 0);
@ -2854,7 +2864,12 @@ void QQmlQmldirData::setPriority(int priority)
void QQmlQmldirData::dataReceived(const Data &data)
{
m_content = QString::fromUtf8(data.data(), data.size());
QString error;
m_content = QString::fromUtf8(data.readAll(&error));
if (!error.isEmpty()) {
setError(error);
return;
}
}
void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
@ -2862,6 +2877,26 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
Q_UNIMPLEMENTED();
}
QByteArray QQmlDataBlob::Data::readAll(QString *error) const
{
Q_ASSERT(!d.isNull());
error->clear();
if (d.isT1()) {
return *d.asT1();
}
QFile f(*d.asT2());
if (!f.open(QIODevice::ReadOnly)) {
*error = f.errorString();
return QByteArray();
}
QByteArray data(f.size(), Qt::Uninitialized);
if (f.read(data.data(), data.length()) != data.length()) {
*error = f.errorString();
return QByteArray();
}
return data;
}
QT_END_NAMESPACE
#include "qqmltypeloader.moc"

View File

@ -131,21 +131,14 @@ public:
class Data {
public:
inline const char *data() const;
inline int size() const;
inline QByteArray asByteArray() const;
inline bool isFile() const;
inline QQmlFile *asFile() const;
QByteArray readAll(QString *error) const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
inline Data();
Data(const Data &);
Data &operator=(const Data &);
QBiPointer<const QByteArray, QQmlFile> d;
QBiPointer<const QByteArray, const QString> d;
};
protected:
@ -153,6 +146,7 @@ protected:
void setError(const QQmlError &);
void setError(const QList<QQmlError> &errors);
void setError(const QQmlCompileError &error);
void setError(const QString &description);
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
@ -342,7 +336,7 @@ private:
#endif
void setData(QQmlDataBlob *, const QByteArray &);
void setData(QQmlDataBlob *, QQmlFile *);
void setData(QQmlDataBlob *, const QString &fileName);
void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
@ -582,40 +576,7 @@ QQmlDataBlob::Data::Data()
{
}
const char *QQmlDataBlob::Data::data() const
{
Q_ASSERT(!d.isNull());
if (d.isT1()) return d.asT1()->constData();
else return d.asT2()->data();
}
int QQmlDataBlob::Data::size() const
{
Q_ASSERT(!d.isNull());
if (d.isT1()) return d.asT1()->size();
else return d.asT2()->size();
}
bool QQmlDataBlob::Data::isFile() const
{
return d.isT2();
}
QByteArray QQmlDataBlob::Data::asByteArray() const
{
Q_ASSERT(!d.isNull());
if (d.isT1()) return *d.asT1();
else return d.asT2()->dataByteArray();
}
QQmlFile *QQmlDataBlob::Data::asFile() const
{
if (d.isT2()) return d.asT2();
else return 0;
}
QT_END_NAMESPACE

View File

@ -1,2 +1,2 @@
3:1:Type RegisteredCompositeType2 unavailable
-1:-1:File not found
-1:-1:No such file or directory

View File

@ -2898,7 +2898,7 @@ void tst_qqmllanguage::importIncorrectCase()
QCOMPARE(errors.count(), 1);
const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ?
QStringLiteral("File not found") :
QStringLiteral("No such file or directory") :
QStringLiteral("File name case mismatch");
QCOMPARE(errors.at(0).description(), expectedError);

View File

@ -213,7 +213,7 @@ void tst_QQuickLoader::sourceOrComponent_data()
QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << "";
QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
<< QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
<< QString(testFileUrl("IDontExist.qml").toString() + ": No such file or directory");
}
void tst_QQuickLoader::clear()
@ -748,7 +748,7 @@ void tst_QQuickLoader::initialPropertyValuesError_data()
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object"));
QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
<< (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
<< (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory"));
QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
@ -901,7 +901,7 @@ void tst_QQuickLoader::asynchronous_data()
<< QStringList();
QTest::newRow("Non-existent component") << testFileUrl("IDoNotExist.qml")
<< (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
<< (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory"));
QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));