diff options
Diffstat (limited to 'src/qml/qml/qqmlengine.cpp')
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 353 |
1 files changed, 220 insertions, 133 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 7c218276c2..62b7675e1d 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -62,6 +62,8 @@ QT_BEGIN_NAMESPACE +void qml_register_types_QML(); + /*! \qmltype QtObject \instantiates QObject @@ -215,23 +217,16 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) { QObjectPrivate *p = QObjectPrivate::get(o); if (QQmlData *d = QQmlData::get(p)) { + const auto invalidate = [](QQmlContextData *c) {c->invalidate();}; if (d->ownContext) { - for (QQmlRefPointer<QQmlContextData> lc = d->ownContext->linkedContext(); lc; - lc = lc->linkedContext()) { - lc->invalidate(); - if (lc->contextObject() == o) - lc->setContextObject(nullptr); - } - d->ownContext->invalidate(); - if (d->ownContext->contextObject() == o) - d->ownContext->setContextObject(nullptr); + d->ownContext->deepClearContextObject(o, invalidate, invalidate); d->ownContext.reset(); d->context = nullptr; + Q_ASSERT(!d->outerContext || d->outerContext->contextObject() != o); + } else if (d->outerContext && d->outerContext->contextObject() == o) { + d->outerContext->deepClearContextObject(o, invalidate, invalidate); } - if (d->outerContext && d->outerContext->contextObject() == o) - d->outerContext->setContextObject(nullptr); - if (d->hasVMEMetaObject || d->hasInterceptorMetaObject) { // This is somewhat dangerous because another thread might concurrently // try to resolve the dynamic metaobject. In practice this will then @@ -255,14 +250,11 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) } } -QQmlData::QQmlData() - : ownMemory(true), indestructible(true), explicitIndestructibleSet(false), +QQmlData::QQmlData(Ownership ownership) + : ownMemory(ownership == OwnsMemory), indestructible(true), explicitIndestructibleSet(false), hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), - hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), - bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr), - bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr), - lineNumber(0), columnNumber(0), jsEngineId(0), - guards(nullptr), extendedData(nullptr) + hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), dummy(0), + bindingBitsArraySize(InlineBindingArraySize) { memset(bindingBitsValue, 0, sizeof(bindingBitsValue)); init(); @@ -312,7 +304,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in // QQmlEngine to emit signals from a different thread. These signals are then automatically // marshalled back onto the QObject's thread and handled by QML from there. This is tested // by the qqmlecmascript::threadSignal() autotest. - if (!ddata->notifyList) + + // Relaxed semantics here. If we're on a different thread we might schedule a useless event, + // but that should be rare. + if (!ddata->notifyList.loadRelaxed()) return; auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed(); @@ -386,11 +381,15 @@ int QQmlData::endpointCount(int index) void QQmlData::markAsDeleted(QObject *o) { - QQmlData::setQueuedForDeletion(o); - - QObjectPrivate *p = QObjectPrivate::get(o); - for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) { - QQmlData::markAsDeleted(*it); + QVarLengthArray<QObject *> workStack; + workStack.push_back(o); + while (!workStack.isEmpty()) { + auto currentObject = workStack.last(); + workStack.pop_back(); + QQmlData::setQueuedForDeletion(currentObject); + auto currentObjectPriv = QObjectPrivate::get(currentObject); + for (QObject *child: std::as_const(currentObjectPriv->children)) + workStack.push_back(child); } } @@ -400,9 +399,7 @@ void QQmlData::setQueuedForDeletion(QObject *object) if (QQmlData *ddata = QQmlData::get(object)) { if (ddata->ownContext) { Q_ASSERT(ddata->ownContext.data() == ddata->context); - ddata->context->emitDestruction(); - if (ddata->ownContext->contextObject() == object) - ddata->ownContext->setContextObject(nullptr); + ddata->ownContext->deepClearContextObject(object); ddata->ownContext.reset(); ddata->context = nullptr; } @@ -413,7 +410,7 @@ void QQmlData::setQueuedForDeletion(QObject *object) // possible to get the metaobject anymore. // Also, there is no point in evaluating bindings in order to set properties on // half-deleted objects. - ddata->disconnectNotifiers(); + ddata->disconnectNotifiers(DeleteNotifyList::No); } } } @@ -437,38 +434,57 @@ void QQmlData::flushPendingBinding(int coreIndex) QQmlData::DeferredData::DeferredData() = default; QQmlData::DeferredData::~DeferredData() = default; +template<> +int qmlRegisterType<void>(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QQmlPrivate::RegisterType type = { + QQmlPrivate::RegisterType::CurrentVersion, + QMetaType(), + QMetaType(), + 0, nullptr, nullptr, + QString(), + nullptr, + uri, + QTypeRevision::fromVersion(versionMajor, versionMinor), + qmlName, + nullptr, + nullptr, + nullptr, + -1, + -1, + -1, + nullptr, + nullptr, + nullptr, + QTypeRevision::zero(), + -1, + QQmlPrivate::ValueTypeCreationMethod::None, + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + bool QQmlEnginePrivate::baseModulesUninitialized = true; void QQmlEnginePrivate::init() { Q_Q(QQmlEngine); if (baseModulesUninitialized) { - - // required for the Compiler. - qmlRegisterType<QObject>("QML", 1, 0, "QtObject"); - qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); - qmlRegisterAnonymousSequentialContainer<QList<QVariant>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<bool>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<int>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<float>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<double>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<QString>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<QUrl>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<QDateTime>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<QRegularExpression>>("QML", 1); - qmlRegisterAnonymousSequentialContainer<QList<QByteArray>>("QML", 1); + // Register builtins + qml_register_types_QML(); // No need to specifically register those. static_assert(std::is_same_v<QStringList, QList<QString>>); static_assert(std::is_same_v<QVariantList, QList<QVariant>>); - qRegisterMetaType<QVariant>(); qRegisterMetaType<QQmlScriptString>(); - qRegisterMetaType<QJSValue>(); qRegisterMetaType<QQmlComponent::Status>(); qRegisterMetaType<QList<QObject*> >(); qRegisterMetaType<QQmlBinding*>(); + // Protect the module: We don't want any URL interceptor to mess with the builtins. + qmlProtectModule("QML", 1); + QQmlData::init(); baseModulesUninitialized = false; } @@ -484,29 +500,16 @@ void QQmlEnginePrivate::init() \inmodule QtQml \brief The QQmlEngine class provides an environment for instantiating QML components. - Each QML component is instantiated in a QQmlContext. - QQmlContext's are essential for passing data to QML - components. In QML, contexts are arranged hierarchically and this - hierarchy is managed by the QQmlEngine. - - Prior to creating any QML components, an application must have - created a QQmlEngine to gain access to a QML context. The - following example shows how to create a simple Text item. - - \code - QQmlEngine engine; - QQmlComponent component(&engine); - component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl()); - QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); - - //add item to view, etc - ... - \endcode + A QQmlEngine is used to manage \l{QQmlComponent}{components} and objects created from + them and execute their bindings and functions. QQmlEngine also inherits from + \l{QJSEngine} which allows seamless integration between your QML components and + JavaScript code. - In this case, the Text item will be created in the engine's - \l {QQmlEngine::rootContext()}{root context}. + Each QML component is instantiated in a QQmlContext. In QML, contexts are arranged + hierarchically and this hierarchy is managed by the QQmlEngine. By default, + components are instantiated in the \l {QQmlEngine::rootContext()}{root context}. - \sa QQmlComponent, QQmlContext, {QML Global Object} + \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine */ /*! @@ -537,11 +540,12 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent) invalidated, but not destroyed (unless they are parented to the QQmlEngine object). - See QJSEngine docs for details on cleaning up the JS engine. + See ~QJSEngine() for details on cleaning up the JS engine. */ QQmlEngine::~QQmlEngine() { Q_D(QQmlEngine); + handle()->inShutdown = true; QJSEnginePrivate::removeFromDebugServer(this); // Emit onDestruction signals for the root context before @@ -610,9 +614,20 @@ QQmlEngine::~QQmlEngine() void QQmlEngine::clearComponentCache() { Q_D(QQmlEngine); + + // Contexts can hold on to CUs but live on the JS heap. + // Use a non-incremental GC run to get rid of those. + QV4::MemoryManager *mm = handle()->memoryManager; + auto oldLimit = mm->gcStateMachine->timeLimit; + mm->setGCTimeLimit(-1); + mm->runGC(); + mm->gcStateMachine->timeLimit = std::move(oldLimit); + + handle()->clearCompilationUnits(); d->typeLoader.lock(); d->typeLoader.clearCache(); d->typeLoader.unlock(); + QQmlMetaType::freeUnusedTypesAndCaches(); } /*! @@ -630,6 +645,7 @@ void QQmlEngine::clearComponentCache() void QQmlEngine::trimComponentCache() { Q_D(QQmlEngine); + handle()->trimCompilationUnits(); d->typeLoader.trimCache(); } @@ -927,6 +943,45 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) d->outputWarningsToMsgLog = enabled; } + +/*! + \since 6.6 + If this method is called inside of a function that is part of + a binding in QML, the binding will be treated as a translation binding. + + \code + class I18nAwareClass : public QObject { + + //... + + QString text() const + { + if (auto engine = qmlEngine(this)) + engine->markCurrentFunctionAsTranslationBinding(); + return tr("Hello, world!"); + } + }; + \endcode + + \note This function is mostly useful if you wish to provide your + own alternative to the qsTr function. To ensure that properties + exposed from C++ classes are updated on language changes, it is + instead recommended to react to \c LanguageChange events. That + is a more general mechanism which also works when the class is + used in a non-QML context, and has slightly less overhead. However, + using \c markCurrentFunctionAsTranslationBinding can be acceptable + when the class is already closely tied to the QML engine. + For more details, see \l {Prepare for Dynamic Language Changes} + + \sa QQmlEngine::retranslate +*/ +void QQmlEngine::markCurrentFunctionAsTranslationBinding() +{ + Q_D(QQmlEngine); + if (auto propertyCapture = d->propertyCapture) + propertyCapture->captureTranslation(); +} + /*! \internal @@ -1194,11 +1249,12 @@ void QQmlData::deferData( deferData->context = context; const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex); - const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex); + const QV4::CompiledData::BindingPropertyData *propertyData + = compilationUnit->bindingPropertyDataPerObjectAt(objectIndex); const QV4::CompiledData::Binding *binding = compiledObject->bindingTable(); for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) { - const QQmlPropertyData *property = propertyData.at(i); + const QQmlPropertyData *property = propertyData->at(i); if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) deferData->bindings.insert(property ? property->coreIndex() : -1, binding); } @@ -1222,49 +1278,73 @@ void QQmlData::releaseDeferredData() void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint) { - if (!notifyList) { - notifyList = (NotifyList *)malloc(sizeof(NotifyList)); - notifyList->connectionMask = 0; - notifyList->maximumTodoIndex = 0; - notifyList->notifiesSize = 0; - notifyList->todo = nullptr; - notifyList->notifies = nullptr; + // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics. + + NotifyList *list = notifyList.loadRelaxed(); + + if (!list) { + list = new NotifyList; + // We don't really care when this change takes effect on other threads. The notifyList can + // only become non-null once in the life time of a QQmlData. It becomes null again when the + // underlying QObject is deleted. At that point any interaction with the QQmlData is UB + // anyway. So, for all intents and purposese, the list becomes non-null once and then stays + // non-null "forever". We can apply relaxed semantics. + notifyList.storeRelaxed(list); } Q_ASSERT(!endpoint->isConnected()); index = qMin(index, 0xFFFF - 1); - notifyList->connectionMask |= (1ULL << quint64(index % 64)); - if (index < notifyList->notifiesSize) { + // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other + // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying + // the conenctionMask in the presence of concurrent modification, any result is correct. + list->connectionMask.storeRelaxed( + list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64))); - endpoint->next = notifyList->notifies[index]; + if (index < list->notifiesSize) { + endpoint->next = list->notifies[index]; if (endpoint->next) endpoint->next->prev = &endpoint->next; - endpoint->prev = ¬ifyList->notifies[index]; - notifyList->notifies[index] = endpoint; - + endpoint->prev = &list->notifies[index]; + list->notifies[index] = endpoint; } else { - notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index); + list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index); - endpoint->next = notifyList->todo; + endpoint->next = list->todo; if (endpoint->next) endpoint->next->prev = &endpoint->next; - endpoint->prev = ¬ifyList->todo; - notifyList->todo = endpoint; + endpoint->prev = &list->todo; + list->todo = endpoint; } } -void QQmlData::disconnectNotifiers() +void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete) { - if (notifyList) { - while (notifyList->todo) - notifyList->todo->disconnect(); - for (int ii = 0; ii < notifyList->notifiesSize; ++ii) { - while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii]) + // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics. + if (NotifyList *list = notifyList.loadRelaxed()) { + while (QQmlNotifierEndpoint *todo = list->todo) + todo->disconnect(); + for (int ii = 0; ii < list->notifiesSize; ++ii) { + while (QQmlNotifierEndpoint *ep = list->notifies[ii]) ep->disconnect(); } - free(notifyList->notifies); - free(notifyList); - notifyList = nullptr; + free(list->notifies); + + if (doDelete == DeleteNotifyList::Yes) { + // We can only get here from QQmlData::destroyed(), and that can only come from the + // the QObject dtor. If you're still sending signals at that point you have UB already + // without any threads. Therefore, it's enough to apply relaxed semantics. + notifyList.storeRelaxed(nullptr); + delete list; + } else { + // We can use relaxed semantics here. The worst thing that can happen is that some + // signal is falsely reported as connected. Signal connectedness across threads + // is not quite deterministic anyway. + list->connectionMask.storeRelaxed(0); + list->maximumTodoIndex = 0; + list->notifiesSize = 0; + list->notifies = nullptr; + + } } } @@ -1349,7 +1429,7 @@ void QQmlData::destroyed(QObject *object) guard->objectDestroyed(guard); } - disconnectNotifiers(); + disconnectNotifiers(DeleteNotifyList::Yes); if (extendedData) delete extendedData; @@ -1390,7 +1470,7 @@ QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv) { Q_ASSERT(priv); Q_ASSERT(!priv->isDeletingChildren); - priv->declarativeData = new QQmlData; + priv->declarativeData = new QQmlData(OwnsMemory); return static_cast<QQmlData *>(priv->declarativeData); } @@ -1545,7 +1625,8 @@ void QQmlEnginePrivate::cleanupScarceResources() The newly added \a path will be first in the importPathList(). - \sa setImportPathList(), {QML Modules} + \b {See also} \l setImportPathList(), \l {QML Modules}, + and \l [QtQml] {QML Import Path} */ void QQmlEngine::addImportPath(const QString& path) { @@ -1563,9 +1644,8 @@ void QQmlEngine::addImportPath(const QString& path) provided by that module. A \c qmldir file is required for defining the type version mapping and possibly QML extensions plugins. - By default, the list contains the directory of the application executable, - paths specified in the \c QML_IMPORT_PATH environment variable, - and the builtin \c QmlImportsPath from QLibraryInfo. + By default, this list contains the paths mentioned in + \l {QML Import Path}. \sa addImportPath(), setImportPathList() */ @@ -1579,9 +1659,11 @@ QStringList QQmlEngine::importPathList() const Sets \a paths as the list of directories where the engine searches for installed modules in a URL-based directory structure. - By default, the list contains the directory of the application executable, - paths specified in the \c QML_IMPORT_PATH environment variable, - and the builtin \c QmlImportsPath from QLibraryInfo. + By default, this list contains the paths mentioned in + \l {QML Import Path}. + + \warning Calling setImportPathList does not preserve the default + import paths. \sa importPathList(), addImportPath() */ @@ -1745,14 +1827,13 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) { Q_Q(QQmlEngine); - QJSValue value = singletonInstances.value(type); - if (!value.isUndefined()) { - return value; - } - - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo::ConstPtr siinfo = type.singletonInstanceInfo(); Q_ASSERT(siinfo != nullptr); + QJSValue value = singletonInstances.value(siinfo); + if (!value.isUndefined()) + return value; + if (siinfo->scriptCallback) { value = siinfo->scriptCallback(q, q); if (value.isQObject()) { @@ -1761,7 +1842,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) // should behave identically to QML singleton types. q->setContextForObject(o, new QQmlContext(q->rootContext(), q)); } - singletonInstances.convertAndInsert(v4engine(), type, &value); + singletonInstances.convertAndInsert(v4engine(), siinfo, &value); } else if (siinfo->qobjectCallback) { QObject *o = siinfo->qobjectCallback(q, q); @@ -1790,7 +1871,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) } value = q->newQObject(o); - singletonInstances.convertAndInsert(v4engine(), type, &value); + singletonInstances.convertAndInsert(v4engine(), siinfo, &value); } else if (!siinfo->url.isEmpty()) { QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous); if (component.isError()) { @@ -1801,7 +1882,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) } QObject *o = component.beginCreate(q->rootContext()); value = q->newQObject(o); - singletonInstances.convertAndInsert(v4engine(), type, &value); + singletonInstances.convertAndInsert(v4engine(), siinfo, &value); component.completeCreate(); } @@ -1864,7 +1945,7 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU // different version of ExecutionEngine::callInContext() that returns a // QV4::ReturnedValue with no arguments since they are not needed by the // outer function anyhow - QV4::ScopedFunctionObject result(scope, + QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope, v4->callInContext(function, thisObject, callContext, 0, nullptr)); Q_ASSERT(result->function()); Q_ASSERT(result->function()->compilationUnit == function->compilationUnit); @@ -1879,12 +1960,20 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url) { + QV4::ExecutionEngine *v4 = v4engine(); + if (auto unit = v4->compilationUnitForUrl(url)) { + if (!unit->runtimeStrings) + unit->populate(); + return unit.data(); + } + auto unit = typeLoader.getType(url)->compilationUnit(); if (!unit) return nullptr; - if (!unit->engine) - unit->linkToEngine(v4engine()); - return unit; + + auto executable = v4->executableCompilationUnit(std::move(unit)); + executable->populate(); + return executable.data(); } QQmlRefPointer<QQmlContextData> @@ -1897,21 +1986,21 @@ QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCom QQmlRefPointer<QQmlContextData> context; context = QQmlContextData::createRefCounted(parentContext); context->setInternal(true); - context->setImports(unit->typeNameCache); + context->setImports(unit->typeNameCache()); context->initFromTypeCompilationUnit(unit, subComponentIndex); - if (isComponentRoot && unit->dependentScripts.size()) { + const auto *dependentScripts = unit->dependentScriptsPtr(); + const qsizetype dependentScriptsSize = dependentScripts->size(); + if (isComponentRoot && dependentScriptsSize) { QV4::ExecutionEngine *v4 = v4engine(); Q_ASSERT(v4); QV4::Scope scope(v4); - QV4::ScopedObject scripts(scope, v4->newArrayObject(unit->dependentScripts.size())); + QV4::ScopedObject scripts(scope, v4->newArrayObject(dependentScriptsSize)); context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue())); QV4::ScopedValue v(scope); - for (int i = 0; i < unit->dependentScripts.size(); ++i) { - QQmlRefPointer<QQmlScriptData> s = unit->dependentScripts.at(i); - scripts->put(i, (v = s->scriptValueForContext(context))); - } + for (qsizetype i = 0; i < dependentScriptsSize; ++i) + scripts->put(i, (v = dependentScripts->at(i)->scriptValueForContext(context))); } return context; @@ -2032,10 +2121,12 @@ LoadHelper::LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri) { auto import = std::make_shared<PendingImport>(); - import->uri = uri.toString(); + import->uri = m_uri; QList<QQmlError> errorList; - if (!Blob::addImport(import, &errorList)) - m_uri = QString(); // reset m_uri to remember the failure + if (!Blob::addImport(import, &errorList)) { + qCDebug(lcQmlImport) << "LoadHelper: Errors loading " << m_uri << errorList; + m_uri.clear(); // reset m_uri to remember the failure + } } LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName) @@ -2054,9 +2145,8 @@ LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName) QTypeRevision versionReturn; QList<QQmlError> errors; QQmlImportNamespace *ns_return = nullptr; - m_importCache->resolveType(typeName.toString(), &type, &versionReturn, - &ns_return, - &errors); + m_importCache->resolveType( + typeLoader(), typeName.toString(), &type, &versionReturn, &ns_return, &errors); return {ResolveTypeResult::ModuleFound, type}; } @@ -2072,7 +2162,4 @@ bool LoadHelper::couldFindModule() const QT_END_NAMESPACE -#include "moc_qqmlengine_p.cpp" - #include "moc_qqmlengine.cpp" - |