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)) {
327 if (qmlElementName == S_ANONYMOUS)
330 if (qmlElementName == S_AUTO) {
331 qmlElementName = classDef.className().toString();
334 if (!qmlElementName.isEmpty()
335 && qmlElementName.front().isLower()
336 && !classDef.enums().empty()) {
337 warning(classDef.inputFile()).nospace()
338 <<
"QML type '" << qmlElementName
339 <<
"' starts with a lowercase letter and exports enums, "
340 "which are not accessible from QML or JavaScript.";
343 qmlElementInfos[qmlElementName].append({
344 classDef.inputFile(),
354 const QList<QAnyStringView> namespaces
355 = MetaTypesJsonProcessor::namespaces(classDef);
357 const FoundType target = QmlTypesClassDescription::findType(
358 m_types, m_foreignTypes, targetName, namespaces);
362 if (!target.native.isEmpty())
363 targetName = target.native.qualifiedClassName().toString();
365 if (targetIsNamespace) {
369 QString targetTypeName = targetName;
371 if (!target.javaScript.isEmpty() && target.native.isEmpty())
372 warning(target.javaScript) <<
"JavaScript type cannot be used as namespace";
374 if (target.native.kind() == MetaType::Kind::Object)
375 targetTypeName +=
" *"_L1;
380 if (className == targetName || target.native.kind() == MetaType::Kind::Namespace) {
382 {
383 Q_CONSTINIT static auto metaType = QQmlPrivate::metaTypeForNamespace(
384 [](const QtPrivate::QMetaTypeInterface *) {return &%1::staticMetaObject;},
385 "%2");
386 QMetaType(&metaType).id();
387 })"_s.arg(targetName,targetTypeName);
389 Q_ASSERT(!targetTypeName.isEmpty());
390 output << u"\n QMetaType::fromType<%1>().id();"_s.arg(targetTypeName);
393 auto metaObjectPointer = [](QAnyStringView name) -> QString {
395 const QLatin1StringView staticMetaObject =
"::staticMetaObject"_L1;
396 result.reserve(1 + name.length() + staticMetaObject.length());
397 result.append(
'&'_L1);
398 name.visit([&](
auto view) { result.append(view); });
399 result.append(staticMetaObject);
403 if (!qmlElementNames.isEmpty()) {
405 qmlRegisterNamespaceAndRevisions(%1, "%2", %3, nullptr, %4, %5);)"_s
406 .arg(metaObjectPointer(targetName), m_module)
408 .arg(metaObjectPointer(className),
409 extendedName.isEmpty() ? QStringLiteral(
"nullptr")
410 : metaObjectPointer(extendedName));
413 if (!qmlElementNames.isEmpty()) {
414 auto checkRevisions = [&](
const auto &array, QLatin1StringView type) {
415 for (
auto it = array.begin(); it != array.end(); ++it) {
416 if (!it->revision.isValid())
419 QTypeRevision revision = it->revision;
420 if (m_moduleVersion < revision) {
422 << className <<
"is trying to register" << type
424 <<
"with future version" << revision
425 <<
"when module version is only" << m_moduleVersion;
430 const Method::Container methods = classDef.methods();
431 const Property::Container properties = classDef.properties();
433 if (m_moduleVersion.isValid()) {
434 checkRevisions(properties, S_PROPERTY);
435 checkRevisions(methods, S_METHOD);
439 qmlRegisterTypesAndRevisions<%1>("%2", %3);)"_s.arg(className,m_module).arg(majorVersion);
442 if (classDef.kind() == MetaType::Kind::Gadget)
443 output << u"\n QMetaType::fromType<%1 *>().id();"_s.arg(className);
445 const BaseType::Container superClasses = classDef.superClasses();
447 for (
const BaseType &object : superClasses) {
448 if (object.access != Access::Public)
451 QAnyStringView superClassName = object.name;
453 QList<QAnyStringView> classesToCheck;
455 auto checkForRevisions = [&](QAnyStringView typeName) ->
void {
456 auto typeAsMap = findType(typeName);
458 if (typeAsMap.isEmpty()) {
459 typeAsMap = findTypeForeign(typeName);
460 if (typeAsMap.isEmpty())
463 if (!fillTypesRegisteredAnonymously(
464 typeAsMap.properties(), typeName)) {
465 if (!fillTypesRegisteredAnonymously(
466 typeAsMap.sigs(), typeName)) {
467 fillTypesRegisteredAnonymously(
468 typeAsMap.methods(), typeName);
473 for (
const BaseType &object : typeAsMap.superClasses()) {
474 if (object.access == Access::Public)
475 classesToCheck << object.name;
479 checkForRevisions(superClassName);
481 while (!classesToCheck.isEmpty())
482 checkForRevisions(classesToCheck.takeFirst());
485 Q_ASSERT(!className.isEmpty());
488 Q_ASSERT(className == targetName);
491 QMetaType::fromType<%1%2>().id();)"_s.arg(
492 className, classDef.kind() == MetaType::Kind::Object ? u" *" : u"");
496 const auto enums = target.native.enums();
497 for (
const auto &enumerator : enums) {
499 qmlRegisterEnum<%1::%2>("%1::%2");)"_s.arg(
500 targetName, enumerator.name.toString());
501 if (!enumerator.alias.isEmpty()) {
503 qmlRegisterEnum<%1::%2>("%1::%2");)"_s.arg(
504 targetName, enumerator.alias.toString());
509 for (
const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
512 if (exportsForSameQmlName.size() < 2)
516 std::sort(exportsForSameQmlName.begin(), exportsForSameQmlName.end());
517 auto conflictingExportStartIt = exportsForSameQmlName.cbegin();