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:
parent
4a1e5d8e74
commit
b48bb41681
|
@ -472,6 +472,12 @@ struct Q_QML_COMPILER_PRIVATE_EXPORT Document
|
||||||
|
|
||||||
QV4::CompiledData::CompilationUnit javaScriptCompilationUnit;
|
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); }
|
int registerString(const QString &str) { return jsGenerator.registerString(str); }
|
||||||
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
|
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,11 @@ public:
|
||||||
using NodeList = std::vector<Node>;
|
using NodeList = std::vector<Node>;
|
||||||
using AdjacencyList = std::vector<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>
|
template<typename ObjectContainer, typename InlineComponent>
|
||||||
void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
|
void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
|
||||||
AdjacencyList &adjacencyList, NodeList &nodes,
|
AdjacencyList &adjacencyList, NodeList &nodes,
|
||||||
|
@ -75,7 +80,7 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
|
||||||
if (targetTypeRef) {
|
if (targetTypeRef) {
|
||||||
const auto targetType = targetTypeRef->type();
|
const auto targetType = targetTypeRef->type();
|
||||||
if (targetType.isInlineComponentType()
|
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){
|
auto icIt = std::find_if(allICs.cbegin(), allICs.cend(), [&](const QV4::CompiledData::InlineComponent &icSearched){
|
||||||
return objectContainer->stringAt(icSearched.nameIndex)
|
return objectContainer->stringAt(icSearched.nameIndex)
|
||||||
== targetType.elementName();
|
== targetType.elementName();
|
||||||
|
|
|
@ -859,8 +859,9 @@ ExecutionEngine::~ExecutionEngine()
|
||||||
delete identifierTable;
|
delete identifierTable;
|
||||||
delete memoryManager;
|
delete memoryManager;
|
||||||
|
|
||||||
|
// Take a temporary reference to the CU so that it doesn't disappear during unlinking.
|
||||||
while (!compilationUnits.isEmpty())
|
while (!compilationUnits.isEmpty())
|
||||||
(*compilationUnits.begin())->unlink();
|
QQmlRefPointer<ExecutableCompilationUnit>(*compilationUnits.begin())->unlink();
|
||||||
|
|
||||||
delete bumperPointerAllocator;
|
delete bumperPointerAllocator;
|
||||||
delete regExpCache;
|
delete regExpCache;
|
||||||
|
|
|
@ -272,12 +272,11 @@ void ExecutableCompilationUnit::unlink()
|
||||||
if (engine)
|
if (engine)
|
||||||
nextCompilationUnit.remove();
|
nextCompilationUnit.remove();
|
||||||
|
|
||||||
if (isRegistered) {
|
// Clear the QQmlTypes but not the property caches.
|
||||||
Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
|
// The property caches may still be necessary to resolve further types.
|
||||||
QQmlMetaType::unregisterInternalCompositeType(this);
|
qmlType = QQmlType();
|
||||||
}
|
for (auto &ic : inlineComponentData)
|
||||||
|
ic.qmlType = QQmlType();
|
||||||
propertyCaches.clear();
|
|
||||||
|
|
||||||
if (runtimeLookups) {
|
if (runtimeLookups) {
|
||||||
for (uint i = 0; i < data->lookupTableSize; ++i)
|
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
|
// Add to type registry of composites
|
||||||
if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
|
if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
|
||||||
// typeIds is only valid for types that have references to themselves.
|
// qmlType is only valid for types that have references to themselves.
|
||||||
if (!types.isValid())
|
if (type.isValid()) {
|
||||||
types = CompositeMetaTypeIds::fromCompositeName(rootPropertyCache()->className());
|
qmlType = type;
|
||||||
typeIds = types;
|
} else {
|
||||||
QQmlMetaType::registerInternalCompositeType(this);
|
qmlType = QQmlMetaType::findCompositeType(
|
||||||
|
finalUrl(), this, (unitData()->flags & CompiledData::Unit::IsSingleton)
|
||||||
|
? QQmlMetaType::Singleton
|
||||||
|
: QQmlMetaType::NonSingleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
QQmlMetaType::registerInternalCompositeType(this);
|
||||||
} else {
|
} else {
|
||||||
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
|
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
|
||||||
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
|
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
|
||||||
Q_ASSERT(typeRef);
|
Q_ASSERT(typeRef);
|
||||||
if (const auto compilationUnit = typeRef->compilationUnit()) {
|
if (const auto compilationUnit = typeRef->compilationUnit())
|
||||||
typeIds = compilationUnit->typeIds;
|
qmlType = compilationUnit->qmlType;
|
||||||
} else {
|
else
|
||||||
const auto type = typeRef->type();
|
qmlType = typeRef->type();
|
||||||
typeIds = CompositeMetaTypeIds{ type.typeId(), type.qListTypeId() };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect some data for instantiation later.
|
// Collect some data for instantiation later.
|
||||||
|
@ -520,12 +522,11 @@ bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentType
|
||||||
sizeof(data->dependencyMD5Checksum)) == 0;
|
sizeof(data->dependencyMD5Checksum)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent(
|
QQmlType ExecutableCompilationUnit::qmlTypeForComponent(const QString &inlineComponentName) const
|
||||||
const QString &inlineComponentName) const
|
|
||||||
{
|
{
|
||||||
if (inlineComponentName.isEmpty())
|
if (inlineComponentName.isEmpty())
|
||||||
return typeIds;
|
return qmlType;
|
||||||
return inlineComponentData[inlineComponentName].typeIds;
|
return inlineComponentData[inlineComponentName].qmlType;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ExecutableCompilationUnit::moduleRequests() const
|
QStringList ExecutableCompilationUnit::moduleRequests() const
|
||||||
|
|
|
@ -34,15 +34,17 @@ class QQmlEnginePrivate;
|
||||||
struct InlineComponentData {
|
struct InlineComponentData {
|
||||||
|
|
||||||
InlineComponentData() = default;
|
InlineComponentData() = default;
|
||||||
InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount)
|
InlineComponentData(
|
||||||
: typeIds(typeIds)
|
const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount,
|
||||||
|
int totalBindingCount, int totalParserStatusCount)
|
||||||
|
: qmlType(qmlType)
|
||||||
, objectIndex(objectIndex)
|
, objectIndex(objectIndex)
|
||||||
, nameIndex(nameIndex)
|
, nameIndex(nameIndex)
|
||||||
, totalObjectCount(totalObjectCount)
|
, totalObjectCount(totalObjectCount)
|
||||||
, totalBindingCount(totalBindingCount)
|
, totalBindingCount(totalBindingCount)
|
||||||
, totalParserStatusCount(totalParserStatusCount) {}
|
, totalParserStatusCount(totalParserStatusCount) {}
|
||||||
|
|
||||||
CompositeMetaTypeIds typeIds;
|
QQmlType qmlType;
|
||||||
int objectIndex = -1;
|
int objectIndex = -1;
|
||||||
int nameIndex = -1;
|
int nameIndex = -1;
|
||||||
int totalObjectCount = 0;
|
int totalObjectCount = 0;
|
||||||
|
@ -126,7 +128,7 @@ public:
|
||||||
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
|
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
|
||||||
inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
|
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_totalBindingsCount = 0; // Number of bindings used in this type
|
||||||
int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
|
int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
|
||||||
|
@ -143,10 +145,9 @@ public:
|
||||||
|
|
||||||
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
|
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
|
||||||
|
|
||||||
CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const;
|
QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
|
||||||
|
|
||||||
CompositeMetaTypeIds typeIds;
|
QQmlType qmlType;
|
||||||
bool isRegistered = false;
|
|
||||||
|
|
||||||
QHash<QString, InlineComponentData> inlineComponentData;
|
QHash<QString, InlineComponentData> inlineComponentData;
|
||||||
|
|
||||||
|
|
|
@ -163,13 +163,13 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
|
||||||
if (!qmltype.isComposite()) {
|
if (!qmltype.isComposite()) {
|
||||||
if (!qmltype.isInlineComponentType())
|
if (!qmltype.isInlineComponentType())
|
||||||
return QMetaType();
|
return QMetaType();
|
||||||
const CompositeMetaTypeIds typeIds = unit->typeIdsForComponent(qmltype.elementName());
|
const QQmlType qmlType = unit->qmlTypeForComponent(qmltype.elementName());
|
||||||
return param.isList() ? typeIds.listId : typeIds.id;
|
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CompositeMetaTypeIds typeIds = enginePrivate->typeLoader.getType(
|
const QQmlType qmlType = enginePrivate->typeLoader.getType(
|
||||||
qmltype.sourceUrl())->compilationUnit()->typeIds;
|
qmltype.sourceUrl())->compilationUnit()->qmlType;
|
||||||
return param.isList() ? typeIds.listId : typeIds.id;
|
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (quint16 i = 0; i < nFormals; ++i)
|
for (quint16 i = 0; i < nFormals; ++i)
|
||||||
|
|
|
@ -1824,7 +1824,7 @@ bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
|
||||||
QMetaType metaType = typeWrapper->type().typeId();
|
QMetaType metaType = typeWrapper->type().typeId();
|
||||||
if (!metaType.isValid()) {
|
if (!metaType.isValid()) {
|
||||||
metaType = ep->typeLoader.getType(typeWrapper->type().sourceUrl())
|
metaType = ep->typeLoader.getType(typeWrapper->type().sourceUrl())
|
||||||
->compilationUnit()->typeIds.id;
|
->compilationUnit()->qmlType.typeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
*static_cast<const QMetaObject **>(target)
|
*static_cast<const QMetaObject **>(target)
|
||||||
|
|
|
@ -582,38 +582,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
|
||||||
bool ret = uri == typeStr;
|
bool ret = uri == typeStr;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
Q_ASSERT(!type_return->isValid());
|
Q_ASSERT(!type_return->isValid());
|
||||||
auto createICType = [&]() {
|
*type_return = QQmlMetaType::inlineComponentTypeForUrl(QUrl(url));
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
|
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
|
||||||
if (it != end) {
|
if (it != end) {
|
||||||
QString componentUrl;
|
QString componentUrl;
|
||||||
bool isCompositeSingleton = false;
|
QQmlMetaType::CompositeTypeLookupMode lookupMode = QQmlMetaType::NonSingleton;
|
||||||
QQmlDirComponents::ConstIterator candidate = end;
|
QQmlDirComponents::ConstIterator candidate = end;
|
||||||
for ( ; it != end && it.key() == typeStr; ++it) {
|
for ( ; it != end && it.key() == typeStr; ++it) {
|
||||||
const QQmlDirParser::Component &c = *it;
|
const QQmlDirParser::Component &c = *it;
|
||||||
|
@ -658,7 +634,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
|
||||||
|
|
||||||
// This is our best candidate so far
|
// This is our best candidate so far
|
||||||
candidate = it;
|
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 (candidate != end) {
|
||||||
if (!base) // ensure we have a componentUrl
|
if (!base) // ensure we have a componentUrl
|
||||||
componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
|
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);
|
nullptr, candidate->version);
|
||||||
if (version_return)
|
if (version_return)
|
||||||
*version_return = candidate->version;
|
*version_return = candidate->version;
|
||||||
|
@ -715,7 +691,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
|
||||||
*typeRecursionDetected = recursion;
|
*typeRecursionDetected = recursion;
|
||||||
if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
|
if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
|
||||||
QQmlType returnType = QQmlMetaType::typeForUrl(
|
QQmlType returnType = QQmlMetaType::typeForUrl(
|
||||||
qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
|
qmlUrl, type, registrationType == QQmlType::CompositeSingletonType
|
||||||
|
? QQmlMetaType::Singleton
|
||||||
|
: QQmlMetaType::NonSingleton,
|
||||||
|
errors);
|
||||||
if (type_return)
|
if (type_return)
|
||||||
*type_return = returnType;
|
*type_return = returnType;
|
||||||
return returnType.isValid();
|
return returnType.isValid();
|
||||||
|
@ -747,7 +726,7 @@ bool QQmlImports::resolveType(
|
||||||
*type_return = QQmlMetaType::typeForUrl(
|
*type_return = QQmlMetaType::typeForUrl(
|
||||||
resolveLocalUrl(nameSpace->imports.at(0)->url,
|
resolveLocalUrl(nameSpace->imports.at(0)->url,
|
||||||
unqualifiedtype.toString() + QLatin1String(".qml")),
|
unqualifiedtype.toString() + QLatin1String(".qml")),
|
||||||
type, false, errors);
|
type, QQmlMetaType::NonSingleton, errors);
|
||||||
return type_return->isValid();
|
return type_return->isValid();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -766,22 +745,8 @@ bool QQmlImports::resolveType(
|
||||||
} else {
|
} else {
|
||||||
if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
|
if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
|
||||||
// either simple type + inline component
|
// either simple type + inline component
|
||||||
const QString icName = splitName.at(1).toString();
|
*type_return = QQmlMetaType::inlineComponentTypeForUrl(
|
||||||
const QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName);
|
type_return->sourceUrl(), splitName.at(1).toString());
|
||||||
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());
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// or a failure
|
// or a failure
|
||||||
|
@ -802,21 +767,8 @@ bool QQmlImports::resolveType(
|
||||||
error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
|
error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
|
||||||
} else {
|
} else {
|
||||||
if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
|
if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
|
||||||
auto const icName = splitName.at(2).toString();
|
*type_return = QQmlMetaType::inlineComponentTypeForUrl(
|
||||||
QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName);
|
type_return->sourceUrl(), splitName.at(2).toString());
|
||||||
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;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
|
error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
|
||||||
|
@ -1530,13 +1482,12 @@ QTypeRevision QQmlImports::updateQmldirContent(
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\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->url = importUrl.toString();
|
||||||
importInstance->uri = name;
|
importInstance->uri = name;
|
||||||
importInstance->isInlineComponent = true;
|
importInstance->isInlineComponent = true;
|
||||||
importInstance->version = QTypeRevision::zero();
|
importInstance->version = QTypeRevision::zero();
|
||||||
importInstance->containingType = containingType;
|
|
||||||
m_unqualifiedset.imports.push_back(importInstance);
|
m_unqualifiedset.imports.push_back(importInstance);
|
||||||
m_unqualifiedset.setNeedsSorting(true);
|
m_unqualifiedset.setNeedsSorting(true);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -56,7 +56,6 @@ struct QQmlImportInstance
|
||||||
|
|
||||||
QString uri; // e.g. QtQuick
|
QString uri; // e.g. QtQuick
|
||||||
QString url; // the base path of the import
|
QString url; // the base path of the import
|
||||||
QQmlType containingType; // points to the containing type for inline components
|
|
||||||
QTypeRevision version; // the version imported
|
QTypeRevision version; // the version imported
|
||||||
|
|
||||||
bool isLibrary; // true means that this is not a file import
|
bool isLibrary; // true means that this is not a file import
|
||||||
|
@ -158,8 +157,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addInlineComponentImport(
|
bool addInlineComponentImport(
|
||||||
QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl,
|
QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
|
||||||
QQmlType containingType);
|
|
||||||
|
|
||||||
QTypeRevision addFileImport(
|
QTypeRevision addFileImport(
|
||||||
QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
|
QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
|
|
||||||
#include "qqmlmetatype_p.h"
|
#include "qqmlmetatype_p.h"
|
||||||
|
|
||||||
|
#include <private/qqmlextensionplugin_p.h>
|
||||||
#include <private/qqmlmetatypedata_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/qqmltype_p_p.h>
|
||||||
#include <private/qqmltypeloader_p.h>
|
#include <private/qqmltypeloader_p.h>
|
||||||
#include <private/qqmlextensionplugin_p.h>
|
#include <private/qqmltypemodule_p.h>
|
||||||
#include <private/qqmlvaluetype_p.h>
|
#include <private/qqmlvaluetype_p.h>
|
||||||
#include <private/qv4executablecompilationunit_p.h>
|
#include <private/qv4executablecompilationunit_p.h>
|
||||||
|
|
||||||
|
@ -20,32 +21,6 @@ Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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
|
struct LockedData : private QQmlMetaTypeData
|
||||||
{
|
{
|
||||||
friend class QQmlMetaTypeDataPtr;
|
friend class QQmlMetaTypeDataPtr;
|
||||||
|
@ -178,6 +153,22 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
|
||||||
return d;
|
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,
|
static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
|
||||||
const QQmlPrivate::RegisterCompositeType &type)
|
const QQmlPrivate::RegisterCompositeType &type)
|
||||||
{
|
{
|
||||||
|
@ -186,7 +177,10 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
|
||||||
d->setName(QString::fromUtf8(type.uri), elementName);
|
d->setName(QString::fromUtf8(type.uri), elementName);
|
||||||
d->version = type.version;
|
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;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,9 +193,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
|
||||||
|
|
||||||
d->version = type.version;
|
d->version = type.version;
|
||||||
|
|
||||||
|
const QUrl normalized = QQmlTypeLoader::normalize(type.url);
|
||||||
d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
|
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);
|
d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
|
||||||
|
addQQmlMetaTypeInterfaces(
|
||||||
|
d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized));
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +316,10 @@ void QQmlMetaType::clearTypeRegistrations()
|
||||||
data->undeletableTypes.clear();
|
data->undeletableTypes.clear();
|
||||||
data->propertyCaches.clear();
|
data->propertyCaches.clear();
|
||||||
data->inlineComponentTypes.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)
|
void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
|
||||||
|
@ -564,26 +565,164 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
|
||||||
return QQmlType(priv);
|
return QQmlType(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
|
class QQmlMetaTypeRegistrationFailureRecorder
|
||||||
{
|
{
|
||||||
QByteArray ptr = className + '*';
|
Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
|
||||||
QByteArray lst = "QQmlListProperty<" + className + '>';
|
public:
|
||||||
|
QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
|
||||||
|
: data(data)
|
||||||
|
{
|
||||||
|
data->setTypeRegistrationFailures(failures);
|
||||||
|
}
|
||||||
|
|
||||||
QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
|
~QQmlMetaTypeRegistrationFailureRecorder()
|
||||||
QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
|
{
|
||||||
|
data->setTypeRegistrationFailures(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
|
QQmlMetaTypeData *data = nullptr;
|
||||||
ptr_type.id();
|
};
|
||||||
lst_type.id();
|
|
||||||
|
|
||||||
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);
|
const QUrl normalized = QQmlTypeLoader::normalize(url);
|
||||||
QMetaType listMetaType(typeIds.listId);
|
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.
|
// This may be called from delayed dtors on shutdown when the data is already gone.
|
||||||
QQmlMetaTypeDataPtr data;
|
QQmlMetaTypeDataPtr data;
|
||||||
if (data.isValid()) {
|
if (data.isValid()) {
|
||||||
|
@ -591,6 +730,10 @@ void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &t
|
||||||
delete vt;
|
delete vt;
|
||||||
if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
|
if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
|
||||||
delete vt;
|
delete vt;
|
||||||
|
|
||||||
|
auto it = data->compositeTypes.constFind(metaType.iface());
|
||||||
|
if (it != data->compositeTypes.constEnd())
|
||||||
|
data->compositeTypes.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaType::unregisterMetaType(metaType);
|
QMetaType::unregisterMetaType(metaType);
|
||||||
|
@ -764,25 +907,6 @@ static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const Q
|
||||||
return false;
|
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(
|
QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
|
||||||
QObject *instance, const QString &basePath, const QString &uri,
|
QObject *instance, const QString &basePath, const QString &uri,
|
||||||
const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
|
const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
|
||||||
|
@ -883,7 +1007,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
|
||||||
*/
|
*/
|
||||||
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
|
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
|
||||||
const QHashedStringRef &qualifiedType,
|
const QHashedStringRef &qualifiedType,
|
||||||
bool isCompositeSingleton, QList<QQmlError> *errors,
|
CompositeTypeLookupMode mode, QList<QQmlError> *errors,
|
||||||
QTypeRevision version)
|
QTypeRevision version)
|
||||||
{
|
{
|
||||||
// ### unfortunate (costly) conversion
|
// ### unfortunate (costly) conversion
|
||||||
|
@ -901,64 +1025,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int dot = qualifiedType.indexOf(QLatin1Char('.'));
|
const QQmlType type = createTypeForUrl(
|
||||||
const QString typeName = dot < 0
|
data, url, qualifiedType, mode, errors, version);
|
||||||
? qualifiedType.toString()
|
data->urlToType.insert(url, type.priv());
|
||||||
: QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
|
return type;
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
|
QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
|
||||||
|
@ -1285,36 +1355,17 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
|
||||||
return QQmlType();
|
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;
|
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)
|
return doRegisterInlineComponentType(data, url);
|
||||||
priv->release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a QQmlPropertyCache for \a obj if one is available.
|
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();
|
for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end();
|
||||||
it != end; ++it) {
|
it != end; ++it) {
|
||||||
if (it.key().containingType != d)
|
if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QQmlTypePrivate *icPriv = it->priv();
|
const QQmlTypePrivate *icPriv = it->priv();
|
||||||
|
@ -1831,30 +1882,66 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMet
|
||||||
return data->findPropertyCacheInCompositeTypes(t);
|
return data->findPropertyCacheInCompositeTypes(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
|
void QQmlMetaType::registerInternalCompositeType(
|
||||||
|
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
|
||||||
{
|
{
|
||||||
compilationUnit->isRegistered = true;
|
|
||||||
|
|
||||||
QQmlMetaTypeDataPtr data;
|
QQmlMetaTypeDataPtr data;
|
||||||
|
|
||||||
// The QQmlCompiledData is not referenced here, but it is removed from this
|
auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
|
||||||
// hash in the QQmlCompiledData destructor
|
Q_ASSERT(iface);
|
||||||
data->compositeTypes.insert(compilationUnit->typeIds.id.iface(), compilationUnit);
|
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)
|
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;
|
QQmlMetaTypeDataPtr data;
|
||||||
data->compositeTypes.remove(compilationUnit->typeIds.id.iface());
|
|
||||||
for (auto&& icDatum: compilationUnit->inlineComponentData)
|
auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
|
||||||
data->compositeTypes.remove(icDatum.typeIds.id.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;
|
const QQmlMetaTypeDataPtr data;
|
||||||
return data->compositeTypes.value(type.iface());
|
return data->compositeTypes.value(type.iface());
|
||||||
|
|
|
@ -30,74 +30,55 @@ class QQmlValueType;
|
||||||
|
|
||||||
namespace QV4 { class ExecutableCompilationUnit; }
|
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
|
class Q_QML_PRIVATE_EXPORT QQmlMetaType
|
||||||
{
|
{
|
||||||
friend struct CompositeMetaTypeIds;
|
|
||||||
friend class QQmlDesignerMetaObject;
|
friend class QQmlDesignerMetaObject;
|
||||||
|
|
||||||
static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className);
|
|
||||||
static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class RegistrationResult {
|
enum class RegistrationResult {
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Failure,
|
||||||
NoRegistrationFunction
|
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 registerType(const QQmlPrivate::RegisterType &type);
|
||||||
static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
|
static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
|
||||||
static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
|
static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
|
||||||
|
@ -106,9 +87,15 @@ public:
|
||||||
static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath,
|
static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath,
|
||||||
const QString &uri, const QString &typeNamespace,
|
const QString &uri, const QString &typeNamespace,
|
||||||
QTypeRevision version, QList<QQmlError> *errors);
|
QTypeRevision version, QList<QQmlError> *errors);
|
||||||
|
|
||||||
static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
|
static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
|
||||||
bool isCompositeSingleton, QList<QQmlError> *errors,
|
CompositeTypeLookupMode mode, QList<QQmlError> *errors,
|
||||||
QTypeRevision version = QTypeRevision());
|
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);
|
static void unregisterType(int type);
|
||||||
|
|
||||||
|
@ -143,8 +130,6 @@ public:
|
||||||
static QQmlType qmlListType(QMetaType metaType);
|
static QQmlType qmlListType(QMetaType metaType);
|
||||||
|
|
||||||
static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false);
|
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(
|
static QQmlPropertyCache::ConstPtr propertyCache(
|
||||||
QObject *object, QTypeRevision version = QTypeRevision());
|
QObject *object, QTypeRevision version = QTypeRevision());
|
||||||
|
@ -219,8 +204,9 @@ public:
|
||||||
static void removeFromInlineComponents(
|
static void removeFromInlineComponents(
|
||||||
InlineComponentContainer &container, const QQmlTypePrivate *reference)
|
InlineComponentContainer &container, const QQmlTypePrivate *reference)
|
||||||
{
|
{
|
||||||
|
const QUrl referenceUrl = QQmlType(reference).sourceUrl();
|
||||||
for (auto it = container.begin(), end = container.end(); it != end;) {
|
for (auto it = container.begin(), end = container.end(); it != end;) {
|
||||||
if (it.key().containingType == reference)
|
if (equalBaseUrls(it.key(), referenceUrl))
|
||||||
it = container.erase(it);
|
it = container.erase(it);
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
|
@ -281,9 +267,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
|
static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
|
||||||
static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
|
static void registerInternalCompositeType(
|
||||||
static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
|
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
|
||||||
static QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(QMetaType type);
|
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);
|
Q_DECLARE_TYPEINFO(QQmlMetaType, Q_RELOCATABLE_TYPE);
|
||||||
|
|
|
@ -15,8 +15,12 @@ QQmlMetaTypeData::QQmlMetaTypeData()
|
||||||
|
|
||||||
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();
|
propertyCaches.clear();
|
||||||
// Do this before the attached properties disappear.
|
// Do this before the attached properties disappear.
|
||||||
|
@ -237,13 +241,11 @@ QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
|
||||||
}
|
}
|
||||||
|
|
||||||
static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
|
static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
|
||||||
QMetaType t,
|
QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
|
||||||
const QHash<const QtPrivate::QMetaTypeInterface *,
|
if (t != (*iter)->qmlType.typeId()) {
|
||||||
QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
|
|
||||||
if (t != (*iter)->typeIds.id) {
|
|
||||||
// this is an inline component, and what we have in the iterator is currently the parent compilation unit
|
// this is an inline component, and what we have in the iterator is currently the parent compilation unit
|
||||||
for (auto &&icDatum: (*iter)->inlineComponentData)
|
for (auto &&icDatum: (*iter)->inlineComponentData)
|
||||||
if (icDatum.typeIds.id == t)
|
if (icDatum.qmlType.typeId() == t)
|
||||||
return (*iter)->propertyCaches.at(icDatum.objectIndex);
|
return (*iter)->propertyCaches.at(icDatum.objectIndex);
|
||||||
}
|
}
|
||||||
return (*iter)->rootPropertyCache();
|
return (*iter)->rootPropertyCache();
|
||||||
|
|
|
@ -25,23 +25,6 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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;
|
class QQmlTypePrivate;
|
||||||
struct QQmlMetaTypeData
|
struct QQmlMetaTypeData
|
||||||
{
|
{
|
||||||
|
@ -56,7 +39,7 @@ struct QQmlMetaTypeData
|
||||||
using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>;
|
using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>;
|
||||||
Names nameToType;
|
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 urlToType;
|
||||||
Files urlToNonFileImportType; // For non-file imported composite and composite
|
Files urlToNonFileImportType; // For non-file imported composite and composite
|
||||||
// singleton types. This way we can locate any
|
// singleton types. This way we can locate any
|
||||||
|
@ -66,8 +49,11 @@ struct QQmlMetaTypeData
|
||||||
MetaObjects metaObjectToType;
|
MetaObjects metaObjectToType;
|
||||||
QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches;
|
QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches;
|
||||||
QHash<int, QQmlValueType *> metaTypeToValueType;
|
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 {
|
struct VersionedUri {
|
||||||
VersionedUri() = default;
|
VersionedUri() = default;
|
||||||
|
|
|
@ -66,29 +66,55 @@ QMetaType QQmlPropertyCacheCreatorBase::listTypeForPropertyType(QV4::CompiledDat
|
||||||
return QMetaType {};
|
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();
|
const QString path = url.path();
|
||||||
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
|
|
||||||
// Not a reusable type if we don't have an absolute Url
|
// Not a reusable type if we don't have an absolute Url
|
||||||
|
const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
|
||||||
if (lastSlash <= -1)
|
if (lastSlash <= -1)
|
||||||
return QByteArray();
|
return failHandler();
|
||||||
|
|
||||||
// ### this might not be correct for .ui.qml files
|
// ### 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.
|
// Not a reusable type if it doesn't start with a upper case letter.
|
||||||
if (nameBase.isEmpty() || !nameBase.at(0).isUpper())
|
return (!baseName.isEmpty() && baseName.at(0).isUpper())
|
||||||
return QByteArray();
|
? baseNameHandler(baseName)
|
||||||
return nameBase.toUtf8() + "_QMLTYPE_" +
|
: failHandler();
|
||||||
QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(const QUrl &baseUrl, int icId)
|
bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url)
|
||||||
{
|
{
|
||||||
QByteArray baseName = createClassNameTypeByUrl(baseUrl);
|
return processUrlForClassName(url, [](QStringView) {
|
||||||
if (baseName.isEmpty())
|
return true;
|
||||||
baseName = QByteArray("ANON_QML_IC_") + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
|
}, []() {
|
||||||
baseName += "_" + QByteArray::number(icId);
|
return false;
|
||||||
return baseName;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(
|
||||||
|
|
|
@ -69,9 +69,10 @@ public:
|
||||||
static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type);
|
static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type);
|
||||||
static QMetaType listTypeForPropertyType(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 createClassNameTypeByUrl(const QUrl &url);
|
||||||
|
|
||||||
static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId);
|
static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name);
|
||||||
|
|
||||||
struct IncrementalResult {
|
struct IncrementalResult {
|
||||||
// valid if and only if an error occurred
|
// valid if and only if an error occurred
|
||||||
|
@ -157,7 +158,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
|
||||||
, typeClassName(typeClassName)
|
, typeClassName(typeClassName)
|
||||||
, currentRoot(-1)
|
, currentRoot(-1)
|
||||||
{
|
{
|
||||||
propertyCaches->resize(objectContainer->objectCount());
|
propertyCaches->resetAndResize(objectContainer->objectCount());
|
||||||
|
|
||||||
using namespace icutils;
|
using namespace icutils;
|
||||||
|
|
||||||
|
@ -626,35 +627,29 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
|
||||||
// inline components are not necessarily valid yet
|
// inline components are not necessarily valid yet
|
||||||
Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
|
Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
|
||||||
if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
|
if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
|
||||||
CompositeMetaTypeIds typeIds;
|
QQmlType compositeType;
|
||||||
if (qmltype.isInlineComponentType()) {
|
if (qmltype.isInlineComponentType()) {
|
||||||
const QString icName = qmltype.elementName();
|
const QString icName = qmltype.elementName();
|
||||||
auto containingType = qmltype.containingType();
|
compositeType = QQmlMetaType::inlineComponentTypeForUrl(
|
||||||
if (containingType.isValid()) {
|
qmltype.sourceUrl(), icName);
|
||||||
const QQmlType icType
|
if (!compositeType.isValid()) // type has not been registered yet, we must be in containing type
|
||||||
= QQmlMetaType::inlineComponentType(containingType, icName);
|
compositeType = objectContainer->qmlTypeForComponent(icName);
|
||||||
typeIds = {icType.typeId(), icType.qListTypeId()};
|
Q_ASSERT(compositeType.isValid());
|
||||||
} 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());
|
|
||||||
} else if (selfReference) {
|
} else if (selfReference) {
|
||||||
typeIds = objectContainer->typeIdsForComponent();
|
compositeType = objectContainer->qmlTypeForComponent();
|
||||||
} else {
|
} else {
|
||||||
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
|
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
|
||||||
Q_ASSERT(tdata);
|
Q_ASSERT(tdata);
|
||||||
Q_ASSERT(tdata->isComplete());
|
Q_ASSERT(tdata->isComplete());
|
||||||
|
|
||||||
auto compilationUnit = tdata->compilationUnit();
|
auto compilationUnit = tdata->compilationUnit();
|
||||||
typeIds = compilationUnit->typeIdsForComponent();
|
compositeType = compilationUnit->qmlTypeForComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->isList()) {
|
if (p->isList()) {
|
||||||
propertyType = typeIds.listId;
|
propertyType = compositeType.qListTypeId();
|
||||||
} else {
|
} else {
|
||||||
propertyType = typeIds.id;
|
propertyType = compositeType.typeId();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p->isList())
|
if (p->isList())
|
||||||
|
@ -714,16 +709,16 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
|
||||||
if (!qmltype.isComposite()) {
|
if (!qmltype.isComposite()) {
|
||||||
const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
|
const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
|
||||||
if (!typeId.isValid() && qmltype.isInlineComponentType()) {
|
if (!typeId.isValid() && qmltype.isInlineComponentType()) {
|
||||||
const auto typeIds = objectContainer->typeIdsForComponent(qmltype.elementName());
|
const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
|
||||||
return param.isList() ? typeIds.listId : typeIds.id;
|
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
|
||||||
} else {
|
} else {
|
||||||
return typeId;
|
return typeId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selfReference) {
|
if (selfReference) {
|
||||||
const auto typeIds = objectContainer->typeIdsForComponent();
|
const QQmlType qmlType = objectContainer->qmlTypeForComponent();
|
||||||
return param.isList() ? typeIds.listId : typeIds.id;
|
return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
|
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
|
||||||
|
@ -732,7 +727,9 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
|
||||||
|
|
||||||
auto compilationUnit = tdata->compilationUnit();
|
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>
|
template <typename ObjectContainer>
|
||||||
|
@ -825,11 +822,11 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
|
||||||
if (referencedType.isValid()) {
|
if (referencedType.isValid()) {
|
||||||
*type = referencedType.typeId();
|
*type = referencedType.typeId();
|
||||||
if (!type->isValid() && referencedType.isInlineComponentType()) {
|
if (!type->isValid() && referencedType.isInlineComponentType()) {
|
||||||
*type = objectContainer->typeIdsForComponent(referencedType.elementName()).id;
|
*type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
|
||||||
Q_ASSERT(type->isValid());
|
Q_ASSERT(type->isValid());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*type = typeRef->compilationUnit()->typeIds.id;
|
*type = typeRef->compilationUnit()->qmlType.typeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
*version = typeRef->version();
|
*version = typeRef->version();
|
||||||
|
|
|
@ -643,7 +643,7 @@ bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr
|
||||||
// only occurs after the whole file has been validated
|
// only occurs after the whole file has been validated
|
||||||
// Therefore we need to check the ICs here
|
// Therefore we need to check the ICs here
|
||||||
for (const auto& icDatum : compilationUnit->inlineComponentData) {
|
for (const auto& icDatum : compilationUnit->inlineComponentData) {
|
||||||
if (icDatum.typeIds.id == to) {
|
if (icDatum.qmlType.typeId() == to) {
|
||||||
toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
|
toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -753,7 +753,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *p
|
||||||
// only occurs after the whole file has been validated
|
// only occurs after the whole file has been validated
|
||||||
// Therefore we need to check the ICs here
|
// Therefore we need to check the ICs here
|
||||||
for (const auto& icDatum: compilationUnit->inlineComponentData) {
|
for (const auto& icDatum: compilationUnit->inlineComponentData) {
|
||||||
if (icDatum.typeIds.id == property->propType()) {
|
if (icDatum.qmlType.typeId() == property->propType()) {
|
||||||
propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
|
propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,12 @@ QQmlTypePrivate::~QQmlTypePrivate()
|
||||||
qDeleteAll(scopedEnums);
|
qDeleteAll(scopedEnums);
|
||||||
for (const auto &metaObject : metaObjects)
|
for (const auto &metaObject : metaObjects)
|
||||||
free(metaObject.metaObject);
|
free(metaObject.metaObject);
|
||||||
|
|
||||||
|
if (const auto &iface = typeId.iface()) {
|
||||||
|
if (iface->metaObjectFn == &dynamicQmlMetaObject)
|
||||||
|
QQmlMetaType::unregisterInternalCompositeType(typeId, listId);
|
||||||
|
}
|
||||||
|
|
||||||
switch (regType) {
|
switch (regType) {
|
||||||
case QQmlType::CppType:
|
case QQmlType::CppType:
|
||||||
delete extraData.cd->customParser;
|
delete extraData.cd->customParser;
|
||||||
|
@ -404,12 +410,6 @@ void QQmlTypePrivate::insertEnumsFromPropertyCache(
|
||||||
insertEnums(cppMetaObject);
|
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)
|
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
|
||||||
{
|
{
|
||||||
module = uri;
|
module = uri;
|
||||||
|
@ -928,14 +928,6 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
|
||||||
return -1;
|
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
|
void QQmlType::createProxy(QObject *instance) const
|
||||||
{
|
{
|
||||||
if (!d->metaObjects.isEmpty())
|
if (!d->metaObjects.isEmpty())
|
||||||
|
|
|
@ -39,7 +39,6 @@ class QQmlPropertyCache;
|
||||||
namespace QV4 {
|
namespace QV4 {
|
||||||
struct String;
|
struct String;
|
||||||
}
|
}
|
||||||
struct CompositeMetaTypeIds;
|
|
||||||
|
|
||||||
class Q_QML_PRIVATE_EXPORT QQmlType
|
class Q_QML_PRIVATE_EXPORT QQmlType
|
||||||
{
|
{
|
||||||
|
@ -159,8 +158,6 @@ public:
|
||||||
AnyRegistrationType = 255
|
AnyRegistrationType = 255
|
||||||
};
|
};
|
||||||
|
|
||||||
QQmlType containingType() const;
|
|
||||||
|
|
||||||
void createProxy(QObject *instance) const;
|
void createProxy(QObject *instance) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -36,7 +36,6 @@ public:
|
||||||
void initEnums(QQmlEnginePrivate *engine) const;
|
void initEnums(QQmlEnginePrivate *engine) const;
|
||||||
void insertEnums(const QMetaObject *metaObject) const;
|
void insertEnums(const QMetaObject *metaObject) const;
|
||||||
void insertEnumsFromPropertyCache(const QQmlPropertyCache::ConstPtr &cache) const;
|
void insertEnumsFromPropertyCache(const QQmlPropertyCache::ConstPtr &cache) const;
|
||||||
void setContainingType(QQmlType *containingType);
|
|
||||||
|
|
||||||
QUrl sourceUrl() const
|
QUrl sourceUrl() const
|
||||||
{
|
{
|
||||||
|
@ -111,11 +110,6 @@ public:
|
||||||
struct QQmlInlineTypeData
|
struct QQmlInlineTypeData
|
||||||
{
|
{
|
||||||
QUrl url;
|
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;
|
using QQmlSequenceTypeData = QMetaSequence;
|
||||||
|
|
|
@ -259,9 +259,9 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
|
||||||
document->imports.append(import);
|
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)
|
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
|
||||||
|
|
|
@ -108,7 +108,7 @@ public:
|
||||||
return resolvedTypes->value(id);
|
return resolvedTypes->value(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const;
|
QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QQmlError> errors;
|
QList<QQmlError> errors;
|
||||||
|
|
|
@ -74,11 +74,11 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
|
||||||
Q_ASSERT(!m_callbacks.contains(callback));
|
Q_ASSERT(!m_callbacks.contains(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeMetaTypeIds QQmlTypeData::typeIds(const QString &inlineComponentName) const
|
QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
|
||||||
{
|
{
|
||||||
if (inlineComponentName.isEmpty())
|
if (inlineComponentName.isEmpty())
|
||||||
return m_typeIds;
|
return m_qmlType;
|
||||||
return m_inlineComponentData[inlineComponentName].typeIds;
|
return m_inlineComponentData[inlineComponentName].qmlType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QQmlTypeData::tryLoadFromDiskCache()
|
bool QQmlTypeData::tryLoadFromDiskCache()
|
||||||
|
@ -168,7 +168,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
|
||||||
auto importUrl = finalUrl();
|
auto importUrl = finalUrl();
|
||||||
importUrl.setFragment(nameString);
|
importUrl.setFragment(nameString);
|
||||||
auto import = new QQmlImportInstance();
|
auto import = new QQmlImportInstance();
|
||||||
m_importCache->addInlineComponentImport(import, nameString, importUrl, QQmlType());
|
m_importCache->addInlineComponentImport(import, nameString, importUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -289,13 +289,18 @@ namespace {
|
||||||
template<typename ObjectContainer>
|
template<typename ObjectContainer>
|
||||||
void setupICs(
|
void setupICs(
|
||||||
const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
|
const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
|
||||||
const QUrl &finalUrl) {
|
const QUrl &baseUrl, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
|
||||||
Q_ASSERT(icData->empty());
|
Q_ASSERT(icData->empty());
|
||||||
for (int i = 0; i != container->objectCount(); ++i) {
|
for (int i = 0; i != container->objectCount(); ++i) {
|
||||||
auto root = container->objectAt(i);
|
auto root = container->objectAt(i);
|
||||||
for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
|
for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
|
||||||
const QByteArray &className = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(finalUrl, it->objectIndex);
|
// We cannot re-use a previously finalized inline component type here. We need our own.
|
||||||
InlineComponentData icDatum(CompositeMetaTypeIds::fromCompositeName(className), int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
|
// 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);
|
icData->insert(container->stringAt(it->nameIndex), icDatum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,15 +375,11 @@ void QQmlTypeData::done()
|
||||||
++it) {
|
++it) {
|
||||||
const TypeReference &type = *it;
|
const TypeReference &type = *it;
|
||||||
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
|
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 (type.type.isInlineComponentType()) {
|
||||||
if (!ic.typeId().isValid()) {
|
const QUrl url = type.type.sourceUrl();
|
||||||
|
if (!QQmlMetaType::equalBaseUrls(url, finalUrl())
|
||||||
|
&& !QQmlMetaType::obtainExecutableCompilationUnit(type.type.typeId())) {
|
||||||
const QString &typeName = stringAt(it.key());
|
const QString &typeName = stringAt(it.key());
|
||||||
int lastDot = typeName.lastIndexOf(u'.');
|
int lastDot = typeName.lastIndexOf(u'.');
|
||||||
createError(
|
createError(
|
||||||
|
@ -407,16 +408,22 @@ void QQmlTypeData::done()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
|
if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
|
||||||
if (!m_typeClassName.isEmpty())
|
const bool isSingleton = m_document
|
||||||
m_typeIds = CompositeMetaTypeIds::fromCompositeName(m_typeClassName);
|
? m_document.data()->isSingleton()
|
||||||
|
: (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
|
||||||
if (m_document) {
|
m_qmlType = QQmlMetaType::findCompositeType(
|
||||||
setupICs(m_document, &m_inlineComponentData, finalUrl());
|
finalUrl(), m_compiledData, isSingleton
|
||||||
} else {
|
? QQmlMetaType::Singleton
|
||||||
setupICs(m_compiledData, &m_inlineComponentData, finalUrl());
|
: 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;
|
QV4::ResolvedTypeReferenceMap resolvedTypeCache;
|
||||||
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
|
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
|
// Collect imported scripts
|
||||||
m_compiledData->dependentScripts.reserve(m_scripts.size());
|
m_compiledData->dependentScripts.reserve(m_scripts.size());
|
||||||
|
@ -706,18 +685,13 @@ void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
|
||||||
|
|
||||||
void QQmlTypeData::continueLoadFromIR()
|
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 const& object: m_document->objects) {
|
||||||
for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
|
for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
|
||||||
QString const nameString = m_document->stringAt(it->nameIndex);
|
QString const nameString = m_document->stringAt(it->nameIndex);
|
||||||
auto importUrl = finalUrl();
|
auto importUrl = finalUrl();
|
||||||
importUrl.setFragment(nameString);
|
importUrl.setFragment(nameString);
|
||||||
auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
|
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());
|
addDependency(ref.typeData.data());
|
||||||
}
|
}
|
||||||
if (ref.type.isInlineComponentType()) {
|
if (ref.type.isInlineComponentType()) {
|
||||||
auto containingType = ref.type.containingType();
|
QUrl containingTypeUrl = ref.type.sourceUrl();
|
||||||
if (containingType.isValid()) {
|
containingTypeUrl.setFragment(QString());
|
||||||
auto const url = containingType.sourceUrl();
|
if (!containingTypeUrl.isEmpty()) {
|
||||||
if (url.isValid()) {
|
auto typeData = typeLoader()->getType(containingTypeUrl);
|
||||||
auto typeData = typeLoader()->getType(url);
|
if (typeData.data() != this) {
|
||||||
ref.typeData = typeData;
|
ref.typeData = typeData;
|
||||||
addDependency(typeData.data());
|
addDependency(typeData.data());
|
||||||
}
|
}
|
||||||
|
@ -972,11 +946,7 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
|
||||||
ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
|
ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
|
||||||
if (resolvedType->type.isInlineComponentType()) {
|
if (resolvedType->type.isInlineComponentType()) {
|
||||||
// Inline component which is part of an already resolved type
|
// Inline component which is part of an already resolved type
|
||||||
QString icName;
|
QString icName = qmlType.elementName();
|
||||||
if (qmlType.containingType().isValid())
|
|
||||||
icName = qmlType.elementName();
|
|
||||||
else
|
|
||||||
icName = resolvedType->type.elementName();
|
|
||||||
Q_ASSERT(!icName.isEmpty());
|
Q_ASSERT(!icName.isEmpty());
|
||||||
|
|
||||||
const auto compilationUnit = resolvedType->typeData->compilationUnit();
|
const auto compilationUnit = resolvedType->typeData->compilationUnit();
|
||||||
|
@ -986,14 +956,17 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
|
||||||
Q_ASSERT(ref->type().isInlineComponentType());
|
Q_ASSERT(ref->type().isInlineComponentType());
|
||||||
}
|
}
|
||||||
} else if (resolvedType->type.isInlineComponentType()) {
|
} else if (resolvedType->type.isInlineComponentType()) {
|
||||||
// Inline component, defined in the file we are currently compiling
|
|
||||||
ref->setType(qmlType);
|
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
|
// this is required for inline components in singletons
|
||||||
const QMetaType type
|
const QMetaType type = qmlType.typeId();
|
||||||
= QQmlMetaType::inlineComponentType(qmlType, qmlType.elementName()).typeId();
|
if (auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type)) {
|
||||||
auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type);
|
|
||||||
if (exUnit) {
|
|
||||||
ref->setCompilationUnit(exUnit);
|
ref->setCompilationUnit(exUnit);
|
||||||
ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type));
|
ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type));
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
void registerCallback(TypeDataCallback *);
|
void registerCallback(TypeDataCallback *);
|
||||||
void unregisterCallback(TypeDataCallback *);
|
void unregisterCallback(TypeDataCallback *);
|
||||||
|
|
||||||
CompositeMetaTypeIds typeIds(const QString &inlineComponentName = QString()) const;
|
QQmlType qmlType(const QString &inlineComponentName = QString()) const;
|
||||||
QByteArray typeClassName() const { return m_typeClassName; }
|
QByteArray typeClassName() const { return m_typeClassName; }
|
||||||
SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
|
SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
|
||||||
|
|
||||||
|
@ -120,8 +120,8 @@ private:
|
||||||
QMap<int, TypeReference> m_resolvedTypes;
|
QMap<int, TypeReference> m_resolvedTypes;
|
||||||
bool m_typesResolved:1;
|
bool m_typesResolved:1;
|
||||||
|
|
||||||
// Used for self-referencing types, otherwise -1.
|
// Used for self-referencing types, otherwise invalid.
|
||||||
CompositeMetaTypeIds m_typeIds;
|
QQmlType m_qmlType;
|
||||||
QByteArray m_typeClassName; // used for meta-object later
|
QByteArray m_typeClassName; // used for meta-object later
|
||||||
|
|
||||||
using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>;
|
using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>;
|
||||||
|
|
|
@ -1338,15 +1338,29 @@ void QQmlTypeLoader::trimCache()
|
||||||
// typeData->m_compiledData may be set early on in the proccess of loading a file, so
|
// 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
|
// it's important to check the general loading status of the typeData before making any
|
||||||
// other decisions.
|
// other decisions.
|
||||||
if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete())
|
if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
|
||||||
&& (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) {
|
++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
|
// There are no live objects of this type
|
||||||
iter.value()->release();
|
iter.value()->release();
|
||||||
iter = m_typeCache.erase(iter);
|
iter = m_typeCache.erase(iter);
|
||||||
deletedOneType = true;
|
deletedOneType = true;
|
||||||
} else {
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deletedOneType)
|
if (!deletedOneType)
|
||||||
|
|
|
@ -379,11 +379,13 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper,
|
||||||
QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
|
QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
|
||||||
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
|
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
|
||||||
if (ExecutableCompilationUnit *cu = td->compilationUnit())
|
if (ExecutableCompilationUnit *cu = td->compilationUnit())
|
||||||
myQmlType = QQmlMetaType::metaObjectForType(cu->typeIds.id);
|
myQmlType = QQmlMetaType::metaObjectForType(cu->qmlType.typeId());
|
||||||
else
|
else
|
||||||
return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
|
return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
|
||||||
} else {
|
} else {
|
||||||
myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
|
myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
|
||||||
|
if (myQmlType.isNull())
|
||||||
|
return Encode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMetaObject *theirType = wrapperObject->metaObject();
|
const QMetaObject *theirType = wrapperObject->metaObject();
|
||||||
|
|
|
@ -2029,6 +2029,10 @@ void tst_QmlCppCodegen::invisibleListElementType()
|
||||||
|
|
||||||
void tst_QmlCppCodegen::invisibleSingleton()
|
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;
|
QQmlEngine engine;
|
||||||
const QUrl copy(u"qrc:/qt/qml/TestTypes/hidden/Main.qml"_s);
|
const QUrl copy(u"qrc:/qt/qml/TestTypes/hidden/Main.qml"_s);
|
||||||
QQmlComponent c(&engine, copy);
|
QQmlComponent c(&engine, copy);
|
||||||
|
|
|
@ -5762,7 +5762,7 @@ void tst_qqmllanguage::selfReference()
|
||||||
|
|
||||||
const QMetaObject *metaObject = o->metaObject();
|
const QMetaObject *metaObject = o->metaObject();
|
||||||
QMetaProperty selfProperty = metaObject->property(metaObject->indexOfProperty("self"));
|
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();
|
QByteArray typeName = selfProperty.typeName();
|
||||||
QVERIFY(typeName.endsWith('*'));
|
QVERIFY(typeName.endsWith('*'));
|
||||||
|
@ -5771,7 +5771,7 @@ void tst_qqmllanguage::selfReference()
|
||||||
|
|
||||||
QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()"));
|
QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()"));
|
||||||
QVERIFY(selfFunction.isValid());
|
QVERIFY(selfFunction.isValid());
|
||||||
QCOMPARE(selfFunction.returnType(), compilationUnit->typeIds.id.id());
|
QCOMPARE(selfFunction.returnType(), compilationUnit->qmlType.typeId().id());
|
||||||
|
|
||||||
QMetaMethod selfSignal;
|
QMetaMethod selfSignal;
|
||||||
|
|
||||||
|
@ -5785,7 +5785,7 @@ void tst_qqmllanguage::selfReference()
|
||||||
|
|
||||||
QVERIFY(selfSignal.isValid());
|
QVERIFY(selfSignal.isValid());
|
||||||
QCOMPARE(selfSignal.parameterCount(), 1);
|
QCOMPARE(selfSignal.parameterCount(), 1);
|
||||||
QCOMPARE(selfSignal.parameterType(0), compilationUnit->typeIds.id.id());
|
QCOMPARE(selfSignal.parameterType(0), compilationUnit->qmlType.typeId().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_qqmllanguage::selfReferencingSingleton()
|
void tst_qqmllanguage::selfReferencingSingleton()
|
||||||
|
@ -6772,11 +6772,17 @@ void tst_qqmllanguage::bareInlineComponent()
|
||||||
QVERIFY(type.module().isEmpty());
|
QVERIFY(type.module().isEmpty());
|
||||||
tab1Found = true;
|
tab1Found = true;
|
||||||
|
|
||||||
const QQmlType leftTab = QQmlMetaType::inlineComponentType(type, "LeftTab");
|
const QQmlType leftTab = QQmlMetaType::inlineComponentTypeForUrl(
|
||||||
QCOMPARE(leftTab.containingType(), type);
|
type.sourceUrl(), "LeftTab");
|
||||||
|
QUrl leftUrl = leftTab.sourceUrl();
|
||||||
|
leftUrl.setFragment(QString());
|
||||||
|
QCOMPARE(leftUrl, type.sourceUrl());
|
||||||
|
|
||||||
const QQmlType rightTab = QQmlMetaType::inlineComponentType(type, "RightTab");
|
const QQmlType rightTab = QQmlMetaType::inlineComponentTypeForUrl(
|
||||||
QCOMPARE(rightTab.containingType(), type);
|
type.sourceUrl(), "RightTab");
|
||||||
|
QUrl rightUrl = rightTab.sourceUrl();
|
||||||
|
rightUrl.setFragment(QString());
|
||||||
|
QCOMPARE(rightUrl, type.sourceUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QVERIFY(tab1Found);
|
QVERIFY(tab1Found);
|
||||||
|
|
Loading…
Reference in New Issue