aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-04-11 10:03:38 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-04-25 18:55:23 +0200
commit2bc9c4760898737bcd95a7c679ebee9620d04c45 (patch)
tree36124ecd366f68615905d2b97808a88fb91b2938 /src
parente5d0441409491d84d8153c8650408ee1098e32ad (diff)
qmltyperegistrar: Check properties, methods, enums for missing types
If you have a property of an unknown type, that will create problems later on. The same holds for method arguments, return types and underlying types of enums. qmltyperegistrar now warns about those. When scanning the types, we consider a type potentially primitive if it is not the root type, but one of: a, a self-extending value type b, a type with a JavaScript extension c, a sequence type If those types are found to be "missing" later, we ignore them. All other missing types trigger warnings now. Since we use types from QPA headers in a few places, we now need to recognize QPA headers when looking for private Qt includes. Task-number: QTBUG-101143 Change-Id: Ic4350e8ed46212c0f4af6f10e86323514f710e1e Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor.cpp288
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor_p.h21
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription.cpp73
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription_p.h10
-rw-r--r--src/qmltyperegistrar/qqmltypescreator.cpp73
5 files changed, 297 insertions, 168 deletions
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
index 45e1d9cdfe..4f8342ecc8 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
@@ -146,14 +146,15 @@ static void sortStringList(QList<String> *list)
void MetaTypesJsonProcessor::postProcessTypes()
{
sortTypes(m_types);
- sortStringList(&m_includes);
}
void MetaTypesJsonProcessor::postProcessForeignTypes()
{
sortTypes(m_foreignTypes);
+ sortStringList(&m_primitiveTypes);
addRelatedTypes();
sortStringList(&m_referencedTypes);
+ sortStringList(&m_includes);
}
QString MetaTypesJsonProcessor::extractRegisteredTypes() const
@@ -219,30 +220,59 @@ QString MetaTypesJsonProcessor::extractRegisteredTypes() const
return registrationHelper;
}
-MetaTypesJsonProcessor::RegistrationMode MetaTypesJsonProcessor::qmlTypeRegistrationMode(
- const MetaType &classDef)
+MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
+ const MetaType &classDef, PopulateMode populateMode)
{
- for (const ClassInfo &entry : classDef.classInfos()) {
- const QAnyStringView name = entry.name;
- if (name == S_ELEMENT) {
+ // If this type is a self-extending value type or a sequence type or has a JavaScript extension
+ // and is not the root object, then it's foreign type has no entry of its own.
+ // In that case we need to generate a "primitive" entry.
+
+ QAnyStringView foreign;
+ RegistrationMode mode = NoRegistration;
+ bool isSelfExtendingValueType = false;
+ bool hasJavaScriptExtension = false;
+ bool isRootObject = false;
+ bool isSequence = false;
+
+ for (const ClassInfo &classInfo : classDef.classInfos()) {
+ if (classInfo.name == S_FOREIGN)
+ foreign = classInfo.value;
+ else if (classInfo.name == S_EXTENSION_IS_JAVA_SCRIPT)
+ hasJavaScriptExtension = (classInfo.value == S_TRUE);
+ else if (classInfo.name == S_EXTENDED && classDef.kind() == MetaType::Kind::Gadget)
+ isSelfExtendingValueType = classInfo.value == classDef.className();
+ else if (classInfo.name == S_ROOT)
+ isRootObject = (classInfo.value == S_TRUE);
+ else if (classInfo.name == S_SEQUENCE)
+ isSequence = true;
+ else if (populateMode == PopulateMode::Yes && classInfo.name == S_ELEMENT) {
switch (classDef.kind()) {
case MetaType::Kind::Object:
- return ObjectRegistration;
+ mode = ObjectRegistration;
+ break;
case MetaType::Kind::Gadget:
- return GadgetRegistration;
+ mode = GadgetRegistration;
+ break;
case MetaType::Kind::Namespace:
- return NamespaceRegistration;
+ mode = NamespaceRegistration;
+ break;
default:
warning(classDef)
- << "Not registering a classInfo which is neither an object,"
- << "nor a gadget, nor a namespace:"
- << name.toString();
+ << "Not registering a classInfo which is neither an object,"
+ << "nor a gadget, nor a namespace:"
+ << classInfo.name.toString();
break;
}
- break;
}
}
- return NoRegistration;
+
+ return PreProcessResult {
+ (!isRootObject && (isSequence || isSelfExtendingValueType || hasJavaScriptExtension))
+ ? foreign
+ : QAnyStringView(),
+ mode
+ };
+
}
// TODO: Remove this when QAnyStringView gets a proper qHash()
@@ -351,6 +381,11 @@ void MetaTypesJsonProcessor::addRelatedTypes()
qualifiedClassNameLessThan);
m_types.insert(insert, type);
+ // Also add its include. We don't want to rely on transitive inclues.
+ const QString inputFile = type.inputFile();
+ if (!inputFile.isEmpty())
+ m_includes.append(inputFile);
+
// Remove from the foreign types to avoid the ODR warning.
const auto remove = std::equal_range(
m_foreignTypes.constBegin(), m_foreignTypes.constEnd(), type,
@@ -363,7 +398,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
}
};
- const auto addInterfaceOrSelfExtension
+ const auto addInterface
= [&](QAnyStringView typeName, const QList<QAnyStringView> &namespaces) {
if (const FoundType other = QmlTypesClassDescription::findType(
m_types, m_foreignTypes, typeName, namespaces)) {
@@ -382,7 +417,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
};
const auto addType = [&](const MetaType &context, QAnyStringView typeName,
- const QList<QAnyStringView> &namespaces) {
+ const QList<QAnyStringView> &namespaces, QAnyStringView relation) {
if (const FoundType other = QmlTypesClassDescription::findType(
m_types, m_foreignTypes, typeName, namespaces)) {
addReference(other.native, &processedRelatedNativeNames, other.nativeOrigin);
@@ -399,7 +434,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
const QAnyStringView enumName = typeName.mid(index + separator.length());
for (const Enum &enumerator : other.native.enums()) {
- if (enumerator.name != enumName)
+ if (enumerator.name != enumName && enumerator.alias != enumName)
continue;
addReference(other.native, &processedRelatedNativeNames, other.nativeOrigin);
@@ -411,20 +446,40 @@ void MetaTypesJsonProcessor::addRelatedTypes()
}
}
+ // If it's an enum of the context type itself, we don't have to do anything.
+ for (const Enum &enumerator : context.enums()) {
+ if (enumerator.name == typeName || enumerator.alias == typeName)
+ return true;
+ }
+
// If we've detected this type as unresolved foreign and it actually belongs to this module,
// we'll get to it again when we process it as foreign type. In that case we'll look at the
// special cases for sequences and extensions.
- if (!unresolvedForeignNames.contains(typeName))
- warning(context) << typeName << "is used but cannot be found.";
+ if (!unresolvedForeignNames.contains(typeName) && !isPrimitive(typeName))
+ warning(context) << typeName << "is used as" << relation << "type but cannot be found.";
processedRelatedNativeNames.insert(typeName);
processedRelatedJavaScriptNames.insert(typeName);
return false;
};
+ const auto doAddReferences = [&](QAnyStringView typeName,
+ const QList<QAnyStringView> &namespaces) {
+ if (const FoundType other = QmlTypesClassDescription::findType(
+ m_types, m_foreignTypes, typeName, namespaces)) {
+ addReference(
+ other.native, &processedRelatedNativeNames, other.nativeOrigin);
+ addReference(
+ other.javaScript, &processedRelatedJavaScriptNames, other.javaScriptOrigin);
+ return true;
+ }
+
+ return false;
+ };
+
const auto addSupers = [&](const MetaType &context, const QList<QAnyStringView> &namespaces) {
for (const Interface &iface : context.ifaces())
- addInterfaceOrSelfExtension(interfaceName(iface), namespaces);
+ addInterface(interfaceName(iface), namespaces);
// We don't warn about missing bases for value types. They don't have to be registered.
bool warnAboutSupers = context.kind() != MetaType::Kind::Gadget;
@@ -436,110 +491,128 @@ void MetaTypesJsonProcessor::addRelatedTypes()
continue;
QAnyStringView typeName = superObject.name;
- if (const FoundType other = QmlTypesClassDescription::findType(
- m_types, m_foreignTypes, typeName, namespaces)) {
- addReference(
- other.native, &processedRelatedNativeNames, other.nativeOrigin);
- addReference(
- other.javaScript, &processedRelatedJavaScriptNames, other.javaScriptOrigin);
+ if (doAddReferences(typeName, namespaces))
warnAboutSupers = false;
- } else {
+ else
missingSupers.append(typeName);
- }
}
for (QAnyStringView typeName : std::as_const(missingSupers)) {
// If we've found one valid base type, don't complain about the others.
- if (warnAboutSupers && !unresolvedForeignNames.contains(typeName))
- warning(context) << typeName << "is used but cannot be found.";
+ if (warnAboutSupers
+ && !unresolvedForeignNames.contains(typeName)
+ && !isPrimitive(typeName)) {
+ warning(context) << typeName << "is used as base type but cannot be found.";
+ }
processedRelatedNativeNames.insert(typeName);
processedRelatedJavaScriptNames.insert(typeName);
}
};
+ const auto addProperties = [&](const MetaType &context,
+ const QList<QAnyStringView> &namespaces) {
+ for (const Property &property : context.properties()) {
+ ResolvedTypeAlias resolved(property.type);
+ if (!resolved.type.isEmpty())
+ addType(context, resolved.type, namespaces, "property");
+ }
+ };
+
+ const auto addMethods = [&](const MetaType &context,
+ const QList<QAnyStringView> &namespaces) {
+ for (const Method::Container &methods
+ : {context.methods(), context.constructors(), context.sigs() }) {
+ for (const Method &methodObject : methods) {
+ for (const Argument &argument : std::as_const(methodObject.arguments)) {
+ ResolvedTypeAlias resolved(argument.type);
+ if (!resolved.type.isEmpty())
+ addType(context, resolved.type, namespaces, "argument");
+ }
+
+ ResolvedTypeAlias resolved(methodObject.returnType);
+ if (!resolved.type.isEmpty())
+ addType(context, resolved.type, namespaces, "return");
+ }
+ }
+ };
+
+ const auto addEnums = [&](const MetaType &context,
+ const QList<QAnyStringView> &namespaces) {
+ for (const Enum &enumerator : context.enums()) {
+ ResolvedTypeAlias resolved(enumerator.type);
+ if (!resolved.type.isEmpty())
+ addType(context, resolved.type, namespaces, "enum");
+ }
+ };
+
+ const auto addRelation = [&](const MetaType &classDef, const ClassInfo &obj,
+ const QList<QAnyStringView> &namespaces) {
+ const QAnyStringView objNameValue = obj.name;
+ if (objNameValue == S_ATTACHED) {
+ addType(classDef, obj.value, namespaces, "attached");
+ return true;
+ } else if (objNameValue == S_SEQUENCE) {
+ ResolvedTypeAlias value(obj.value);
+ addType(classDef, value.type, namespaces, "sequence value");
+ return true;
+ } else if (objNameValue == S_EXTENDED) {
+ const QAnyStringView value = obj.value;
+ addType(classDef, value, namespaces, "extension");
+ return true;
+ }
+ return false;
+ };
+
// Then recursively iterate the super types and attached types, marking the
// ones we are interested in as related.
while (!typeQueue.isEmpty()) {
QAnyStringView unresolvedForeign;
- // We don't need to resolve the foreign part of sequence registrations.
- bool isSequence = false;
- // We don't need to resolve the foreign part of self-extending value types.
- bool isSelfExtendingValueType = false;
- // We don't want to deal with builtins that have JavaScript extensions. Consider them found.
- bool hasJavaScriptExtension = false;
-
const MetaType classDef = typeQueue.dequeue();
const QList<QAnyStringView> namespaces = MetaTypesJsonProcessor::namespaces(classDef);
for (const ClassInfo &obj : classDef.classInfos()) {
- const QAnyStringView objNameValue = obj.name;
- if (objNameValue == S_ATTACHED) {
- addType(classDef, obj.value, namespaces);
- } else if (objNameValue == S_SEQUENCE) {
- isSequence = true;
- QAnyStringView value = obj.value;
-
- if (!value.isEmpty() && value.back() == '*'_L1) {
- // Pointers as sequence values include the '*'
- QAnyStringView chopped = value.chopped(1);
- while (!chopped.isEmpty() && chopped.back() == ' '_L1)
- chopped = chopped.chopped(1);
- addType(classDef, chopped, namespaces);
- } else {
- addType(classDef, value, namespaces);
- }
- } else if (objNameValue == S_EXTENDED) {
- const QAnyStringView value = obj.value;
- if (value == classDef.qualifiedClassName()
- && classDef.kind() == MetaType::Kind::Gadget) {
- isSelfExtendingValueType = true;
- addInterfaceOrSelfExtension(value, namespaces);
- } else {
- addType(classDef, value, namespaces);
- }
- } else if (objNameValue == S_EXTENSION_IS_JAVA_SCRIPT) {
- hasJavaScriptExtension = true;
- } else if (objNameValue == S_FOREIGN) {
- const QAnyStringView foreignClassName = obj.value;
-
- // A type declared as QML_FOREIGN will usually be a foreign type, but it can
- // actually be an additional registration of a local type, too.
- const FoundType found = QmlTypesClassDescription::findType(
- m_foreignTypes, {}, foreignClassName, namespaces);
- if (!found) {
- if (!QmlTypesClassDescription::findType(
- m_types, {}, foreignClassName, namespaces)) {
- unresolvedForeign = foreignClassName;
- }
- } else {
- const MetaType other = found.select(classDef, "Foreign");
- const QList<QAnyStringView> otherNamespaces
- = MetaTypesJsonProcessor::namespaces(other);
- addSupers(other, otherNamespaces);
-
- for (const ClassInfo &obj : other.classInfos()) {
- const QAnyStringView objNameValue = obj.name;
- if (objNameValue == S_ATTACHED || objNameValue == S_SEQUENCE
- || objNameValue == S_EXTENDED) {
- addType(classDef, obj.value, otherNamespaces);
- break;
- }
- // No, you cannot chain S_FOREIGN declarations. Sorry.
- }
+ if (addRelation(classDef, obj, namespaces))
+ continue;
+ if (obj.name != S_FOREIGN)
+ continue;
+
+ const QAnyStringView foreignClassName = obj.value;
+
+ // A type declared as QML_FOREIGN will usually be a foreign type, but it can
+ // actually be an additional registration of a local type, too.
+ if (const FoundType found = QmlTypesClassDescription::findType(
+ m_foreignTypes, {}, foreignClassName, namespaces)) {
+ const MetaType other = found.select(classDef, "Foreign");
+ const QList<QAnyStringView> otherNamespaces
+ = MetaTypesJsonProcessor::namespaces(other);
+ addSupers(other, otherNamespaces);
+ addProperties(other, otherNamespaces);
+ addMethods(other, otherNamespaces);
+ addEnums(other, otherNamespaces);
+
+ for (const ClassInfo &obj : other.classInfos()) {
+ if (addRelation(classDef, obj, otherNamespaces))
+ break;
+ // No, you cannot chain S_FOREIGN declarations. Sorry.
}
+ } else if (!QmlTypesClassDescription::findType(
+ m_types, {}, foreignClassName, namespaces)) {
+ unresolvedForeign = foreignClassName;
}
}
- if (!isSequence && !isSelfExtendingValueType && !hasJavaScriptExtension
- && !unresolvedForeign.isEmpty()) {
+ if (!unresolvedForeign.isEmpty() && !isPrimitive(unresolvedForeign)) {
warning(classDef)
<< unresolvedForeign
<< "is declared as foreign type, but cannot be found.";
}
addSupers(classDef, namespaces);
+ addProperties(classDef, namespaces);
+ addMethods(classDef, namespaces);
+ addEnums(classDef, namespaces);
}
}
@@ -550,9 +623,16 @@ void MetaTypesJsonProcessor::sortTypes(QVector<MetaType> &types)
QString MetaTypesJsonProcessor::resolvedInclude(QAnyStringView include)
{
- return (m_privateIncludes && endsWith(include, "_p.h"_L1))
- ? QLatin1String("private/") + include.toString()
- : include.toString();
+ if (!m_privateIncludes)
+ return include.toString();
+
+ if (endsWith(include, "_p.h"_L1))
+ return QLatin1String("private/") + include.toString();
+
+ if (startsWith(include, "qplatform"_L1) || startsWith(include, "qwindowsystem"_L1))
+ return QLatin1String("qpa/") + include.toString();
+
+ return include.toString();
}
void MetaTypesJsonProcessor::processTypes(const QCborMap &types)
@@ -562,7 +642,8 @@ void MetaTypesJsonProcessor::processTypes(const QCborMap &types)
for (const QCborValue &cls : classes) {
const MetaType classDef(cls.toMap(), include);
- switch (qmlTypeRegistrationMode(classDef)) {
+ const PreProcessResult preprocessed = preProcess(classDef, PopulateMode::Yes);
+ switch (preprocessed.mode) {
case NamespaceRegistration:
case GadgetRegistration:
case ObjectRegistration: {
@@ -585,6 +666,9 @@ void MetaTypesJsonProcessor::processTypes(const QCborMap &types)
m_foreignTypes.emplaceBack(classDef);
break;
}
+
+ if (!preprocessed.foreignPrimitive.isEmpty())
+ m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
}
}
@@ -592,8 +676,14 @@ void MetaTypesJsonProcessor::processForeignTypes(const QCborMap &types)
{
const QString include = resolvedInclude(toStringView(types, S_INPUT_FILE));
const QCborArray classes = types[S_CLASSES].toArray();
- for (const QCborValue &cls : classes)
- m_foreignTypes.emplaceBack(cls.toMap(), include);
+ for (const QCborValue &cls : classes) {
+ const MetaType classDef(cls.toMap(), include);
+ PreProcessResult preprocessed = preProcess(classDef, PopulateMode::No);
+
+ m_foreignTypes.emplaceBack(classDef);
+ if (!preprocessed.foreignPrimitive.isEmpty())
+ m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
+ }
}
static QTypeRevision getRevision(const QCborMap &cbor)
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
index 8da03e82d7..8b70b56f6e 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
@@ -178,7 +178,7 @@ public:
bool isEmpty() const { return d == &s_empty; }
- QAnyStringView inputFile() const { return d->inputFile; }
+ QString inputFile() const { return d->inputFile; }
QAnyStringView className() const { return d->className; }
QAnyStringView qualifiedClassName() const { return d->qualifiedClassName; }
const BaseType::Container &superClasses() const { return d->superClasses; }
@@ -239,7 +239,18 @@ private:
NamespaceRegistration
};
- static RegistrationMode qmlTypeRegistrationMode(const MetaType &classDef);
+ struct PreProcessResult {
+ QAnyStringView foreignPrimitive;
+ RegistrationMode mode;
+ };
+
+ struct PotentialPrimitiveType {
+ QAnyStringView name;
+ QString file;
+ };
+
+ enum class PopulateMode { No, Yes };
+ static PreProcessResult preProcess(const MetaType &classDef, PopulateMode populateMode);
void addRelatedTypes();
void sortTypes(QVector<MetaType> &types);
@@ -247,8 +258,14 @@ private:
void processTypes(const QCborMap &types);
void processForeignTypes(const QCborMap &types);
+ bool isPrimitive(QAnyStringView type) const
+ {
+ return std::binary_search(m_primitiveTypes.begin(), m_primitiveTypes.end(), type);
+ }
+
QList<QString> m_includes;
QList<QAnyStringView> m_referencedTypes;
+ QList<QAnyStringView> m_primitiveTypes;
QVector<MetaType> m_types;
QVector<MetaType> m_foreignTypes;
bool m_privateIncludes = false;
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription.cpp b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
index 2f1f268dc8..79a64fb87d 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
@@ -12,6 +12,7 @@
#include <QtCore/qcbormap.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
using namespace Constants;
using namespace Constants::MetatypesDotJson;
using namespace Constants::MetatypesDotJson::Qml;
@@ -454,4 +455,76 @@ FoundType QmlTypesClassDescription::collectRelated(
return FoundType();
}
+
+ResolvedTypeAlias::ResolvedTypeAlias(QAnyStringView alias)
+ : type(alias)
+{
+ if (type.isEmpty())
+ return;
+
+ if (type == "void") {
+ type = "";
+ return;
+ }
+
+ // This is a best effort approach and will not return correct results in the
+ // presence of typedefs.
+
+ auto handleList = [&](QLatin1StringView list) {
+ if (!startsWith(type, list) || type.back() != '>'_L1)
+ return false;
+
+ const int listSize = list.size();
+ const QAnyStringView elementType = trimmed(type.mid(listSize, type.size() - listSize - 1));
+
+ // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
+ // produce double pointers. QList is only for value types. We can't handle QLists
+ // of pointers (unless specially registered, but then they're not isList).
+ if (elementType.back() == '*'_L1)
+ return false;
+
+ isList = true;
+ type = elementType;
+ return true;
+ };
+
+ if (!handleList("QQmlListProperty<"_L1) && !handleList("QList<"_L1)) {
+ if (type.back() == '*'_L1) {
+ isPointer = true;
+ type = type.chopped(1);
+ }
+ if (startsWith(type, "const "_L1)) {
+ isConstant = true;
+ type = type.sliced(strlen("const "));
+ }
+ }
+
+ if (type == "qreal") {
+#ifdef QT_COORD_TYPE_STRING
+ type = QT_COORD_TYPE_STRING;
+#else
+ type = "double";
+#endif
+ } else if (type == "int8_t") {
+ // TODO: What can we do with "char"? It's ambiguous.
+ type = "qint8";
+ } else if (type == "uchar" || type == "uint8_t") {
+ type = "quint8";
+ } else if (type == "qint16" || type == "int16_t") {
+ type = "short";
+ } else if (type == "quint16" || type == "uint16_t") {
+ type = "ushort";
+ } else if (type == "qint32" || type == "int32_t") {
+ type = "int";
+ } else if (type == "quint32" || type == "uint32_t") {
+ type = "uint";
+ } else if (type == "qint64" || type == "int64_t") {
+ type = "qlonglong";
+ } else if (type == "quint64" || type == "uint64_t") {
+ type = "qulonglong";
+ } else if (type == "QList<QObject*>") {
+ type = "QObjectList";
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription_p.h b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
index 721b7f16dd..e6e9ab36a7 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription_p.h
+++ b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
@@ -110,5 +110,15 @@ private:
void collectInterfaces(const MetaType &classDef);
};
+struct ResolvedTypeAlias
+{
+ ResolvedTypeAlias(QAnyStringView alias);
+
+ QAnyStringView type;
+ bool isList = false;
+ bool isPointer = false;
+ bool isConstant = false;
+};
+
QT_END_NAMESPACE
#endif // QMLTYPESCLASSDESCRIPTION_P_H
diff --git a/src/qmltyperegistrar/qqmltypescreator.cpp b/src/qmltyperegistrar/qqmltypescreator.cpp
index 2454f505eb..6e463882ec 100644
--- a/src/qmltyperegistrar/qqmltypescreator.cpp
+++ b/src/qmltyperegistrar/qqmltypescreator.cpp
@@ -160,77 +160,16 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
void QmlTypesCreator::writeType(QAnyStringView type)
{
- if (type.isEmpty() || type == "void")
+ ResolvedTypeAlias resolved(type);
+ if (resolved.type.isEmpty())
return;
- bool isList = false;
- bool isPointer = false;
- // This is a best effort approach (like isPointer) and will not return correct results in the
- // presence of typedefs.
- bool isConstant = false;
-
- auto handleList = [&](QLatin1StringView list) {
- if (!startsWith(type, list) || type.back() != '>'_L1)
- return false;
-
- const int listSize = list.size();
- const QAnyStringView elementType = trimmed(type.mid(listSize, type.size() - listSize - 1));
-
- // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
- // produce double pointers. QList is only for value types. We can't handle QLists
- // of pointers (unless specially registered, but then they're not isList).
- if (elementType.back() == '*'_L1)
- return false;
-
- isList = true;
- type = elementType;
- return true;
- };
-
- if (!handleList("QQmlListProperty<"_L1) && !handleList("QList<"_L1)) {
- if (type.back() == '*'_L1) {
- isPointer = true;
- type = type.chopped(1);
- }
- if (startsWith(type, "const "_L1)) {
- isConstant = true;
- type = type.sliced(strlen("const "));
- }
- }
-
- if (type == "qreal") {
-#ifdef QT_COORD_TYPE_STRING
- type = QT_COORD_TYPE_STRING;
-#else
- type = "double";
-#endif
- } else if (type == "int8_t") {
- // TODO: What can we do with "char"? It's ambiguous.
- type = "qint8";
- } else if (type == "uchar" || type == "uint8_t") {
- type = "quint8";
- } else if (type == "qint16" || type == "int16_t") {
- type = "short";
- } else if (type == "quint16" || type == "uint16_t") {
- type = "ushort";
- } else if (type == "qint32" || type == "int32_t") {
- type = "int";
- } else if (type == "quint32" || type == "uint32_t") {
- type = "uint";
- } else if (type == "qint64" || type == "int64_t") {
- type = "qlonglong";
- } else if (type == "quint64" || type == "uint64_t") {
- type = "qulonglong";
- } else if (type == "QList<QObject*>") {
- type = "QObjectList";
- }
-
- m_qml.writeStringBinding(S_TYPE, type);
- if (isList)
+ m_qml.writeStringBinding(S_TYPE, resolved.type);
+ if (resolved.isList)
m_qml.writeBooleanBinding(S_IS_LIST, true);
- if (isPointer)
+ if (resolved.isPointer)
m_qml.writeBooleanBinding(S_IS_POINTER, true);
- if (isConstant)
+ if (resolved.isConstant)
m_qml.writeBooleanBinding(S_IS_CONSTANT, true);
}