182 output << uR"(/****************************************************************************
183** Generated QML type registration code
184**
185** WARNING! All changes made in this file will be lost!
186*****************************************************************************/
187
188)"_s;
190 output << u"#include <QtQml/qqml.h>\n"_s;
191 output << u"#include <QtQml/qqmlmoduleregistration.h>\n"_s;
193 for (
const QString &include : m_includes) {
194 output << u"\n#if __has_include(<%1>)"_s.arg(include);
195 output << u"\n# include <%1>"_s.arg(include);
196 output << u"\n#endif"_s;
202 QString moduleAsSymbol = m_module;
203 static const QRegularExpression nonAlnumRegexp(QLatin1String(
"[^A-Za-z0-9]"));
204 moduleAsSymbol.replace(nonAlnumRegexp, QStringLiteral(
"_"));
206 QString underscoredModuleAsSymbol = m_module;
207 underscoredModuleAsSymbol.replace(QLatin1Char(
'.'), QLatin1Char(
'_'));
209 if (underscoredModuleAsSymbol != moduleAsSymbol
210 || underscoredModuleAsSymbol.isEmpty()
211 || underscoredModuleAsSymbol.front().isDigit()) {
212 warning(outFileName) << m_module <<
"is an invalid QML module URI. You cannot import this.";
215 const QString functionName = QStringLiteral(
"qml_register_types_") + moduleAsSymbol;
217#if !defined(QT_STATIC)
218#define Q_QMLTYPE_EXPORT Q_DECL_EXPORT
219#else
220#define Q_QMLTYPE_EXPORT
221#endif
222)"_s;
224 if (!m_targetNamespace.isEmpty())
225 output << u"namespace "_s << m_targetNamespace << u" {\n"_s;
227 output << u"Q_QMLTYPE_EXPORT void "_s << functionName << u"()\n{"_s;
228 const quint8 majorVersion = m_moduleVersion.majorVersion();
229 const quint8 minorVersion = m_moduleVersion.minorVersion();
231 for (
const auto &version : m_pastMajorVersions) {
233 qmlRegisterModule("%1", %2, 0);
234 qmlRegisterModule("%1", %2, 254);)"_s.arg(m_module)
238 if (minorVersion != 0) {
240 qmlRegisterModule("%1", %2, 0);)"_s.arg(m_module)
245 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED)"_s;
247 QList<QAnyStringView> typesRegisteredAnonymously;
249 const auto fillTypesRegisteredAnonymously = [&](
const auto &members, QAnyStringView typeName) {
250 bool foundRevisionEntry =
false;
251 for (
const auto &entry : members) {
252 if (entry.revision.isValid()) {
253 foundRevisionEntry =
true;
258 if (!foundRevisionEntry)
261 if (typesRegisteredAnonymously.contains(typeName))
264 typesRegisteredAnonymously.append(typeName);
266 if (m_followForeignVersioning) {
268 qmlRegisterAnonymousTypesAndRevisions<%1>("%2", %3);)"_s.arg(typeName.toString(),m_module)
273 for (
const auto &version
274 : m_pastMajorVersions +
decltype(m_pastMajorVersions){ majorVersion }) {
276 qmlRegisterAnonymousType<%1, 254>("%2", %3);)"_s.arg(typeName.toString(),m_module)
284 QHash<QString, QList<ExclusiveVersionRange>> qmlElementInfos;
286 for (
const MetaType &classDef : std::as_const(m_types)) {
289 if (classDef.inputFile().isEmpty())
292 QString className = classDef.qualifiedClassName().toString();
293 QString targetName = className;
297 bool targetIsNamespace = classDef.kind() == MetaType::Kind::Namespace;
299 QAnyStringView extendedName;
300 QList<QString> qmlElementNames;
301 QTypeRevision addedIn;
302 QTypeRevision removedIn;
304 for (
const ClassInfo &v : classDef.classInfos()) {
305 const QAnyStringView name = v.name;
306 if (name == S_ELEMENT) {
307 qmlElementNames.append(v.value.toString());
308 }
else if (name == S_FOREIGN) {
309 targetName = v.value.toString();
310 }
else if (name == S_FOREIGN_IS_NAMESPACE) {
311 targetIsNamespace = targetIsNamespace || (v.value == S_TRUE);
312 }
else if (name == S_EXTENDED) {
313 extendedName = v.value;
314 }
else if (name == S_ADDED_IN_VERSION) {
315 int version = toInt(v.value);
316 addedIn = QTypeRevision::fromEncodedVersion(version);
317 addedIn = handleInMinorVersion(addedIn, majorVersion);
318 }
else if (name == S_REMOVED_IN_VERSION) {
319 int version = toInt(v.value);
320 removedIn = QTypeRevision::fromEncodedVersion(version);
321 removedIn = handleInMinorVersion(removedIn, majorVersion);
325 for (QString qmlElementName : std::as_const(qmlElementNames)) {
326 if (qmlElementName == S_ANONYMOUS)
328 if (qmlElementName == S_AUTO)
329 qmlElementName = className;
330 qmlElementInfos[qmlElementName].append({
331 classDef.inputFile(),
341 const QList<QAnyStringView> namespaces
342 = MetaTypesJsonProcessor::namespaces(classDef);
344 const FoundType target = QmlTypesClassDescription::findType(
345 m_types, m_foreignTypes, targetName, namespaces);
349 if (!target.native.isEmpty())
350 targetName = target.native.qualifiedClassName().toString();
352 if (targetIsNamespace) {
356 QString targetTypeName = targetName;
358 if (!target.javaScript.isEmpty() && target.native.isEmpty())
359 warning(target.javaScript) <<
"JavaScript type cannot be used as namespace";
361 if (target.native.kind() == MetaType::Kind::Object)
362 targetTypeName +=
" *"_L1;
367 if (className == targetName || target.native.kind() == MetaType::Kind::Namespace) {
369 {
370 Q_CONSTINIT static auto metaType = QQmlPrivate::metaTypeForNamespace(
371 [](const QtPrivate::QMetaTypeInterface *) {return &%1::staticMetaObject;},
372 "%2");
373 QMetaType(&metaType).id();
374 })"_s.arg(targetName,targetTypeName);
376 Q_ASSERT(!targetTypeName.isEmpty());
377 output << u"\n QMetaType::fromType<%1>().id();"_s.arg(targetTypeName);
380 auto metaObjectPointer = [](QAnyStringView name) -> QString {
382 const QLatin1StringView staticMetaObject =
"::staticMetaObject"_L1;
383 result.reserve(1 + name.length() + staticMetaObject.length());
384 result.append(
'&'_L1);
385 name.visit([&](
auto view) { result.append(view); });
386 result.append(staticMetaObject);
390 if (!qmlElementNames.isEmpty()) {
392 qmlRegisterNamespaceAndRevisions(%1, "%2", %3, nullptr, %4, %5);)"_s
393 .arg(metaObjectPointer(targetName), m_module)
395 .arg(metaObjectPointer(className),
396 extendedName.isEmpty() ? QStringLiteral(
"nullptr")
397 : metaObjectPointer(extendedName));
400 if (!qmlElementNames.isEmpty()) {
401 auto checkRevisions = [&](
const auto &array, QLatin1StringView type) {
402 for (
auto it = array.begin(); it != array.end(); ++it) {
403 if (!it->revision.isValid())
406 QTypeRevision revision = it->revision;
407 if (m_moduleVersion < revision) {
409 << className <<
"is trying to register" << type
411 <<
"with future version" << revision
412 <<
"when module version is only" << m_moduleVersion;
417 const Method::Container methods = classDef.methods();
418 const Property::Container properties = classDef.properties();
420 if (m_moduleVersion.isValid()) {
421 checkRevisions(properties, S_PROPERTY);
422 checkRevisions(methods, S_METHOD);
426 qmlRegisterTypesAndRevisions<%1>("%2", %3);)"_s.arg(className,m_module).arg(majorVersion);
428 const BaseType::Container superClasses = classDef.superClasses();
430 for (
const BaseType &object : classDef.superClasses()) {
431 if (object.access != Access::Public)
434 QAnyStringView superClassName = object.name;
436 QList<QAnyStringView> classesToCheck;
438 auto checkForRevisions = [&](QAnyStringView typeName) ->
void {
439 auto typeAsMap = findType(typeName);
441 if (typeAsMap.isEmpty()) {
442 typeAsMap = findTypeForeign(typeName);
443 if (typeAsMap.isEmpty())
446 if (!fillTypesRegisteredAnonymously(
447 typeAsMap.properties(), typeName)) {
448 if (!fillTypesRegisteredAnonymously(
449 typeAsMap.sigs(), typeName)) {
450 fillTypesRegisteredAnonymously(
451 typeAsMap.methods(), typeName);
456 for (
const BaseType &object : typeAsMap.superClasses()) {
457 if (object.access == Access::Public)
458 classesToCheck << object.name;
462 checkForRevisions(superClassName);
464 while (!classesToCheck.isEmpty())
465 checkForRevisions(classesToCheck.takeFirst());
468 Q_ASSERT(!className.isEmpty());
471 Q_ASSERT(className == targetName);
474 QMetaType::fromType<%1%2>().id();)"_s.arg(
475 className, classDef.kind() == MetaType::Kind::Object ? u" *" : u"");
479 const auto enums = target.native.enums();
480 for (
const auto &enumerator : enums) {
482 qmlRegisterEnum<%1::%2>("%1::%2");)"_s.arg(
483 targetName, enumerator.name.toString());
484 if (!enumerator.alias.isEmpty()) {
486 qmlRegisterEnum<%1::%2>("%1::%2");)"_s.arg(
487 targetName, enumerator.alias.toString());
492 for (
const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
495 if (exportsForSameQmlName.size() < 2)
499 std::sort(exportsForSameQmlName.begin(), exportsForSameQmlName.end());
500 auto conflictingExportStartIt = exportsForSameQmlName.cbegin();