QML: Use QQmlType as container for composite types (inline or not)

This gives us a unified interface to all kinds of QML types at run time
and reduces the effort of finding corresponding type attributes.

QQmlType is much larger than CompositeMetaTypeIds. Most composite types,
however, are initially referenced by URL, and we call typeForUrl anyway.
typeForUrl already creates a mostly functional QQmlType; we only need to
add the dynamic metatypes. The same type can be retrieved later and
associated with the actual CU using the compositeTypes hash. That way,
we don't need any extra type. We do, however, incur the cost of creating
the QMetaTypePrivate instances when first referencing a type. This could
be optimized, like many things in this area, by using thread safe lazy
initialization.

Now some QQmlTypes implicitly depend on the CUs they were created for.
This creates problems if the CUs are removed but the types still
persist. Such a situation can arise if you create and delete engines. In
order to avoid it, we:

1. Make the compositeTypes hold a strong reference to the CUs
2. When unlinking, avoid dropping the property caches (as those are used
   to hold the metaobjects)

Now, however we got a cyclic reference between the CU and its
QQmlType(s). To resolve this, we clear the QQmlTypes on unlinking.
Finally, to avoid deletion recursion when clearing the last CUs on
destruction of the QQmlMetaTypeData, we move the compilation units out
of the way first.

All of this still doesn't work if multiple CUs hold the same QQmlType,
since compositeTypes can only hold one CU per type and that may be the
one that gets removed first. Therefore, we cannot allow such a situation
to happen and have to create a new QQmlType if it arises. It can only
arise if you have multiple engines loading the same QML components,
which should be fairly rare.

For inline components, we apply a similar trick: You can either find an
inline component by Url, and receive any type that matches, no matter
what CU it belongs to. Or you can request an inline component type that
belongs to a specific CU. It turns out we don't have to store the
containing type of an IC at all. Also, we slightly change the naming of
internal components' "class names" since we want to use the inline
components' element names for them.

Change-Id: I0ef89bd4b0a02cc927aed2525e72f6bff56df626
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
This commit is contained in:
Ulf Hermann 2023-05-24 13:00:20 +02:00
parent 4a1e5d8e74
commit b48bb41681
27 changed files with 552 additions and 518 deletions

View File

@ -472,6 +472,12 @@ struct Q_QML_COMPILER_PRIVATE_EXPORT Document
QV4::CompiledData::CompilationUnit javaScriptCompilationUnit;
bool isSingleton() const {
return std::any_of(pragmas.constBegin(), pragmas.constEnd(), [](const Pragma *pragma) {
return pragma->type == Pragma::Singleton;
});
}
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }

View File

@ -58,6 +58,11 @@ public:
using NodeList = std::vector<Node>;
using AdjacencyList = std::vector<std::vector<Node*>>;
inline bool containedInSameType(const QQmlType &a, const QQmlType &b)
{
return QQmlMetaType::equalBaseUrls(a.sourceUrl(), b.sourceUrl());
}
template<typename ObjectContainer, typename InlineComponent>
void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
AdjacencyList &adjacencyList, NodeList &nodes,
@ -75,7 +80,7 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
if (targetTypeRef) {
const auto targetType = targetTypeRef->type();
if (targetType.isInlineComponentType()
&& targetType.containingType() == currentICTypeRef->type().containingType()) {
&& containedInSameType(targetType, currentICTypeRef->type())) {
auto icIt = std::find_if(allICs.cbegin(), allICs.cend(), [&](const QV4::CompiledData::InlineComponent &icSearched){
return objectContainer->stringAt(icSearched.nameIndex)
== targetType.elementName();

View File

@ -859,8 +859,9 @@ ExecutionEngine::~ExecutionEngine()
delete identifierTable;
delete memoryManager;
// Take a temporary reference to the CU so that it doesn't disappear during unlinking.
while (!compilationUnits.isEmpty())
(*compilationUnits.begin())->unlink();
QQmlRefPointer<ExecutableCompilationUnit>(*compilationUnits.begin())->unlink();
delete bumperPointerAllocator;
delete regExpCache;

View File

@ -272,12 +272,11 @@ void ExecutableCompilationUnit::unlink()
if (engine)
nextCompilationUnit.remove();
if (isRegistered) {
Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
QQmlMetaType::unregisterInternalCompositeType(this);
}
propertyCaches.clear();
// Clear the QQmlTypes but not the property caches.
// The property caches may still be necessary to resolve further types.
qmlType = QQmlType();
for (auto &ic : inlineComponentData)
ic.qmlType = QQmlType();
if (runtimeLookups) {
for (uint i = 0; i < data->lookupTableSize; ++i)
@ -382,26 +381,29 @@ void processInlinComponentType(
}
}
void ExecutableCompilationUnit::finalizeCompositeType(CompositeMetaTypeIds types)
void ExecutableCompilationUnit::finalizeCompositeType(const QQmlType &type)
{
// Add to type registry of composites
if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
// typeIds is only valid for types that have references to themselves.
if (!types.isValid())
types = CompositeMetaTypeIds::fromCompositeName(rootPropertyCache()->className());
typeIds = types;
QQmlMetaType::registerInternalCompositeType(this);
// qmlType is only valid for types that have references to themselves.
if (type.isValid()) {
qmlType = type;
} else {
qmlType = QQmlMetaType::findCompositeType(
finalUrl(), this, (unitData()->flags & CompiledData::Unit::IsSingleton)
? QQmlMetaType::Singleton
: QQmlMetaType::NonSingleton);
}
QQmlMetaType::registerInternalCompositeType(this);
} else {
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
if (const auto compilationUnit = typeRef->compilationUnit()) {
typeIds = compilationUnit->typeIds;
} else {
const auto type = typeRef->type();
typeIds = CompositeMetaTypeIds{ type.typeId(), type.qListTypeId() };
}
if (const auto compilationUnit = typeRef->compilationUnit())
qmlType = compilationUnit->qmlType;
else
qmlType = typeRef->type();
}
// Collect some data for instantiation later.
@ -520,12 +522,11 @@ bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentType
sizeof(data->dependencyMD5Checksum)) == 0;
}
CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent(
const QString &inlineComponentName) const
QQmlType ExecutableCompilationUnit::qmlTypeForComponent(const QString &inlineComponentName) const
{
if (inlineComponentName.isEmpty())
return typeIds;
return inlineComponentData[inlineComponentName].typeIds;
return qmlType;
return inlineComponentData[inlineComponentName].qmlType;
}
QStringList ExecutableCompilationUnit::moduleRequests() const

View File

@ -34,15 +34,17 @@ class QQmlEnginePrivate;
struct InlineComponentData {
InlineComponentData() = default;
InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount)
: typeIds(typeIds)
, objectIndex(objectIndex)
, nameIndex(nameIndex)
, totalObjectCount(totalObjectCount)
, totalBindingCount(totalBindingCount)
, totalParserStatusCount(totalParserStatusCount) {}
InlineComponentData(
const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount,
int totalBindingCount, int totalParserStatusCount)
: qmlType(qmlType)
, objectIndex(objectIndex)
, nameIndex(nameIndex)
, totalObjectCount(totalObjectCount)
, totalBindingCount(totalBindingCount)
, totalParserStatusCount(totalParserStatusCount) {}
CompositeMetaTypeIds typeIds;
QQmlType qmlType;
int objectIndex = -1;
int nameIndex = -1;
int totalObjectCount = 0;
@ -126,7 +128,7 @@ public:
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
void finalizeCompositeType(CompositeMetaTypeIds typeIdsForComponent);
void finalizeCompositeType(const QQmlType &type);
int m_totalBindingsCount = 0; // Number of bindings used in this type
int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
@ -143,10 +145,9 @@ public:
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const;
QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
CompositeMetaTypeIds typeIds;
bool isRegistered = false;
QQmlType qmlType;
QHash<QString, InlineComponentData> inlineComponentData;

View File

@ -163,13 +163,13 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
if (!qmltype.isComposite()) {
if (!qmltype.isInlineComponentType())
return QMetaType();
const CompositeMetaTypeIds typeIds = unit->typeIdsForComponent(qmltype.elementName());
return param.isList() ? typeIds.listId : typeIds.id;
const QQmlType qmlType = unit->qmlTypeForComponent(qmltype.elementName());
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
}
const CompositeMetaTypeIds typeIds = enginePrivate->typeLoader.getType(
qmltype.sourceUrl())->compilationUnit()->typeIds;
return param.isList() ? typeIds.listId : typeIds.id;
const QQmlType qmlType = enginePrivate->typeLoader.getType(
qmltype.sourceUrl())->compilationUnit()->qmlType;
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
};
for (quint16 i = 0; i < nFormals; ++i)

View File

@ -1824,7 +1824,7 @@ bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
QMetaType metaType = typeWrapper->type().typeId();
if (!metaType.isValid()) {
metaType = ep->typeLoader.getType(typeWrapper->type().sourceUrl())
->compilationUnit()->typeIds.id;
->compilationUnit()->qmlType.typeId();
}
*static_cast<const QMetaObject **>(target)

View File

@ -582,38 +582,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
bool ret = uri == typeStr;
if (ret) {
Q_ASSERT(!type_return->isValid());
auto createICType = [&]() {
auto typePriv = new QQmlTypePrivate {QQmlType::RegistrationType::InlineComponentType};
const QUrl ownUrl = QUrl(url);
typePriv->elementName = ownUrl.fragment();
Q_ASSERT(!typePriv->elementName.isEmpty());
typePriv->extraData.id->url = ownUrl;
auto icType = QQmlType(typePriv);
typePriv->release();
return icType;
};
if (containingType.isValid()) {
// we currently cannot reference a Singleton inside itself
// in that case, containingType is still invalid
if (QQmlType ic = QQmlMetaType::inlineComponentType(containingType, typeStr);
ic.isValid()) {
*type_return = ic;
} else {
auto icType = createICType();
QQmlMetaType::associateInlineComponent(
containingType, typeStr, CompositeMetaTypeIds {}, icType);
*type_return = QQmlType(icType);
}
} else {
*type_return = createICType();
}
*type_return = QQmlMetaType::inlineComponentTypeForUrl(QUrl(url));
}
return ret;
}
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
bool isCompositeSingleton = false;
QQmlMetaType::CompositeTypeLookupMode lookupMode = QQmlMetaType::NonSingleton;
QQmlDirComponents::ConstIterator candidate = end;
for ( ; it != end && it.key() == typeStr; ++it) {
const QQmlDirParser::Component &c = *it;
@ -658,7 +634,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
// This is our best candidate so far
candidate = it;
isCompositeSingleton = c.singleton;
lookupMode = c.singleton ? QQmlMetaType::Singleton : QQmlMetaType::NonSingleton;
}
}
}
@ -666,7 +642,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (candidate != end) {
if (!base) // ensure we have a componentUrl
componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton,
QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, lookupMode,
nullptr, candidate->version);
if (version_return)
*version_return = candidate->version;
@ -715,7 +691,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
*typeRecursionDetected = recursion;
if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
QQmlType returnType = QQmlMetaType::typeForUrl(
qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
qmlUrl, type, registrationType == QQmlType::CompositeSingletonType
? QQmlMetaType::Singleton
: QQmlMetaType::NonSingleton,
errors);
if (type_return)
*type_return = returnType;
return returnType.isValid();
@ -747,7 +726,7 @@ bool QQmlImports::resolveType(
*type_return = QQmlMetaType::typeForUrl(
resolveLocalUrl(nameSpace->imports.at(0)->url,
unqualifiedtype.toString() + QLatin1String(".qml")),
type, false, errors);
type, QQmlMetaType::NonSingleton, errors);
return type_return->isValid();
}
return false;
@ -766,22 +745,8 @@ bool QQmlImports::resolveType(
} else {
if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
// either simple type + inline component
const QString icName = splitName.at(1).toString();
const QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName);
if (ic.isValid()) {
*type_return = ic;
} else {
auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
icTypePriv->setContainingType(type_return);
icTypePriv->extraData.id->url = type_return->sourceUrl();
icTypePriv->extraData.id->url.setFragment(icName);
auto icType = QQmlType(icTypePriv);
icTypePriv->release();
QQmlMetaType::associateInlineComponent(
*type_return, icName, CompositeMetaTypeIds {}, icType);
*type_return = icType;
}
Q_ASSERT(type_return->containingType().isValid());
*type_return = QQmlMetaType::inlineComponentTypeForUrl(
type_return->sourceUrl(), splitName.at(1).toString());
return true;
} else {
// or a failure
@ -802,21 +767,8 @@ bool QQmlImports::resolveType(
error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
} else {
if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
auto const icName = splitName.at(2).toString();
QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName);
if (ic.isValid())
*type_return = ic;
else {
auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
icTypePriv->setContainingType(type_return);
icTypePriv->extraData.id->url = type_return->sourceUrl();
icTypePriv->extraData.id->url.setFragment(icName);
auto icType = QQmlType(icTypePriv);
icTypePriv->release();
QQmlMetaType::associateInlineComponent(
*type_return, icName, CompositeMetaTypeIds {}, icType);
*type_return = icType;
}
*type_return = QQmlMetaType::inlineComponentTypeForUrl(
type_return->sourceUrl(), splitName.at(2).toString());
return true;
} else {
error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
@ -1530,13 +1482,12 @@ QTypeRevision QQmlImports::updateQmldirContent(
/*!
\internal
*/
bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType)
bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl)
{
importInstance->url = importUrl.toString();
importInstance->uri = name;
importInstance->isInlineComponent = true;
importInstance->version = QTypeRevision::zero();
importInstance->containingType = containingType;
m_unqualifiedset.imports.push_back(importInstance);
m_unqualifiedset.setNeedsSorting(true);
return true;

View File

@ -56,7 +56,6 @@ struct QQmlImportInstance
QString uri; // e.g. QtQuick
QString url; // the base path of the import
QQmlType containingType; // points to the containing type for inline components
QTypeRevision version; // the version imported
bool isLibrary; // true means that this is not a file import
@ -158,8 +157,7 @@ public:
}
bool addInlineComponentImport(
QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl,
QQmlType containingType);
QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
QTypeRevision addFileImport(
QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,

View File

@ -3,11 +3,12 @@
#include "qqmlmetatype_p.h"
#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltypemodule_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlextensionplugin_p.h>
#include <private/qqmltypemodule_p.h>
#include <private/qqmlvaluetype_p.h>
#include <private/qv4executablecompilationunit_p.h>
@ -20,32 +21,6 @@ Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
CompositeMetaTypeIds CompositeMetaTypeIds::fromCompositeName(const QByteArray &name)
{
auto ids = QQmlMetaType::registerInternalCompositeType(name);
ids.refCount = new int;
*ids.refCount = 1;
return ids;
}
void CompositeMetaTypeIds::deref()
{
Q_ASSERT(refCount);
--*refCount;
if (!*refCount) {
delete refCount;
QQmlMetaType::unregisterInternalCompositeType(*this);
refCount = nullptr;
}
}
CompositeMetaTypeIds::~CompositeMetaTypeIds()
{
if (refCount)
deref();
}
struct LockedData : private QQmlMetaTypeData
{
friend class QQmlMetaTypeDataPtr;
@ -178,6 +153,22 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
return d;
}
static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className)
{
QByteArray ptr = className + '*';
QByteArray lst = "QQmlListProperty<" + className + '>';
QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
// Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
ptr_type.id();
lst_type.id();
priv->typeId = ptr_type;
priv->listId = lst_type;
}
static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
const QQmlPrivate::RegisterCompositeType &type)
{
@ -186,7 +177,10 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->setName(QString::fromUtf8(type.uri), elementName);
d->version = type.version;
d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
const QUrl normalized = QQmlTypeLoader::normalize(type.url);
d->extraData.fd->url = normalized;
addQQmlMetaTypeInterfaces(
d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized));
return d;
}
@ -199,9 +193,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->version = type.version;
const QUrl normalized = QQmlTypeLoader::normalize(type.url);
d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
d->extraData.sd->singletonInstanceInfo->url = normalized;
d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
addQQmlMetaTypeInterfaces(
d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized));
return d;
}
@ -319,6 +316,10 @@ void QQmlMetaType::clearTypeRegistrations()
data->undeletableTypes.clear();
data->propertyCaches.clear();
data->inlineComponentTypes.clear();
// Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
QQmlMetaTypeData::CompositeTypes emptyComposites;
emptyComposites.swap(data->compositeTypes);
}
void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
@ -564,26 +565,164 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
return QQmlType(priv);
}
CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
class QQmlMetaTypeRegistrationFailureRecorder
{
QByteArray ptr = className + '*';
QByteArray lst = "QQmlListProperty<" + className + '>';
Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
public:
QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
: data(data)
{
data->setTypeRegistrationFailures(failures);
}
QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
~QQmlMetaTypeRegistrationFailureRecorder()
{
data->setTypeRegistrationFailures(nullptr);
}
// Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
ptr_type.id();
lst_type.id();
QQmlMetaTypeData *data = nullptr;
};
return {ptr_type, lst_type};
static QQmlType createTypeForUrl(
QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
{
const int dot = qualifiedType.indexOf(QLatin1Char('.'));
const QString typeName = dot < 0
? qualifiedType.toString()
: QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
QStringList failures;
QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
// Register the type. Note that the URI parameters here are empty; for
// file type imports, we do not place them in a URI as we don't
// necessarily have a good and unique one (picture a library import,
// which may be found in multiple plugin locations on disk), but there
// are other reasons for this too.
//
// By not putting them in a URI, we prevent the types from being
// registered on a QQmlTypeModule; this is important, as once types are
// placed on there, they cannot be easily removed, meaning if the
// developer subsequently loads a different import (meaning different
// types) with the same URI (using, say, a different plugin path), it is
// very undesirable that we continue to associate the types from the
// "old" URI with that new module.
//
// Not having URIs also means that the types cannot be found by name
// etc, the only way to look them up is through QQmlImports -- for
// better or worse.
const QQmlType::RegistrationType registrationType = mode == QQmlMetaType::Singleton
? QQmlType::CompositeSingletonType
: QQmlType::CompositeType;
if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
// TODO: Ideally we should defer most of this work using some lazy/atomic mechanism
// that creates the details on first use. We must not observably modify
// QQmlTypePrivate after it has been created since it is supposed to be immutable
// and shared across threads.
auto *priv = new QQmlTypePrivate(registrationType);
addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
priv->setName(QString(), typeName);
priv->version = version;
if (mode == QQmlMetaType::Singleton) {
priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
priv->extraData.sd->singletonInstanceInfo->url = url;
priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
} else {
priv->extraData.fd->url = url;
}
data->registerType(priv);
addTypeToData(priv, data);
return QQmlType(priv);
}
// This means that the type couldn't be found by URL, but could not be
// registered either, meaning we most likely were passed some kind of bad
// data.
if (errors) {
QQmlError error;
error.setDescription(failures.join(u'\n'));
errors->prepend(error);
} else {
qWarning("%s", failures.join(u'\n').toLatin1().constData());
}
return QQmlType();
}
void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds)
QQmlType QQmlMetaType::findCompositeType(
const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
CompositeTypeLookupMode mode)
{
QMetaType metaType(typeIds.id);
QMetaType listMetaType(typeIds.listId);
const QUrl normalized = QQmlTypeLoader::normalize(url);
QQmlMetaTypeDataPtr data;
bool urlExists = true;
auto found = data->urlToType.find(normalized);
if (found == data->urlToType.end()) {
found = data->urlToNonFileImportType.find(normalized);
if (found == data->urlToNonFileImportType.end())
urlExists = false;
}
if (urlExists) {
const auto composite = data->compositeTypes.constFind(found.value()->typeId.iface());
if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit)
return QQmlType(*found);
}
const QQmlType type = createTypeForUrl(
data, normalized, QHashedStringRef(), mode, nullptr, QTypeRevision());
if (!urlExists && type.isValid())
data->urlToType.insert(normalized, type.priv());
return type;
}
static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
{
QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType);
priv->setName(QString(), url.fragment());
priv->extraData.id->url = url;
const QByteArray className
= QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment());
addQQmlMetaTypeInterfaces(priv, className);
const QQmlType result(priv);
priv->release();
data->inlineComponentTypes.insert(url, result);
return result;
}
QQmlType QQmlMetaType::findInlineComponentType(
const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
QQmlMetaTypeDataPtr data;
// If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise
// we have to create a new one.
const auto it = data->inlineComponentTypes.constFind(url);
if (it != data->inlineComponentTypes.constEnd()) {
const auto jt = data->compositeTypes.constFind(it->typeId().iface());
if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit)
return *it;
}
return doRegisterInlineComponentType(data, url);
}
void QQmlMetaType::unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType)
{
// This may be called from delayed dtors on shutdown when the data is already gone.
QQmlMetaTypeDataPtr data;
if (data.isValid()) {
@ -591,6 +730,10 @@ void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &t
delete vt;
if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
delete vt;
auto it = data->compositeTypes.constFind(metaType.iface());
if (it != data->compositeTypes.constEnd())
data->compositeTypes.erase(it);
}
QMetaType::unregisterMetaType(metaType);
@ -764,25 +907,6 @@ static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const Q
return false;
}
class QQmlMetaTypeRegistrationFailureRecorder
{
Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
public:
QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
: data(data)
{
data->setTypeRegistrationFailures(failures);
}
~QQmlMetaTypeRegistrationFailureRecorder()
{
data->setTypeRegistrationFailures(nullptr);
}
QQmlMetaTypeData *data = nullptr;
};
QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
QObject *instance, const QString &basePath, const QString &uri,
const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
@ -883,7 +1007,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
bool isCompositeSingleton, QList<QQmlError> *errors,
CompositeTypeLookupMode mode, QList<QQmlError> *errors,
QTypeRevision version)
{
// ### unfortunate (costly) conversion
@ -901,64 +1025,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
return ret;
}
const int dot = qualifiedType.indexOf(QLatin1Char('.'));
const QString typeName = dot < 0
? qualifiedType.toString()
: QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
QStringList failures;
QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
// Register the type. Note that the URI parameters here are empty; for
// file type imports, we do not place them in a URI as we don't
// necessarily have a good and unique one (picture a library import,
// which may be found in multiple plugin locations on disk), but there
// are other reasons for this too.
//
// By not putting them in a URI, we prevent the types from being
// registered on a QQmlTypeModule; this is important, as once types are
// placed on there, they cannot be easily removed, meaning if the
// developer subsequently loads a different import (meaning different
// types) with the same URI (using, say, a different plugin path), it is
// very undesirable that we continue to associate the types from the
// "old" URI with that new module.
//
// Not having URIs also means that the types cannot be found by name
// etc, the only way to look them up is through QQmlImports -- for
// better or worse.
const QQmlType::RegistrationType registrationType = isCompositeSingleton
? QQmlType::CompositeSingletonType
: QQmlType::CompositeType;
if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
auto *priv = new QQmlTypePrivate(registrationType);
priv->setName(QString(), typeName);
priv->version = version;
if (isCompositeSingleton) {
priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
priv->extraData.sd->singletonInstanceInfo->url = url;
priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
} else {
priv->extraData.fd->url = url;
}
data->registerType(priv);
addTypeToData(priv, data);
data->urlToType.insert(url, priv);
return QQmlType(priv);
}
// This means that the type couldn't be found by URL, but could not be
// registered either, meaning we most likely were passed some kind of bad
// data.
if (errors) {
QQmlError error;
error.setDescription(failures.join(u'\n'));
errors->prepend(error);
} else {
qWarning("%s", failures.join(u'\n').toLatin1().constData());
}
return QQmlType();
const QQmlType type = createTypeForUrl(
data, url, qualifiedType, mode, errors, version);
data->urlToType.insert(url, type.priv());
return type;
}
QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
@ -1285,36 +1355,17 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
QQmlType QQmlMetaType::inlineComponentType(const QQmlType &containingType, const QString &name)
QQmlType QQmlMetaType::inlineComponentTypeForUrl(const QUrl &url)
{
const QQmlMetaTypeDataPtr data;
return data->inlineComponentTypes[InlineComponentKey {containingType.priv(), name}];
}
void QQmlMetaType::associateInlineComponent(
const QQmlType &containingType, const QString &name,
const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType)
{
bool const reuseExistingType = existingType.isValid();
auto priv = reuseExistingType
? const_cast<QQmlTypePrivate *>(existingType.priv())
: new QQmlTypePrivate { QQmlType::RegistrationType::InlineComponentType } ;
priv->setName( QString::fromUtf8(existingType.typeName()), name);
QUrl icUrl(existingType.sourceUrl());
icUrl.setFragment(name);
priv->extraData.id->url = icUrl;
priv->extraData.id->containingType = containingType.priv();
priv->typeId = metaTypeIds.id;
priv->listId = metaTypeIds.listId;
QQmlType icType(priv);
QQmlMetaTypeDataPtr data;
data->inlineComponentTypes.insert({containingType.priv(), name}, icType);
const auto it = data->inlineComponentTypes.constFind(url);
if (it != data->inlineComponentTypes.constEnd())
return *it;
if (!reuseExistingType)
priv->release();
return doRegisterInlineComponentType(data, url);
}
/*!
Returns a QQmlPropertyCache for \a obj if one is available.
@ -1475,7 +1526,7 @@ static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTy
{
for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end();
it != end; ++it) {
if (it.key().containingType != d)
if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl()))
continue;
const QQmlTypePrivate *icPriv = it->priv();
@ -1831,30 +1882,66 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMet
return data->findPropertyCacheInCompositeTypes(t);
}
void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
void QQmlMetaType::registerInternalCompositeType(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
compilationUnit->isRegistered = true;
QQmlMetaTypeDataPtr data;
// The QQmlCompiledData is not referenced here, but it is removed from this
// hash in the QQmlCompiledData destructor
data->compositeTypes.insert(compilationUnit->typeIds.id.iface(), compilationUnit);
auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
Q_ASSERT(iface);
const auto it = data->compositeTypes.constFind(iface);
Q_ASSERT(it == data->compositeTypes.constEnd() || *it == compilationUnit);
data->compositeTypes.insert(iface, compilationUnit);
};
doInsert(compilationUnit->qmlType.typeId().iface());
for (auto &&inlineData: compilationUnit->inlineComponentData)
data->compositeTypes.insert(inlineData.typeIds.id.iface(), compilationUnit);
doInsert(inlineData.qmlType.typeId().iface());
}
void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
void QQmlMetaType::unregisterInternalCompositeType(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
compilationUnit->isRegistered = false;
QQmlMetaTypeDataPtr data;
data->compositeTypes.remove(compilationUnit->typeIds.id.iface());
for (auto&& icDatum: compilationUnit->inlineComponentData)
data->compositeTypes.remove(icDatum.typeIds.id.iface());
auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
if (!iface)
return;
const auto it = data->compositeTypes.constFind(iface);
if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
data->compositeTypes.erase(it);
};
doRemove(compilationUnit->qmlType.typeId().iface());
for (auto &&inlineData: compilationUnit->inlineComponentData)
doRemove(inlineData.qmlType.typeId().iface());
}
QV4::ExecutableCompilationUnit *QQmlMetaType::obtainExecutableCompilationUnit(QMetaType type)
int QQmlMetaType::countInternalCompositeTypeSelfReferences(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
QQmlMetaTypeDataPtr data;
int result = 0;
auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
if (!iface)
return;
const auto it = data->compositeTypes.constFind(iface);
if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
++result;
};
doCheck(compilationUnit->qmlType.typeId().iface());
for (auto &&inlineData: compilationUnit->inlineComponentData)
doCheck(inlineData.qmlType.typeId().iface());
return result;
}
QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlMetaType::obtainExecutableCompilationUnit(
QMetaType type)
{
const QQmlMetaTypeDataPtr data;
return data->compositeTypes.value(type.iface());

View File

@ -30,74 +30,55 @@ class QQmlValueType;
namespace QV4 { class ExecutableCompilationUnit; }
struct CompositeMetaTypeIds
{
private:
int *refCount = nullptr;
void deref();
void ref()
{
Q_ASSERT(refCount);
++*refCount;
}
public:
CompositeMetaTypeIds() = default;
CompositeMetaTypeIds(QMetaType id, QMetaType listId) : id(id), listId(listId) {}
CompositeMetaTypeIds(const CompositeMetaTypeIds &other)
: refCount(other.refCount), id(other.id), listId(other.listId)
{
if (refCount)
ref();
}
CompositeMetaTypeIds(CompositeMetaTypeIds &&other)
: refCount(other.refCount), id(other.id), listId(other.listId)
{
other.refCount = nullptr;
}
CompositeMetaTypeIds &operator=(const CompositeMetaTypeIds &other)
{
if (refCount)
deref();
refCount = other.refCount;
id = other.id;
listId = other.listId;
if (refCount)
ref();
return *this;
}
CompositeMetaTypeIds &operator=(CompositeMetaTypeIds &&other)
{
if (refCount)
deref();
refCount = other.refCount;
id = other.id;
listId = other.listId;
other.refCount = nullptr;
return *this;
}
~CompositeMetaTypeIds();
static CompositeMetaTypeIds fromCompositeName(const QByteArray &name);
public:
QMetaType id;
QMetaType listId;
bool isValid() const { return id.isValid() && listId.isValid(); }
};
class Q_QML_PRIVATE_EXPORT QQmlMetaType
{
friend struct CompositeMetaTypeIds;
friend class QQmlDesignerMetaObject;
static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className);
static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds);
public:
enum class RegistrationResult {
Success,
Failure,
NoRegistrationFunction
};
static QUrl inlineComponentUrl(const QUrl &baseUrl, const QString &name)
{
QUrl icUrl = baseUrl;
icUrl.setFragment(name);
return icUrl;
}
static bool equalBaseUrls(const QUrl &aUrl, const QUrl &bUrl)
{
// Everything but fragment has to match
return aUrl.port() == bUrl.port()
&& aUrl.scheme() == bUrl.scheme()
&& aUrl.userName() == bUrl.userName()
&& aUrl.password() == bUrl.password()
&& aUrl.host() == bUrl.host()
&& aUrl.path() == bUrl.path()
&& aUrl.query() == bUrl.query();
}
enum CompositeTypeLookupMode {
NonSingleton,
Singleton,
};
static QQmlType findCompositeType(
const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
CompositeTypeLookupMode mode = NonSingleton);
static QQmlType findInlineComponentType(
const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
static QQmlType findInlineComponentType(
const QUrl &baseUrl, const QString &name,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
return findInlineComponentType(inlineComponentUrl(baseUrl, name), compilationUnit);
}
static void unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType);
static QQmlType registerType(const QQmlPrivate::RegisterType &type);
static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
@ -106,9 +87,15 @@ public:
static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath,
const QString &uri, const QString &typeNamespace,
QTypeRevision version, QList<QQmlError> *errors);
static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
bool isCompositeSingleton, QList<QQmlError> *errors,
CompositeTypeLookupMode mode, QList<QQmlError> *errors,
QTypeRevision version = QTypeRevision());
static QQmlType inlineComponentTypeForUrl(const QUrl &url);
static QQmlType inlineComponentTypeForUrl(const QUrl &baseUrl, const QString &name)
{
return inlineComponentTypeForUrl(inlineComponentUrl(baseUrl, name));
}
static void unregisterType(int type);
@ -143,8 +130,6 @@ public:
static QQmlType qmlListType(QMetaType metaType);
static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false);
static QQmlType inlineComponentType(const QQmlType &containingType, const QString &name);
static void associateInlineComponent(const QQmlType &containingType, const QString &name, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType);
static QQmlPropertyCache::ConstPtr propertyCache(
QObject *object, QTypeRevision version = QTypeRevision());
@ -219,8 +204,9 @@ public:
static void removeFromInlineComponents(
InlineComponentContainer &container, const QQmlTypePrivate *reference)
{
const QUrl referenceUrl = QQmlType(reference).sourceUrl();
for (auto it = container.begin(), end = container.end(); it != end;) {
if (it.key().containingType == reference)
if (equalBaseUrls(it.key(), referenceUrl))
it = container.erase(it);
else
++it;
@ -281,9 +267,14 @@ public:
}
static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
static QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(QMetaType type);
static void registerInternalCompositeType(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
static void unregisterInternalCompositeType(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
static int countInternalCompositeTypeSelfReferences(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
static QQmlRefPointer<QV4::ExecutableCompilationUnit> obtainExecutableCompilationUnit(
QMetaType type);
};
Q_DECLARE_TYPEINFO(QQmlMetaType, Q_RELOCATABLE_TYPE);

View File

@ -15,8 +15,12 @@ QQmlMetaTypeData::QQmlMetaTypeData()
QQmlMetaTypeData::~QQmlMetaTypeData()
{
for (auto iter = compositeTypes.cbegin(), end = compositeTypes.cend(); iter != end; ++iter)
iter.value()->isRegistered = false;
{
// Unregister all remaining composite types.
// Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
CompositeTypes emptyComposites;
emptyComposites.swap(compositeTypes);
}
propertyCaches.clear();
// Do this before the attached properties disappear.
@ -237,13 +241,11 @@ QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
}
static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
QMetaType t,
const QHash<const QtPrivate::QMetaTypeInterface *,
QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
if (t != (*iter)->typeIds.id) {
QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
if (t != (*iter)->qmlType.typeId()) {
// this is an inline component, and what we have in the iterator is currently the parent compilation unit
for (auto &&icDatum: (*iter)->inlineComponentData)
if (icDatum.typeIds.id == t)
if (icDatum.qmlType.typeId() == t)
return (*iter)->propertyCaches.at(icDatum.objectIndex);
}
return (*iter)->rootPropertyCache();

View File

@ -25,23 +25,6 @@
QT_BEGIN_NAMESPACE
struct InlineComponentKey
{
const QQmlTypePrivate *containingType = nullptr;
QString name;
private:
friend bool operator==(const InlineComponentKey &a, const InlineComponentKey &b)
{
return a.containingType == b.containingType && a.name == b.name;
}
friend size_t qHash(const InlineComponentKey &byId, size_t seed = 0)
{
return qHashMulti(seed, byId.containingType, byId.name);
}
};
class QQmlTypePrivate;
struct QQmlMetaTypeData
{
@ -56,7 +39,7 @@ struct QQmlMetaTypeData
using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>;
Names nameToType;
typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
typedef QHash<QUrl, const QQmlTypePrivate *> Files; //For file imported composite types only
Files urlToType;
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
@ -66,8 +49,11 @@ struct QQmlMetaTypeData
MetaObjects metaObjectToType;
QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches;
QHash<int, QQmlValueType *> metaTypeToValueType;
QHash<const QtPrivate::QMetaTypeInterface *, QV4::ExecutableCompilationUnit *> compositeTypes;
QHash<InlineComponentKey, QQmlType> inlineComponentTypes;
using CompositeTypes = QHash<const QtPrivate::QMetaTypeInterface *,
QQmlRefPointer<QV4::ExecutableCompilationUnit>>;
CompositeTypes compositeTypes;
QHash<QUrl, QQmlType> inlineComponentTypes;
struct VersionedUri {
VersionedUri() = default;

View File

@ -66,29 +66,55 @@ QMetaType QQmlPropertyCacheCreatorBase::listTypeForPropertyType(QV4::CompiledDat
return QMetaType {};
}
QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
template<typename BaseNameHandler, typename FailHandler>
auto processUrlForClassName(
const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler)
{
const QString path = url.path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
// Not a reusable type if we don't have an absolute Url
const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash <= -1)
return QByteArray();
return failHandler();
// ### this might not be correct for .ui.qml files
const QStringView nameBase = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5);
const QStringView baseName = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5);
// Not a reusable type if it doesn't start with a upper case letter.
if (nameBase.isEmpty() || !nameBase.at(0).isUpper())
return QByteArray();
return nameBase.toUtf8() + "_QMLTYPE_" +
QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
return (!baseName.isEmpty() && baseName.at(0).isUpper())
? baseNameHandler(baseName)
: failHandler();
}
QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(const QUrl &baseUrl, int icId)
bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url)
{
QByteArray baseName = createClassNameTypeByUrl(baseUrl);
if (baseName.isEmpty())
baseName = QByteArray("ANON_QML_IC_") + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
baseName += "_" + QByteArray::number(icId);
return baseName;
return processUrlForClassName(url, [](QStringView) {
return true;
}, []() {
return false;
});
}
QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
{
return processUrlForClassName(url, [](QStringView nameBase) {
return QByteArray(nameBase.toUtf8() + "_QMLTYPE_"
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
}, []() {
return QByteArray();
});
}
QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(
const QUrl &baseUrl, const QString &name)
{
QByteArray baseName = processUrlForClassName(baseUrl, [](QStringView nameBase) {
return QByteArray(nameBase.toUtf8() + "_QMLTYPE_");
}, []() {
return QByteArray("ANON_QML_IC_");
});
return baseName + name.toUtf8() + '_'
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
}
QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(

View File

@ -69,9 +69,10 @@ public:
static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type);
static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type);
static bool canCreateClassNameTypeByUrl(const QUrl &url);
static QByteArray createClassNameTypeByUrl(const QUrl &url);
static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId);
static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name);
struct IncrementalResult {
// valid if and only if an error occurred
@ -157,7 +158,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
, typeClassName(typeClassName)
, currentRoot(-1)
{
propertyCaches->resize(objectContainer->objectCount());
propertyCaches->resetAndResize(objectContainer->objectCount());
using namespace icutils;
@ -626,35 +627,29 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
// inline components are not necessarily valid yet
Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
CompositeMetaTypeIds typeIds;
QQmlType compositeType;
if (qmltype.isInlineComponentType()) {
const QString icName = qmltype.elementName();
auto containingType = qmltype.containingType();
if (containingType.isValid()) {
const QQmlType icType
= QQmlMetaType::inlineComponentType(containingType, icName);
typeIds = {icType.typeId(), icType.qListTypeId()};
} else {
typeIds = {};
}
if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type
typeIds = objectContainer->typeIdsForComponent(icName);
Q_ASSERT(typeIds.isValid());
compositeType = QQmlMetaType::inlineComponentTypeForUrl(
qmltype.sourceUrl(), icName);
if (!compositeType.isValid()) // type has not been registered yet, we must be in containing type
compositeType = objectContainer->qmlTypeForComponent(icName);
Q_ASSERT(compositeType.isValid());
} else if (selfReference) {
typeIds = objectContainer->typeIdsForComponent();
compositeType = objectContainer->qmlTypeForComponent();
} else {
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
auto compilationUnit = tdata->compilationUnit();
typeIds = compilationUnit->typeIdsForComponent();
compositeType = compilationUnit->qmlTypeForComponent();
}
if (p->isList()) {
propertyType = typeIds.listId;
propertyType = compositeType.qListTypeId();
} else {
propertyType = typeIds.id;
propertyType = compositeType.typeId();
}
} else {
if (p->isList())
@ -714,16 +709,16 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
if (!qmltype.isComposite()) {
const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
if (!typeId.isValid() && qmltype.isInlineComponentType()) {
const auto typeIds = objectContainer->typeIdsForComponent(qmltype.elementName());
return param.isList() ? typeIds.listId : typeIds.id;
const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
} else {
return typeId;
}
}
if (selfReference) {
const auto typeIds = objectContainer->typeIdsForComponent();
return param.isList() ? typeIds.listId : typeIds.id;
const QQmlType qmlType = objectContainer->qmlTypeForComponent();
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
}
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
@ -732,7 +727,9 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
auto compilationUnit = tdata->compilationUnit();
return param.isList() ? compilationUnit->typeIds.listId : compilationUnit->typeIds.id;
return param.isList()
? compilationUnit->qmlType.qListTypeId()
: compilationUnit->qmlType.typeId();
}
template <typename ObjectContainer>
@ -825,11 +822,11 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
if (referencedType.isValid()) {
*type = referencedType.typeId();
if (!type->isValid() && referencedType.isInlineComponentType()) {
*type = objectContainer->typeIdsForComponent(referencedType.elementName()).id;
*type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
Q_ASSERT(type->isValid());
}
} else {
*type = typeRef->compilationUnit()->typeIds.id;
*type = typeRef->compilationUnit()->qmlType.typeId();
}
*version = typeRef->version();

View File

@ -643,7 +643,7 @@ bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum : compilationUnit->inlineComponentData) {
if (icDatum.typeIds.id == to) {
if (icDatum.qmlType.typeId() == to) {
toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}
@ -753,7 +753,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *p
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum: compilationUnit->inlineComponentData) {
if (icDatum.typeIds.id == property->propType()) {
if (icDatum.qmlType.typeId() == property->propType()) {
propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}

View File

@ -68,6 +68,12 @@ QQmlTypePrivate::~QQmlTypePrivate()
qDeleteAll(scopedEnums);
for (const auto &metaObject : metaObjects)
free(metaObject.metaObject);
if (const auto &iface = typeId.iface()) {
if (iface->metaObjectFn == &dynamicQmlMetaObject)
QQmlMetaType::unregisterInternalCompositeType(typeId, listId);
}
switch (regType) {
case QQmlType::CppType:
delete extraData.cd->customParser;
@ -404,12 +410,6 @@ void QQmlTypePrivate::insertEnumsFromPropertyCache(
insertEnums(cppMetaObject);
}
void QQmlTypePrivate::setContainingType(QQmlType *containingType)
{
Q_ASSERT(regType == QQmlType::InlineComponentType);
extraData.id->containingType = containingType->d.data();
}
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
{
module = uri;
@ -928,14 +928,6 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
return -1;
}
QQmlType QQmlType::containingType() const
{
Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
auto ret = QQmlType {d->extraData.id->containingType};
Q_ASSERT(!ret.isInlineComponentType());
return ret;
}
void QQmlType::createProxy(QObject *instance) const
{
if (!d->metaObjects.isEmpty())

View File

@ -39,7 +39,6 @@ class QQmlPropertyCache;
namespace QV4 {
struct String;
}
struct CompositeMetaTypeIds;
class Q_QML_PRIVATE_EXPORT QQmlType
{
@ -159,8 +158,6 @@ public:
AnyRegistrationType = 255
};
QQmlType containingType() const;
void createProxy(QObject *instance) const;
private:

View File

@ -36,7 +36,6 @@ public:
void initEnums(QQmlEnginePrivate *engine) const;
void insertEnums(const QMetaObject *metaObject) const;
void insertEnumsFromPropertyCache(const QQmlPropertyCache::ConstPtr &cache) const;
void setContainingType(QQmlType *containingType);
QUrl sourceUrl() const
{
@ -111,11 +110,6 @@ public:
struct QQmlInlineTypeData
{
QUrl url;
// The containing type stores a pointer to the inline component type
// Using QQmlType here would create a reference cycle
// As the inline component type cannot outlive the containing type
// this should still be fine
QQmlTypePrivate const * containingType = nullptr;
};
using QQmlSequenceTypeData = QMetaSequence;

View File

@ -259,9 +259,9 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
document->imports.append(import);
}
CompositeMetaTypeIds QQmlTypeCompiler::typeIdsForComponent(const QString &inlineComponentName) const
QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
{
return typeData->typeIds(inlineComponentName);
return typeData->qmlType(inlineComponentName);
}
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)

View File

@ -108,7 +108,7 @@ public:
return resolvedTypes->value(id);
}
CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const;
QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
private:
QList<QQmlError> errors;

View File

@ -74,11 +74,11 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
CompositeMetaTypeIds QQmlTypeData::typeIds(const QString &inlineComponentName) const
QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
{
if (inlineComponentName.isEmpty())
return m_typeIds;
return m_inlineComponentData[inlineComponentName].typeIds;
return m_qmlType;
return m_inlineComponentData[inlineComponentName].qmlType;
}
bool QQmlTypeData::tryLoadFromDiskCache()
@ -168,7 +168,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
auto importUrl = finalUrl();
importUrl.setFragment(nameString);
auto import = new QQmlImportInstance();
m_importCache->addInlineComponentImport(import, nameString, importUrl, QQmlType());
m_importCache->addInlineComponentImport(import, nameString, importUrl);
}
return true;
@ -289,13 +289,18 @@ namespace {
template<typename ObjectContainer>
void setupICs(
const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
const QUrl &finalUrl) {
const QUrl &baseUrl, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
Q_ASSERT(icData->empty());
for (int i = 0; i != container->objectCount(); ++i) {
auto root = container->objectAt(i);
for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
const QByteArray &className = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(finalUrl, it->objectIndex);
InlineComponentData icDatum(CompositeMetaTypeIds::fromCompositeName(className), int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
// We cannot re-use a previously finalized inline component type here. We need our own.
// We can and should re-use speculative type references, though.
InlineComponentData icDatum(
QQmlMetaType::findInlineComponentType(
baseUrl, container->stringAt(it->nameIndex), compilationUnit),
int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
icData->insert(container->stringAt(it->nameIndex), icDatum);
}
}
@ -370,15 +375,11 @@ void QQmlTypeData::done()
++it) {
const TypeReference &type = *it;
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
const QQmlType containingType = type.type.isInlineComponentType()
? type.type.containingType()
: QQmlType();
if (containingType.isValid()) {
const QQmlType ic = QQmlMetaType::inlineComponentType(
containingType, type.type.elementName());
// Only if we create the IC from an actual CU, we have valid metatypes.
if (!ic.typeId().isValid()) {
if (type.type.isInlineComponentType()) {
const QUrl url = type.type.sourceUrl();
if (!QQmlMetaType::equalBaseUrls(url, finalUrl())
&& !QQmlMetaType::obtainExecutableCompilationUnit(type.type.typeId())) {
const QString &typeName = stringAt(it.key());
int lastDot = typeName.lastIndexOf(u'.');
createError(
@ -407,16 +408,22 @@ void QQmlTypeData::done()
}
}
m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
if (!m_typeClassName.isEmpty())
m_typeIds = CompositeMetaTypeIds::fromCompositeName(m_typeClassName);
if (m_document) {
setupICs(m_document, &m_inlineComponentData, finalUrl());
} else {
setupICs(m_compiledData, &m_inlineComponentData, finalUrl());
if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
const bool isSingleton = m_document
? m_document.data()->isSingleton()
: (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
m_qmlType = QQmlMetaType::findCompositeType(
finalUrl(), m_compiledData, isSingleton
? QQmlMetaType::Singleton
: QQmlMetaType::NonSingleton);
m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
}
if (m_document)
setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
else
setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
QV4::ResolvedTypeReferenceMap resolvedTypeCache;
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
{
@ -502,7 +509,7 @@ void QQmlTypeData::done()
}
}
m_compiledData->finalizeCompositeType(typeIds());
m_compiledData->finalizeCompositeType(qmlType());
}
{
@ -530,34 +537,6 @@ void QQmlTypeData::done()
}
}
// associate inline components to root component
{
auto fileName = finalUrl().fileName();
QStringView typeName = [&]() {
// extract base name (QFileInfo::baseName would require constructing a QFileInfo)
auto dotIndex = fileName.indexOf(u'.');
if (dotIndex < 0)
return QStringView();
return QStringView(fileName).first(dotIndex);
}();
// typeName can be empty if a QQmlComponent was constructed with an empty QUrl parameter
if (!typeName.isEmpty() && typeName.at(0).isUpper() && !m_inlineComponentData.isEmpty()) {
QHashedStringRef const hashedStringRef { typeName };
QList<QQmlError> errors;
auto type = QQmlMetaType::typeForUrl(finalUrlString(), hashedStringRef, false, &errors);
Q_ASSERT(errors.empty());
if (type.isValid()) {
for (auto const &icDatum : std::as_const(m_inlineComponentData)) {
Q_ASSERT(icDatum.typeIds.isValid());
const QString icName = m_compiledData->stringAt(icDatum.nameIndex);
QQmlType existingType = QQmlMetaType::inlineComponentType(type, icName);
QQmlMetaType::associateInlineComponent(
type, icName, icDatum.typeIds, existingType);
}
}
}
}
{
// Collect imported scripts
m_compiledData->dependentScripts.reserve(m_scripts.size());
@ -706,18 +685,13 @@ void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
void QQmlTypeData::continueLoadFromIR()
{
QQmlType containingType;
auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
QTypeRevision version;
QQmlImportNamespace *ns = nullptr;
m_importCache->resolveType(containingTypeName, &containingType, &version, &ns);
for (auto const& object: m_document->objects) {
for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
QString const nameString = m_document->stringAt(it->nameIndex);
auto importUrl = finalUrl();
importUrl.setFragment(nameString);
auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
m_importCache->addInlineComponentImport(import, nameString, importUrl, containingType);
m_importCache->addInlineComponentImport(import, nameString, importUrl);
}
}
@ -925,11 +899,11 @@ void QQmlTypeData::resolveTypes()
addDependency(ref.typeData.data());
}
if (ref.type.isInlineComponentType()) {
auto containingType = ref.type.containingType();
if (containingType.isValid()) {
auto const url = containingType.sourceUrl();
if (url.isValid()) {
auto typeData = typeLoader()->getType(url);
QUrl containingTypeUrl = ref.type.sourceUrl();
containingTypeUrl.setFragment(QString());
if (!containingTypeUrl.isEmpty()) {
auto typeData = typeLoader()->getType(containingTypeUrl);
if (typeData.data() != this) {
ref.typeData = typeData;
addDependency(typeData.data());
}
@ -972,11 +946,7 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
if (resolvedType->type.isInlineComponentType()) {
// Inline component which is part of an already resolved type
QString icName;
if (qmlType.containingType().isValid())
icName = qmlType.elementName();
else
icName = resolvedType->type.elementName();
QString icName = qmlType.elementName();
Q_ASSERT(!icName.isEmpty());
const auto compilationUnit = resolvedType->typeData->compilationUnit();
@ -986,14 +956,17 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
Q_ASSERT(ref->type().isInlineComponentType());
}
} else if (resolvedType->type.isInlineComponentType()) {
// Inline component, defined in the file we are currently compiling
ref->setType(qmlType);
if (qmlType.isValid()) {
// Inline component
// If it's defined in the same file we're currently compiling, we don't want to use it.
// We're going to fill in the property caches later after all.
if (qmlType.isValid()
&& !QQmlMetaType::equalBaseUrls(finalUrl(), qmlType.sourceUrl())) {
// this is required for inline components in singletons
const QMetaType type
= QQmlMetaType::inlineComponentType(qmlType, qmlType.elementName()).typeId();
auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type);
if (exUnit) {
const QMetaType type = qmlType.typeId();
if (auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type)) {
ref->setCompilationUnit(exUnit);
ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type));
}

View File

@ -68,7 +68,7 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
CompositeMetaTypeIds typeIds(const QString &inlineComponentName = QString()) const;
QQmlType qmlType(const QString &inlineComponentName = QString()) const;
QByteArray typeClassName() const { return m_typeClassName; }
SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
@ -120,8 +120,8 @@ private:
QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
// Used for self-referencing types, otherwise -1.
CompositeMetaTypeIds m_typeIds;
// Used for self-referencing types, otherwise invalid.
QQmlType m_qmlType;
QByteArray m_typeClassName; // used for meta-object later
using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>;

View File

@ -1338,15 +1338,29 @@ void QQmlTypeLoader::trimCache()
// typeData->m_compiledData may be set early on in the proccess of loading a file, so
// it's important to check the general loading status of the typeData before making any
// other decisions.
if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete())
&& (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) {
// There are no live objects of this type
iter.value()->release();
iter = m_typeCache.erase(iter);
deletedOneType = true;
} else {
if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
++iter;
continue;
}
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit
= typeData->m_compiledData;
if (compilationUnit) {
if (compilationUnit->count()
> QQmlMetaType::countInternalCompositeTypeSelfReferences(
compilationUnit) + 1) {
++iter;
continue;
}
QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
Q_ASSERT(compilationUnit->count() == 1);
}
// There are no live objects of this type
iter.value()->release();
iter = m_typeCache.erase(iter);
deletedOneType = true;
}
if (!deletedOneType)

View File

@ -379,11 +379,13 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper,
QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
if (ExecutableCompilationUnit *cu = td->compilationUnit())
myQmlType = QQmlMetaType::metaObjectForType(cu->typeIds.id);
myQmlType = QQmlMetaType::metaObjectForType(cu->qmlType.typeId());
else
return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
if (myQmlType.isNull())
return Encode(false);
}
const QMetaObject *theirType = wrapperObject->metaObject();

View File

@ -2029,6 +2029,10 @@ void tst_QmlCppCodegen::invisibleListElementType()
void tst_QmlCppCodegen::invisibleSingleton()
{
// We may have seen Style.qml as singleton before, which would make the assignment pass.
// So let's flush the type registry.
qmlClearTypeRegistrations();
QQmlEngine engine;
const QUrl copy(u"qrc:/qt/qml/TestTypes/hidden/Main.qml"_s);
QQmlComponent c(&engine, copy);

View File

@ -5762,7 +5762,7 @@ void tst_qqmllanguage::selfReference()
const QMetaObject *metaObject = o->metaObject();
QMetaProperty selfProperty = metaObject->property(metaObject->indexOfProperty("self"));
QCOMPARE(selfProperty.metaType().id(), compilationUnit->typeIds.id.id());
QCOMPARE(selfProperty.metaType().id(), compilationUnit->qmlType.typeId().id());
QByteArray typeName = selfProperty.typeName();
QVERIFY(typeName.endsWith('*'));
@ -5771,7 +5771,7 @@ void tst_qqmllanguage::selfReference()
QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()"));
QVERIFY(selfFunction.isValid());
QCOMPARE(selfFunction.returnType(), compilationUnit->typeIds.id.id());
QCOMPARE(selfFunction.returnType(), compilationUnit->qmlType.typeId().id());
QMetaMethod selfSignal;
@ -5785,7 +5785,7 @@ void tst_qqmllanguage::selfReference()
QVERIFY(selfSignal.isValid());
QCOMPARE(selfSignal.parameterCount(), 1);
QCOMPARE(selfSignal.parameterType(0), compilationUnit->typeIds.id.id());
QCOMPARE(selfSignal.parameterType(0), compilationUnit->qmlType.typeId().id());
}
void tst_qqmllanguage::selfReferencingSingleton()
@ -6772,11 +6772,17 @@ void tst_qqmllanguage::bareInlineComponent()
QVERIFY(type.module().isEmpty());
tab1Found = true;
const QQmlType leftTab = QQmlMetaType::inlineComponentType(type, "LeftTab");
QCOMPARE(leftTab.containingType(), type);
const QQmlType leftTab = QQmlMetaType::inlineComponentTypeForUrl(
type.sourceUrl(), "LeftTab");
QUrl leftUrl = leftTab.sourceUrl();
leftUrl.setFragment(QString());
QCOMPARE(leftUrl, type.sourceUrl());
const QQmlType rightTab = QQmlMetaType::inlineComponentType(type, "RightTab");
QCOMPARE(rightTab.containingType(), type);
const QQmlType rightTab = QQmlMetaType::inlineComponentTypeForUrl(
type.sourceUrl(), "RightTab");
QUrl rightUrl = rightTab.sourceUrl();
rightUrl.setFragment(QString());
QCOMPARE(rightUrl, type.sourceUrl());
}
}
QVERIFY(tab1Found);