1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include <QFile> |
5 | #include <QCborArray> |
6 | #include <QCborValue> |
7 | |
8 | #include "qqmltyperegistrar_p.h" |
9 | #include "qqmltypescreator_p.h" |
10 | #include "qanystringviewutils_p.h" |
11 | #include "qqmltyperegistrarconstants_p.h" |
12 | #include "qqmltyperegistrarutils_p.h" |
13 | |
14 | #include <algorithm> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | using namespace Qt::Literals; |
18 | using namespace Constants; |
19 | using namespace Constants::MetatypesDotJson; |
20 | using namespace Constants::MetatypesDotJson::Qml; |
21 | using namespace QAnyStringViewUtils; |
22 | |
23 | struct ExclusiveVersionRange |
24 | { |
25 | QAnyStringView fileName; |
26 | QString claimerName; |
27 | QTypeRevision addedIn; |
28 | QTypeRevision removedIn; |
29 | }; |
30 | |
31 | /*! |
32 | * \brief True if x was removed before y was introduced. |
33 | * \param o |
34 | * \return |
35 | */ |
36 | bool operator<(const ExclusiveVersionRange &x, const ExclusiveVersionRange &y) |
37 | { |
38 | if (x.removedIn.isValid()) |
39 | return y.addedIn.isValid() ? x.removedIn <= y.addedIn : true; |
40 | else |
41 | return false; |
42 | } |
43 | |
44 | /*! |
45 | * \brief True when x and y share a common version. (Warning: not transitive!) |
46 | * \param o |
47 | * \return |
48 | */ |
49 | bool operator==(const ExclusiveVersionRange &x, const ExclusiveVersionRange &y) |
50 | { |
51 | return !(x < y) && !(y < x); |
52 | } |
53 | |
54 | bool QmlTypeRegistrar::argumentsFromCommandLineAndFile(QStringList &allArguments, |
55 | const QStringList &arguments) |
56 | { |
57 | allArguments.reserve(asize: arguments.size()); |
58 | for (const QString &argument : arguments) { |
59 | // "@file" doesn't start with a '-' so we can't use QCommandLineParser for it |
60 | if (argument.startsWith(c: QLatin1Char('@'))) { |
61 | QString optionsFile = argument; |
62 | optionsFile.remove(i: 0, len: 1); |
63 | if (optionsFile.isEmpty()) { |
64 | warning(fileName: optionsFile) << "The @ option requires an input file" ; |
65 | return false; |
66 | } |
67 | QFile f(optionsFile); |
68 | if (!f.open(flags: QIODevice::ReadOnly | QIODevice::Text)) { |
69 | warning(fileName: optionsFile) << "Cannot open options file specified with @" ; |
70 | return false; |
71 | } |
72 | while (!f.atEnd()) { |
73 | QString line = QString::fromLocal8Bit(ba: f.readLine().trimmed()); |
74 | if (!line.isEmpty()) |
75 | allArguments << line; |
76 | } |
77 | } else { |
78 | allArguments << argument; |
79 | } |
80 | } |
81 | return true; |
82 | } |
83 | |
84 | int QmlTypeRegistrar::( |
85 | const QString &baseName, const QString &nameSpace, const MetaTypesJsonProcessor &processor) |
86 | { |
87 | if (processor.types().isEmpty()) { |
88 | error(fileName: baseName) << "No types to register found in library" ; |
89 | return EXIT_FAILURE; |
90 | } |
91 | QFile (baseName + u".h" ); |
92 | bool ok = headerFile.open(flags: QFile::WriteOnly); |
93 | if (!ok) { |
94 | error(fileName: headerFile.fileName()) << "Cannot open header file for writing" ; |
95 | return EXIT_FAILURE; |
96 | } |
97 | |
98 | QString includeGuard = baseName; |
99 | static const QRegularExpression nonAlNum(QLatin1String("[^a-zA-Z0-9_]" )); |
100 | includeGuard.replace(re: nonAlNum, after: QLatin1String("_" )); |
101 | |
102 | auto prefix = QString::fromLatin1( |
103 | ba: "#ifndef %1_H\n" |
104 | "#define %1_H\n" |
105 | "#include <QtQml/qqml.h>\n" |
106 | "#include <QtQml/qqmlmoduleregistration.h>\n" ).arg(a: includeGuard); |
107 | auto postfix = QString::fromLatin1(ba: "\n#endif // %1_H\n" ).arg(a: includeGuard); |
108 | |
109 | const QList<QString> includes = processor.includes(); |
110 | for (const QString &include: includes) |
111 | prefix += u"\n#include <%1>"_s .arg(a: include); |
112 | if (!nameSpace.isEmpty()) { |
113 | prefix += u"\nnamespace %1 {"_s .arg(a: nameSpace); |
114 | postfix.prepend(s: u"\n} // namespace %1"_s .arg(a: nameSpace)); |
115 | } |
116 | |
117 | headerFile.write(data: (prefix + processor.extractRegisteredTypes() + postfix).toUtf8()); |
118 | |
119 | QFile sourceFile(baseName + u".cpp" ); |
120 | ok = sourceFile.open(flags: QFile::WriteOnly); |
121 | if (!ok) { |
122 | error(fileName: sourceFile.fileName()) << "Cannot open implementation file for writing" ; |
123 | return EXIT_FAILURE; |
124 | } |
125 | // the string split is necessaury because cmake's automoc scanner would otherwise pick up the include |
126 | QString code = u"#include \"%1.h\"\n#include "_s .arg(a: baseName); |
127 | code += uR"("moc_%1.cpp")"_s .arg(a: baseName); |
128 | sourceFile.write(data: code.toUtf8()); |
129 | sourceFile.write(data: "\n" ); |
130 | return EXIT_SUCCESS; |
131 | } |
132 | |
133 | MetaType QmlTypeRegistrar::findType(QAnyStringView name) const |
134 | { |
135 | for (const MetaType &type : m_types) { |
136 | if (type.qualifiedClassName() != name) |
137 | continue; |
138 | return type; |
139 | } |
140 | return MetaType(); |
141 | }; |
142 | |
143 | MetaType QmlTypeRegistrar::findTypeForeign(QAnyStringView name) const |
144 | { |
145 | for (const MetaType &type : m_foreignTypes) { |
146 | if (type.qualifiedClassName() != name) |
147 | continue; |
148 | return type; |
149 | } |
150 | return MetaType(); |
151 | }; |
152 | |
153 | QString conflictingVersionToString(const ExclusiveVersionRange &r) |
154 | { |
155 | using namespace Qt::StringLiterals; |
156 | |
157 | QString s = r.claimerName; |
158 | if (r.addedIn.isValid()) { |
159 | s += u" (added in %1.%2)"_s .arg(a: r.addedIn.majorVersion()).arg(a: r.addedIn.minorVersion()); |
160 | } |
161 | if (r.removedIn.isValid()) { |
162 | s += u" (removed in %1.%2)"_s .arg(a: r.removedIn.majorVersion()) |
163 | .arg(a: r.removedIn.minorVersion()); |
164 | } |
165 | return s; |
166 | }; |
167 | |
168 | // Return a name for the registration variable containing the module to |
169 | // avoid clashes in Unity builds. |
170 | static QString registrationVarName(const QString &module) |
171 | { |
172 | auto specialCharPred = [](QChar c) { return !c.isLetterOrNumber(); }; |
173 | QString result = module; |
174 | result[0] = result.at(i: 0).toLower(); |
175 | result.erase(first: std::remove_if(first: result.begin(), last: result.end(), pred: specialCharPred), last: result.end()); |
176 | return result + "Registration"_L1 ; |
177 | } |
178 | |
179 | void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) const |
180 | { |
181 | output << uR"(/**************************************************************************** |
182 | ** Generated QML type registration code |
183 | ** |
184 | ** WARNING! All changes made in this file will be lost! |
185 | *****************************************************************************/ |
186 | |
187 | )"_s ; |
188 | |
189 | output << u"#include <QtQml/qqml.h>\n"_s ; |
190 | output << u"#include <QtQml/qqmlmoduleregistration.h>\n"_s ; |
191 | |
192 | for (const QString &include : m_includes) { |
193 | output << u"\n#if __has_include(<%1>)"_s .arg(a: include); |
194 | output << u"\n# include <%1>"_s .arg(a: include); |
195 | output << u"\n#endif"_s ; |
196 | } |
197 | |
198 | output << u"\n\n"_s ; |
199 | |
200 | // Keep this in sync with _qt_internal_get_escaped_uri in CMake |
201 | QString moduleAsSymbol = m_module; |
202 | static const QRegularExpression nonAlnumRegexp(QLatin1String("[^A-Za-z0-9]" )); |
203 | moduleAsSymbol.replace(re: nonAlnumRegexp, QStringLiteral("_" )); |
204 | |
205 | QString underscoredModuleAsSymbol = m_module; |
206 | underscoredModuleAsSymbol.replace(before: QLatin1Char('.'), after: QLatin1Char('_')); |
207 | |
208 | if (underscoredModuleAsSymbol != moduleAsSymbol |
209 | || underscoredModuleAsSymbol.isEmpty() |
210 | || underscoredModuleAsSymbol.front().isDigit()) { |
211 | warning(fileName: outFileName) << m_module << "is an invalid QML module URI. You cannot import this." ; |
212 | } |
213 | |
214 | const QString functionName = QStringLiteral("qml_register_types_" ) + moduleAsSymbol; |
215 | output << uR"( |
216 | #if !defined(QT_STATIC) |
217 | #define Q_QMLTYPE_EXPORT Q_DECL_EXPORT |
218 | #else |
219 | #define Q_QMLTYPE_EXPORT |
220 | #endif |
221 | )"_s ; |
222 | |
223 | if (!m_targetNamespace.isEmpty()) |
224 | output << u"namespace "_s << m_targetNamespace << u" {\n"_s ; |
225 | |
226 | output << u"Q_QMLTYPE_EXPORT void "_s << functionName << u"()\n{"_s ; |
227 | const quint8 majorVersion = m_moduleVersion.majorVersion(); |
228 | const quint8 minorVersion = m_moduleVersion.minorVersion(); |
229 | |
230 | for (const auto &version : m_pastMajorVersions) { |
231 | output << uR"( |
232 | qmlRegisterModule("%1", %2, 0); |
233 | qmlRegisterModule("%1", %2, 254);)"_s .arg(a: m_module) |
234 | .arg(a: version); |
235 | } |
236 | |
237 | if (minorVersion != 0) { |
238 | output << uR"( |
239 | qmlRegisterModule("%1", %2, 0);)"_s .arg(a: m_module) |
240 | .arg(a: majorVersion); |
241 | } |
242 | |
243 | output << uR"( |
244 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED)"_s ; |
245 | |
246 | QVector<QAnyStringView> typesRegisteredAnonymously; |
247 | |
248 | const auto fillTypesRegisteredAnonymously = [&](const auto &members, QAnyStringView typeName) { |
249 | bool foundRevisionEntry = false; |
250 | for (const auto &entry : members) { |
251 | if (entry.revision.isValid()) { |
252 | foundRevisionEntry = true; |
253 | break; |
254 | } |
255 | } |
256 | |
257 | if (!foundRevisionEntry) |
258 | return false; |
259 | |
260 | if (typesRegisteredAnonymously.contains(t: typeName)) |
261 | return true; |
262 | |
263 | typesRegisteredAnonymously.append(t: typeName); |
264 | |
265 | if (m_followForeignVersioning) { |
266 | output << uR"( |
267 | qmlRegisterAnonymousTypesAndRevisions<%1>("%2", %3);)"_s .arg(args: typeName.toString(), args: m_module) |
268 | .arg(a: majorVersion); |
269 | return true; |
270 | } |
271 | |
272 | for (const auto &version |
273 | : m_pastMajorVersions + decltype(m_pastMajorVersions){ majorVersion }) { |
274 | output << uR"( |
275 | qmlRegisterAnonymousType<%1, 254>("%2", %3);)"_s .arg(args: typeName.toString(), args: m_module) |
276 | .arg(a: version); |
277 | } |
278 | |
279 | return true; |
280 | }; |
281 | |
282 | |
283 | QHash<QString, QList<ExclusiveVersionRange>> qmlElementInfos; |
284 | |
285 | for (const MetaType &classDef : std::as_const(t: m_types)) { |
286 | |
287 | // Do not generate C++ registrations for JavaScript types. |
288 | if (classDef.inputFile().isEmpty()) |
289 | continue; |
290 | |
291 | QString className = classDef.qualifiedClassName().toString(); |
292 | QString targetName = className; |
293 | |
294 | // If either the foreign or the local part is a namespace we need to |
295 | // generate a namespace registration. |
296 | bool targetIsNamespace = classDef.kind() == MetaType::Kind::Namespace; |
297 | |
298 | QAnyStringView extendedName; |
299 | QList<QString> qmlElementNames; |
300 | QTypeRevision addedIn; |
301 | QTypeRevision removedIn; |
302 | |
303 | for (const ClassInfo &v : classDef.classInfos()) { |
304 | const QAnyStringView name = v.name; |
305 | if (name == S_ELEMENT) { |
306 | qmlElementNames.append(t: v.value.toString()); |
307 | } else if (name == S_FOREIGN) { |
308 | targetName = v.value.toString(); |
309 | } else if (name == S_FOREIGN_IS_NAMESPACE) { |
310 | targetIsNamespace = targetIsNamespace || (v.value == S_TRUE); |
311 | } else if (name == S_EXTENDED) { |
312 | extendedName = v.value; |
313 | } else if (name == S_ADDED_IN_VERSION) { |
314 | int version = toInt(string: v.value); |
315 | addedIn = QTypeRevision::fromEncodedVersion(value: version); |
316 | addedIn = handleInMinorVersion(revision: addedIn, majorVersion); |
317 | } else if (name == S_REMOVED_IN_VERSION) { |
318 | int version = toInt(string: v.value); |
319 | removedIn = QTypeRevision::fromEncodedVersion(value: version); |
320 | removedIn = handleInMinorVersion(revision: removedIn, majorVersion); |
321 | } |
322 | } |
323 | |
324 | for (QString qmlElementName : std::as_const(t&: qmlElementNames)) { |
325 | if (qmlElementName == S_ANONYMOUS) |
326 | continue; |
327 | if (qmlElementName == S_AUTO) |
328 | qmlElementName = className; |
329 | qmlElementInfos[qmlElementName].append(t: { |
330 | .fileName: classDef.inputFile(), |
331 | .claimerName: className, |
332 | .addedIn: addedIn, |
333 | .removedIn: removedIn |
334 | }); |
335 | } |
336 | |
337 | // We want all related metatypes to be registered by name, so that we can look them up |
338 | // without including the C++ headers. That's the reason for the QMetaType(foo).id() calls. |
339 | |
340 | const QList<QAnyStringView> namespaces |
341 | = MetaTypesJsonProcessor::namespaces(classDef); |
342 | |
343 | const FoundType target = QmlTypesClassDescription::findType( |
344 | types: m_types, foreign: m_foreignTypes, name: targetName, namespaces); |
345 | |
346 | if (targetIsNamespace) { |
347 | // We need to figure out if the _target_ is a namespace. If not, it already has a |
348 | // QMetaType and we don't need to generate one. |
349 | |
350 | QString targetTypeName = targetName; |
351 | |
352 | if (!target.javaScript.isEmpty() && target.native.isEmpty()) |
353 | warning(classDef: target.javaScript) << "JavaScript type cannot be used as namespace" ; |
354 | |
355 | if (target.native.kind() == MetaType::Kind::Object) |
356 | targetTypeName += " *"_L1 ; |
357 | |
358 | // If there is no foreign type, the local one is a namespace. |
359 | // Otherwise, only do metaTypeForNamespace if the target _metaobject_ is a namespace. |
360 | // Not if we merely consider it to be a namespace for QML purposes. |
361 | if (className == targetName || target.native.kind() == MetaType::Kind::Namespace) { |
362 | output << uR"( |
363 | { |
364 | Q_CONSTINIT static auto metaType = QQmlPrivate::metaTypeForNamespace( |
365 | [](const QtPrivate::QMetaTypeInterface *) {return &%1::staticMetaObject;}, |
366 | "%2"); |
367 | QMetaType(&metaType).id(); |
368 | })"_s .arg(args&: targetName, args&: targetTypeName); |
369 | } else { |
370 | Q_ASSERT(!targetTypeName.isEmpty()); |
371 | output << u"\n QMetaType::fromType<%1>().id();"_s .arg(a: targetTypeName); |
372 | } |
373 | |
374 | auto metaObjectPointer = [](QAnyStringView name) -> QString { |
375 | QString result; |
376 | const QLatin1StringView staticMetaObject = "::staticMetaObject"_L1 ; |
377 | result.reserve(asize: 1 + name.length() + staticMetaObject.length()); |
378 | result.append(c: '&'_L1); |
379 | name.visit(v: [&](auto view) { result.append(view); }); |
380 | result.append(s: staticMetaObject); |
381 | return result; |
382 | }; |
383 | |
384 | if (!qmlElementNames.isEmpty()) { |
385 | output << uR"( |
386 | qmlRegisterNamespaceAndRevisions(%1, "%2", %3, nullptr, %4, %5);)"_s |
387 | .arg(args: metaObjectPointer(targetName), args: m_module) |
388 | .arg(a: majorVersion) |
389 | .arg(args: metaObjectPointer(className), |
390 | args: extendedName.isEmpty() ? QStringLiteral("nullptr" ) |
391 | : metaObjectPointer(extendedName)); |
392 | } |
393 | } else { |
394 | if (!qmlElementNames.isEmpty()) { |
395 | auto checkRevisions = [&](const auto &array, QLatin1StringView type) { |
396 | for (auto it = array.begin(); it != array.end(); ++it) { |
397 | if (!it->revision.isValid()) |
398 | continue; |
399 | |
400 | QTypeRevision revision = it->revision; |
401 | if (m_moduleVersion < revision) { |
402 | warning(classDef) |
403 | << className << "is trying to register" << type |
404 | << it->name |
405 | << "with future version" << revision |
406 | << "when module version is only" << m_moduleVersion; |
407 | } |
408 | } |
409 | }; |
410 | |
411 | const Method::Container methods = classDef.methods(); |
412 | const Property::Container properties = classDef.properties(); |
413 | |
414 | if (m_moduleVersion.isValid()) { |
415 | checkRevisions(properties, S_PROPERTY); |
416 | checkRevisions(methods, S_METHOD); |
417 | } |
418 | |
419 | output << uR"( |
420 | qmlRegisterTypesAndRevisions<%1>("%2", %3);)"_s .arg(args&: className, args: m_module).arg(a: majorVersion); |
421 | |
422 | const BaseType::Container superClasses = classDef.superClasses(); |
423 | |
424 | for (const BaseType &object : classDef.superClasses()) { |
425 | if (object.access != Access::Public) |
426 | continue; |
427 | |
428 | QAnyStringView superClassName = object.name; |
429 | |
430 | QVector<QAnyStringView> classesToCheck; |
431 | |
432 | auto checkForRevisions = [&](QAnyStringView typeName) -> void { |
433 | auto typeAsMap = findType(name: typeName); |
434 | |
435 | if (typeAsMap.isEmpty()) { |
436 | typeAsMap = findTypeForeign(name: typeName); |
437 | if (typeAsMap.isEmpty()) |
438 | return; |
439 | |
440 | if (!fillTypesRegisteredAnonymously( |
441 | typeAsMap.properties(), typeName)) { |
442 | if (!fillTypesRegisteredAnonymously( |
443 | typeAsMap.sigs(), typeName)) { |
444 | fillTypesRegisteredAnonymously( |
445 | typeAsMap.methods(), typeName); |
446 | } |
447 | } |
448 | } |
449 | |
450 | for (const BaseType &object : typeAsMap.superClasses()) { |
451 | if (object.access == Access::Public) |
452 | classesToCheck << object.name; |
453 | } |
454 | }; |
455 | |
456 | checkForRevisions(superClassName); |
457 | |
458 | while (!classesToCheck.isEmpty()) |
459 | checkForRevisions(classesToCheck.takeFirst()); |
460 | } |
461 | } else { |
462 | Q_ASSERT(!className.isEmpty()); |
463 | output << uR"( |
464 | QMetaType::fromType<%1%2>().id();)"_s .arg( |
465 | args&: className, args: classDef.kind() == MetaType::Kind::Object ? u" *" : u"" ); |
466 | } |
467 | } |
468 | |
469 | const auto enums = target.native.enums(); |
470 | for (const auto &enumerator : enums) { |
471 | output << uR"( |
472 | QMetaType::fromType<%1::%2>().id();)"_s .arg( |
473 | args&: targetName, args: enumerator.name.toString()); |
474 | if (!enumerator.alias.isEmpty()) { |
475 | output << uR"( |
476 | QMetaType::fromType<%1::%2>().id();)"_s .arg( |
477 | args&: targetName, args: enumerator.alias.toString()); |
478 | } |
479 | } |
480 | } |
481 | |
482 | for (const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) { |
483 | // needs a least two cpp classes exporting the same qml element to potentially have a |
484 | // conflict |
485 | if (exportsForSameQmlName.size() < 2) |
486 | continue; |
487 | |
488 | // sort exports by versions to find conflicting exports |
489 | std::sort(first: exportsForSameQmlName.begin(), last: exportsForSameQmlName.end()); |
490 | auto conflictingExportStartIt = exportsForSameQmlName.cbegin(); |
491 | while (1) { |
492 | // conflicting versions evaluate to true under operator== |
493 | conflictingExportStartIt = |
494 | std::adjacent_find(first: conflictingExportStartIt, last: exportsForSameQmlName.cend()); |
495 | if (conflictingExportStartIt == exportsForSameQmlName.cend()) |
496 | break; |
497 | |
498 | auto conflictingExportEndIt = std::find_if_not( |
499 | first: conflictingExportStartIt, last: exportsForSameQmlName.cend(), |
500 | pred: [=](const auto &x) -> bool { return x == *conflictingExportStartIt; }); |
501 | QString registeringCppClasses = conflictingExportStartIt->claimerName; |
502 | std::for_each(first: std::next(x: conflictingExportStartIt), last: conflictingExportEndIt, |
503 | f: [&](const auto &q) { |
504 | registeringCppClasses += u", %1"_s .arg(conflictingVersionToString(q)); |
505 | }); |
506 | warning(fileName: conflictingExportStartIt->fileName) |
507 | << qmlName << "is registered multiple times by the following C++ classes:" |
508 | << registeringCppClasses; |
509 | conflictingExportStartIt = conflictingExportEndIt; |
510 | } |
511 | } |
512 | |
513 | output << uR"( |
514 | QT_WARNING_POP |
515 | qmlRegisterModule("%1", %2, %3); |
516 | } |
517 | |
518 | static const QQmlModuleRegistration %5("%1", %4); |
519 | )"_s .arg(a: m_module) |
520 | .arg(a: majorVersion) |
521 | .arg(a: minorVersion) |
522 | .arg(args: functionName, args: registrationVarName(module: m_module)); |
523 | |
524 | if (!m_targetNamespace.isEmpty()) |
525 | output << u"} // namespace %1\n"_s .arg(a: m_targetNamespace); |
526 | } |
527 | |
528 | bool QmlTypeRegistrar::generatePluginTypes(const QString &pluginTypesFile, bool generatingJSRoot) |
529 | { |
530 | QmlTypesCreator creator; |
531 | creator.setOwnTypes(m_types); |
532 | creator.setForeignTypes(m_foreignTypes); |
533 | creator.setReferencedTypes(m_referencedTypes); |
534 | creator.setUsingDeclarations(m_usingDeclarations); |
535 | creator.setModule(m_module.toUtf8()); |
536 | creator.setVersion(QTypeRevision::fromVersion(majorVersion: m_moduleVersion.majorVersion(), minorVersion: 0)); |
537 | creator.setGeneratingJSRoot(generatingJSRoot); |
538 | |
539 | return creator.generate(outFileName: pluginTypesFile); |
540 | } |
541 | |
542 | void QmlTypeRegistrar::setModuleNameAndNamespace(const QString &module, |
543 | const QString &targetNamespace) |
544 | { |
545 | m_module = module; |
546 | m_targetNamespace = targetNamespace; |
547 | } |
548 | void QmlTypeRegistrar::setModuleVersions(QTypeRevision moduleVersion, |
549 | const QList<quint8> &pastMajorVersions, |
550 | bool followForeignVersioning) |
551 | { |
552 | m_moduleVersion = moduleVersion; |
553 | m_pastMajorVersions = pastMajorVersions; |
554 | m_followForeignVersioning = followForeignVersioning; |
555 | } |
556 | void QmlTypeRegistrar::setIncludes(const QList<QString> &includes) |
557 | { |
558 | m_includes = includes; |
559 | } |
560 | void QmlTypeRegistrar::setTypes( |
561 | const QVector<MetaType> &types, const QVector<MetaType> &foreignTypes) |
562 | { |
563 | m_types = types; |
564 | m_foreignTypes = foreignTypes; |
565 | } |
566 | void QmlTypeRegistrar::setReferencedTypes(const QList<QAnyStringView> &referencedTypes) |
567 | { |
568 | m_referencedTypes = referencedTypes; |
569 | } |
570 | |
571 | void QmlTypeRegistrar::setUsingDeclarations(const QList<UsingDeclaration> &usingDeclarations) |
572 | { |
573 | m_usingDeclarations = usingDeclarations; |
574 | } |
575 | |
576 | QT_END_NAMESPACE |
577 | |