diff options
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arraydata.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlboundsignal.cpp | 12 | ||||
-rw-r--r-- | src/qml/qml/qqmldirparser_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 62 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 55 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 9 | ||||
-rw-r--r-- | src/qml/types/qqmlconnections.cpp | 7 |
15 files changed, 113 insertions, 67 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index b07e9f55f5..b609a06382 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2102,6 +2102,15 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock); function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode || _module->debugMode; // Conditional breakpoints are like eval in the function + + // When a user writes the following QML signal binding: + // onSignal: function() { doSomethingUsefull } + // we will generate a binding function that just returns the closure. However, that's not useful + // at all, because if the onSignal is a signal handler, the user is actually making it explicit + // that the binding is a function, so we should execute that. However, we don't know that during + // AOT compilation, so mark the surrounding function as only-returning-a-closure. + function->returnsClosure = cast<ExpressionStatement *>(ast) && cast<FunctionExpression *>(cast<ExpressionStatement *>(ast)->expression); + function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed); function->usesThis = _env->usesThis; function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 188a571394..b15e4ade60 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -228,6 +228,7 @@ struct Function LEUInt32 nLocals; LEUInt32 localsOffset; LEUInt32 nInnerFunctions; + LEUInt32 nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers Location location; // Qml Extensions Begin @@ -248,6 +249,7 @@ struct Function quint8 flags; quint8 padding1; LEUInt16 padding2; + LEUInt32 padding3; const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); } const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); } @@ -266,7 +268,7 @@ struct Function return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + nIdObjectDependencies + 2 * nPropertyDependencies) * sizeof(quint32) + 7) & ~0x7; } }; -static_assert(sizeof(Function) == 72, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Function) == 80, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); // Qml data structures diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 0dc40d9698..e11e0bbcdd 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -298,6 +298,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i if (irFunction->hasTry || irFunction->hasWith) function->flags |= CompiledData::Function::HasCatchOrWith; function->nFormals = irFunction->formals.size(); + function->nestedFunctionIndex = + irFunction->returnsClosure ? quint32(irModule->functions.indexOf(irFunction->nestedFunctions.first())) + : std::numeric_limits<uint32_t>::max(); function->formalsOffset = currentOffset; currentOffset += function->nFormals * sizeof(quint32); diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index a4038f827a..7741a64667 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -374,6 +374,7 @@ Function::Function(Module *module, Function *outer, const QString &name) , hasTry(false) , hasWith(false) , isQmlBinding(false) + , returnsClosure(false) , unused(0) , line(0) , column(0) diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 317abd09bb..35b6abaa58 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1313,7 +1313,8 @@ struct Function { uint hasTry: 1; uint hasWith: 1; uint isQmlBinding: 1; - uint unused : 24; + uint returnsClosure: 1; + uint unused : 23; // Location of declaration in source code (0 if not specified) uint line; diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 0944e6d271..0d950223b0 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -647,7 +647,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) uint toCopy = n; uint chunk = toCopy; if (chunk > os->alloc - os->offset) - chunk -= os->alloc - os->offset; + chunk = os->alloc - os->offset; obj->arrayPut(oldSize, os->arrayData + os->offset, chunk); toCopy -= chunk; if (toCopy) diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index b212b3d027..fb8f1400a2 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -50,6 +50,7 @@ // We mean it. // +#include <stdint.h> #include "qv4global_p.h" #include <private/qqmlglobal_p.h> #include <private/qv4compileddata_p.h> @@ -100,6 +101,12 @@ struct Q_QML_EXPORT Function { return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); } + Function *nestedFunction() const + { + if (compiledFunction->nestedFunctionIndex == std::numeric_limits<uint32_t>::max()) + return nullptr; + return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex]; + } }; diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 19ece44beb..efe0cccc8d 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -110,6 +110,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, m_index(index), m_target(target) { + // If the function is marked as having a nested function, then the user wrote: + // onSomeSignal: function() { /*....*/ } + // So take that nested function: + if (auto closure = function->nestedFunction()) + function = closure; + setupFunction(scope, function); init(ctxt, scopeObject); } @@ -122,6 +128,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, // It's important to call init first, because m_index gets remapped in case of cloned signals. init(ctxt, scope); + // If the function is marked as having a nested function, then the user wrote: + // onSomeSignal: function() { /*....*/ } + // So take that nested function: + if (auto closure = runtimeFunction->nestedFunction()) + runtimeFunction = closure; + QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames(); diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h index 1530b7a6cf..1297d21fa0 100644 --- a/src/qml/qml/qqmldirparser_p.h +++ b/src/qml/qml/qqmldirparser_p.h @@ -63,8 +63,6 @@ class QQmlError; class QQmlEngine; class Q_QML_PRIVATE_EXPORT QQmlDirParser { - Q_DISABLE_COPY(QQmlDirParser) - public: QQmlDirParser(); ~QQmlDirParser(); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f4656bafd2..ac92f8dde8 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1098,7 +1098,9 @@ QQmlEngine::~QQmlEngine() void QQmlEngine::clearComponentCache() { Q_D(QQmlEngine); + d->typeLoader.lock(); d->typeLoader.clearCache(); + d->typeLoader.unlock(); } /*! diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index f43ffb4c3c..6e467a6d96 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -316,17 +316,17 @@ public: QQmlImportDatabase *database, QString *outQmldirFilePath, QString *outUrl); - static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin, + static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin, QList<QQmlError> *errors); bool importExtension(const QString &absoluteFilePath, const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database, - const QQmlTypeLoaderQmldirContent *qmldir, + const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors); bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri, - const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors); + QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors); QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); @@ -664,14 +664,14 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return false; } -bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) +bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) { Q_ASSERT(resolvedUrl.endsWith(Slash)); url = resolvedUrl; - qmlDirComponents = qmldir->components(); + qmlDirComponents = qmldir.components(); - const QQmlDirScripts &scripts = qmldir->scripts(); + const QQmlDirScripts &scripts = qmldir.scripts(); if (!scripts.isEmpty()) { // Verify that we haven't imported these scripts already for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin(); @@ -1060,26 +1060,26 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database, - const QQmlTypeLoaderQmldirContent *qmldir, + const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors) { - Q_ASSERT(qmldir); + Q_ASSERT(qmldir.hasContent()); if (qmlImportTrace()) qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: " << "loaded " << qmldirFilePath; - if (designerSupportRequired && !qmldir->designerSupported()) { + if (designerSupportRequired && !qmldir.designerSupported()) { if (errors) { QQmlError error; - error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir->typeNamespace())); + error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir.typeNamespace())); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } return false; } - int qmldirPluginCount = qmldir->plugins().count(); + int qmldirPluginCount = qmldir.plugins().count(); if (qmldirPluginCount == 0) return true; @@ -1090,7 +1090,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // listed plugin inside qmldir. And for this reason, mixing dynamic and static plugins inside a // single module is not recommended. - QString typeNamespace = qmldir->typeNamespace(); + QString typeNamespace = qmldir.typeNamespace(); QString qmldirPath = qmldirFilePath; int slash = qmldirPath.lastIndexOf(Slash); if (slash > 0) @@ -1100,7 +1100,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, int staticPluginsFound = 0; #if defined(QT_SHARED) - const auto qmldirPlugins = qmldir->plugins(); + const auto qmldirPlugins = qmldir.plugins(); for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) { QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); if (!resolvedFilePath.isEmpty()) { @@ -1166,7 +1166,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (qmldirPluginCount > 1 && staticPluginsFound > 0) error.setDescription(QQmlImportDatabase::tr("could not resolve all plugins for module \"%1\"").arg(uri)); else - error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir->plugins()[dynamicPluginsFound].name)); + error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir.plugins()[dynamicPluginsFound].name)); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } @@ -1179,17 +1179,17 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri, - const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors) + QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors) { Q_ASSERT(errors); Q_ASSERT(qmldir); *qmldir = typeLoader->qmldirContent(qmldirIdentifier); - if (*qmldir) { + if ((*qmldir).hasContent()) { // Ensure that parsing was successful - if ((*qmldir)->hasError()) { + if ((*qmldir).hasError()) { QUrl url = QUrl::fromLocalFile(qmldirIdentifier); - const QList<QQmlError> qmldirErrors = (*qmldir)->errors(uri); + const QList<QQmlError> qmldirErrors = (*qmldir).errors(uri); for (int i = 0; i < qmldirErrors.size(); ++i) { QQmlError error = qmldirErrors.at(i); error.setUrl(url); @@ -1313,14 +1313,14 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ return false; } -bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin, +bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin, QList<QQmlError> *errors) { int lowest_min = INT_MAX; int highest_min = INT_MIN; typedef QQmlDirComponents::const_iterator ConstIterator; - const QQmlDirComponents &components = qmldir->components(); + const QQmlDirComponents &components = qmldir.components(); ConstIterator cend = components.constEnd(); for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) { @@ -1344,7 +1344,7 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent } typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator; - const QQmlDirScripts &scripts = qmldir->scripts(); + const QQmlDirScripts &scripts = qmldir.scripts(); SConstIterator send = scripts.constEnd(); for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) { @@ -1436,14 +1436,14 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre Q_ASSERT(inserted); if (!incomplete) { - const QQmlTypeLoaderQmldirContent *qmldir = 0; + QQmlTypeLoaderQmldirContent qmldir; if (!qmldirIdentifier.isEmpty()) { if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors)) return false; - if (qmldir) { - if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) + if (qmldir.hasContent()) { + if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) return false; if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) @@ -1461,7 +1461,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri)); errors->prepend(error); return false; - } else if ((vmaj >= 0) && (vmin >= 0) && qmldir) { + } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) { // Verify that the qmldir content is valid for this version if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors)) return false; @@ -1541,12 +1541,12 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix Q_ASSERT(inserted); if (!incomplete && !qmldirIdentifier.isEmpty()) { - const QQmlTypeLoaderQmldirContent *qmldir = 0; + QQmlTypeLoaderQmldirContent qmldir; if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors)) return false; - if (qmldir) { - if (!importExtension(qmldir->pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors)) + if (qmldir.hasContent()) { + if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors)) return false; if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors)) @@ -1565,14 +1565,14 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString & Q_ASSERT(nameSpace); if (QQmlImportInstance *import = nameSpace->findImport(uri)) { - const QQmlTypeLoaderQmldirContent *qmldir = 0; + QQmlTypeLoaderQmldirContent qmldir; if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors)) return false; - if (qmldir) { + if (qmldir.hasContent()) { int vmaj = import->majversion; int vmin = import->minversion; - if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) + if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) return false; if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) { diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 9cb5340c68..757179bb44 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -80,7 +80,7 @@ struct QQmlImportInstance QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir - bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, + bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors); static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 5318375af7..afcb9cdbe9 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1379,8 +1379,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); - const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier); - const auto qmldirScripts = qmldir->scripts(); + const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier); + const auto qmldirScripts = qmldir.scripts(); for (const QQmlDirParser::Script &script : qmldirScripts) { QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName)); QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); @@ -1427,8 +1427,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); - const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath); - const auto qmldirScripts = qmldir->scripts(); + const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath); + const auto qmldirScripts = qmldir.scripts(); for (const QQmlDirParser::Script &script : qmldirScripts) { QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName)); QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); @@ -1593,6 +1593,7 @@ QString QQmlTypeLoaderQmldirContent::typeNamespace() const void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content) { + m_hasContent = true; m_location = location; m_parser.parse(content); } @@ -1815,6 +1816,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) int lastSlash = path.lastIndexOf(QLatin1Char('/')); QString dirPath(path.left(lastSlash)); + LockHolder<QQmlTypeLoader> holder(this); if (!m_importDirCache.contains(dirPath)) { bool exists = QDir(dirPath).exists(); QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : 0; @@ -1878,6 +1880,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path) --length; QString dirPath(path.left(length)); + LockHolder<QQmlTypeLoader> holder(this); if (!m_importDirCache.contains(dirPath)) { bool exists = QDir(dirPath).exists(); QCache<QString, bool> *files = exists ? new QCache<QString, bool> : 0; @@ -1896,8 +1899,10 @@ Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQm It can also be a remote path for a remote directory import, but it will have been cached by now in this case. */ -const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn) +const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(const QString &filePathIn) { + LockHolder<QQmlTypeLoader> holder(this); + QString filePath; // Try to guess if filePathIn is already a URL. This is necessarily fragile, because @@ -1911,39 +1916,39 @@ const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString & filePath = filePathIn; } else { filePath = QQmlFile::urlToLocalFileOrQrc(url); - if (filePath.isEmpty()) // Can't load the remote here, but should be cached - return *(m_importQmlDirCache.value(filePathIn)); + if (filePath.isEmpty()) { // Can't load the remote here, but should be cached + if (auto entry = m_importQmlDirCache.value(filePathIn)) + return **entry; + else + return QQmlTypeLoaderQmldirContent(); + } } - QQmlTypeLoaderQmldirContent *qmldir; QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath); - if (!val) { - qmldir = new QQmlTypeLoaderQmldirContent; + if (val) + return **val; + QQmlTypeLoaderQmldirContent *qmldir = new QQmlTypeLoaderQmldirContent; #define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); } #define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable")) #define CASE_MISMATCH_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"")) - QFile file(filePath); - if (!QQml_isFileCaseCorrect(filePath)) { - ERROR(CASE_MISMATCH_ERROR.arg(filePath)); - } else if (file.open(QFile::ReadOnly)) { - QByteArray data = file.readAll(); - qmldir->setContent(filePath, QString::fromUtf8(data)); - } else { - ERROR(NOT_READABLE_ERROR.arg(filePath)); - } + QFile file(filePath); + if (!QQml_isFileCaseCorrect(filePath)) { + ERROR(CASE_MISMATCH_ERROR.arg(filePath)); + } else if (file.open(QFile::ReadOnly)) { + QByteArray data = file.readAll(); + qmldir->setContent(filePath, QString::fromUtf8(data)); + } else { + ERROR(NOT_READABLE_ERROR.arg(filePath)); + } #undef ERROR #undef NOT_READABLE_ERROR #undef CASE_MISMATCH_ERROR - m_importQmlDirCache.insert(filePath, qmldir); - } else { - qmldir = *val; - } - - return qmldir; + m_importQmlDirCache.insert(filePath, qmldir); + return *qmldir; } void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content) diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index ab32bac7b2..71bd5a8a7f 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -228,12 +228,16 @@ class QQmlTypeLoaderQmldirContent { private: friend class QQmlTypeLoader; - QQmlTypeLoaderQmldirContent(); void setContent(const QString &location, const QString &content); void setError(const QQmlError &); public: + QQmlTypeLoaderQmldirContent(); + QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default; + QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default; + + bool hasContent() const { return m_hasContent; } bool hasError() const; QList<QQmlError> errors(const QString &uri) const; @@ -250,6 +254,7 @@ public: private: QQmlDirParser m_parser; QString m_location; + bool m_hasContent = false; }; class Q_QML_PRIVATE_EXPORT QQmlTypeLoader @@ -304,7 +309,7 @@ public: QString absoluteFilePath(const QString &path); bool directoryExists(const QString &path); - const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath); + const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath); void setQmldirContent(const QString &filePath, const QString &content); void clearCache(); diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 7607c19374..2554dcf2b6 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -289,9 +289,10 @@ void QQmlConnections::connectSignals() new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); signal->setEnabled(d->enabled); - QQmlBoundSignalExpression *expression = ctxtdata ? - new QQmlBoundSignalExpression(target, signalIndex, - ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0; + auto f = d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; + QQmlBoundSignalExpression *expression = + ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f) + : nullptr; signal->takeExpression(expression); d->boundsignals += signal; } else { |