Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmltypescreator.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
9
10#include <QtCore/qset.h>
11#include <QtCore/qcborarray.h>
12#include <QtCore/qcbormap.h>
13#include <QtCore/qsavefile.h>
14#include <QtCore/qfile.h>
15#include <QtCore/qversionnumber.h>
16
17#include <QtCore/private/qstringalgorithms_p.h>
18
20
21using namespace Qt::StringLiterals;
22using namespace Constants;
23using namespace Constants::DotQmltypes;
24using namespace QAnyStringViewUtils;
25
27{
28 // typical privateClass entry in MOC looks like: ClassName::d_func(), where
29 // ClassName is a non-private class name. we don't need "::d_func()" piece
30 // so that could be removed, but we need "Private" so that ClassName becomes
31 // ClassNamePrivate (at present, simply consider this correct)
32 return s.toString().replace("::d_func()"_L1, "Private"_L1);
33}
34
35void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &collector)
36{
37 if (!collector.file.isEmpty())
38 m_qml.writeStringBinding(S_FILE, collector.file);
39 m_qml.writeStringBinding(S_NAME, collector.className);
40
41 if (!collector.primitiveAliases.isEmpty())
43
44 if (!collector.accessSemantics.isEmpty())
46
47 if (!collector.defaultProp.isEmpty())
49
50 if (!collector.parentProp.isEmpty())
52
53 if (!collector.superClass.isEmpty())
55
56 if (!collector.sequenceValueType.isEmpty()) {
57 const QAnyStringView name = collector.sequenceValueType.back() == '*'_L1
58 ? collector.sequenceValueType.chopped(1)
59 : collector.sequenceValueType;
61 }
62
63 if (collector.extensionIsJavaScript) {
64 if (!collector.javaScriptExtensionType.isEmpty()) {
67 } else {
68 warning(collector.file)
69 << "JavaScript extension type for" << collector.className
70 << "does not exist";
71 }
72
73 if (collector.extensionIsNamespace) {
74 warning(collector.file)
75 << "Extension type for" << collector.className
76 << "cannot be both a JavaScript type and a namespace";
77 if (!collector.nativeExtensionType.isEmpty()) {
80 }
81 }
82 } else if (!collector.nativeExtensionType.isEmpty()) {
84 if (collector.extensionIsNamespace)
86 } else if (collector.extensionIsNamespace) {
87 warning(collector.file)
88 << "Extension namespace for" << collector.className << "does not exist";
90 }
91
92 if (!collector.implementsInterfaces.isEmpty())
94
95 if (!collector.deferredNames.isEmpty())
97
98 if (!collector.immediateNames.isEmpty())
100
101 if (collector.elementNames.isEmpty()) // e.g. if QML_ANONYMOUS
102 return;
103
104 if (!collector.sequenceValueType.isEmpty()) {
105 warning(collector.file) << "Ignoring names of sequential container:";
106 for (const QAnyStringView &name : std::as_const(collector.elementNames))
107 warning(collector.file) << " - " << name.toString();
108 warning(collector.file)
109 << "Sequential containers are anonymous. Use QML_ANONYMOUS to register them.";
110 return;
111 }
112
113 QByteArrayList exports;
114 QByteArrayList metaObjects;
115
116 for (auto it = collector.revisions.begin(), end = collector.revisions.end(); it != end; ++it) {
117 const QTypeRevision revision = *it;
118 if (revision < collector.addedInRevision)
119 continue;
120 if (collector.removedInRevision.isValid() && !(revision < collector.removedInRevision))
121 break;
122 if (revision.hasMajorVersion() && revision.majorVersion() > m_version.majorVersion())
123 break;
124
125 for (const QAnyStringView &elementName : std::as_const(collector.elementNames)) {
126 QByteArray exportEntry = m_module + '/';
127
128 elementName.visit([&](auto view) {
129 processAsUtf8(view, [&](QByteArrayView view) { exportEntry.append(view); });
130 });
131 exportEntry += ' ' + QByteArray::number(revision.hasMajorVersion()
132 ? revision.majorVersion()
133 : m_version.majorVersion());
134 exportEntry += '.' + QByteArray::number(revision.minorVersion());
135
136 exports.append(exportEntry);
137 }
138 metaObjects.append(QByteArray::number(revision.toEncodedVersion<quint16>()));
139 }
140
141 QList<QAnyStringView> exportStrings;
142 exportStrings.reserve(exports.length());
143 for (const QByteArray &entry: exports)
144 exportStrings.append(QUtf8StringView(entry));
145
146 m_qml.writeStringListBinding(S_EXPORTS, exportStrings);
147 m_qml.writeBooleanBinding(S_IS_CREATABLE, collector.isCreatable && !collector.isSingleton);
148
149 if (collector.isStructured)
151
152 if (collector.isSingleton)
154
155 if (collector.hasCustomParser)
157
159
160 if (!collector.attachedType.isEmpty())
162}
163
164void QmlTypesCreator::writeType(QAnyStringView type)
165{
166 ResolvedTypeAlias resolved(type);
167 if (resolved.type.isEmpty())
168 return;
169
170 m_qml.writeStringBinding(S_TYPE, resolved.type);
171 if (resolved.isList)
172 m_qml.writeBooleanBinding(S_IS_LIST, true);
173 if (resolved.isPointer)
175 if (resolved.isConstant)
177}
178
179void QmlTypesCreator::writeProperties(const Property::Container &properties)
180{
181 for (const Property &obj : properties) {
182 const QAnyStringView name = obj.name;
185 if (obj.revision.isValid())
186 m_qml.writeNumberBinding(S_REVISION, obj.revision.toEncodedVersion<int>());
187
188 writeType(obj.type);
189
190 const auto bindable = obj.bindable;
191 if (!bindable.isEmpty())
192 m_qml.writeStringBinding(S_BINDABLE, bindable);
193 const auto read = obj.read;
194 if (!read.isEmpty())
196 const auto write = obj.write;
197 if (!write.isEmpty())
199 const auto reset = obj.reset;
200 if (!reset.isEmpty())
202 const auto notify = obj.notify;
203 if (!notify.isEmpty())
204 m_qml.writeStringBinding(S_NOTIFY, notify);
205 const auto index = obj.index;
206 if (index != -1) {
208 }
209 const auto privateClass = obj.privateClass;
210 if (!privateClass.isEmpty()) {
211 m_qml.writeStringBinding(
213 }
214
215 if (obj.write.isEmpty() && obj.member.isEmpty())
217
218 if (obj.isFinal)
219 m_qml.writeBooleanBinding(S_IS_FINAL, true);
220
221 if (obj.isConstant)
223
224 if (obj.isRequired)
226
227 m_qml.writeEndObject();
228 }
229}
230
231void QmlTypesCreator::writeMethods(const Method::Container &methods, QLatin1StringView type)
232{
233 for (const Method &obj : methods) {
234 const QAnyStringView name = obj.name;
235 if (name.isEmpty())
236 continue;
237
238 const auto revision = obj.revision;
239 m_qml.writeStartObject(type);
241 if (revision.isValid())
242 m_qml.writeNumberBinding(S_REVISION, revision.toEncodedVersion<int>());
243 writeType(obj.returnType);
244
245 if (obj.isCloned)
246 m_qml.writeBooleanBinding(S_IS_CLONED, true);
247 if (obj.isConstructor)
249 if (obj.isJavaScriptFunction)
251
252 const Argument::Container &arguments = obj.arguments;
253 for (qsizetype i = 0, end = arguments.size(); i != end; ++i) {
254 const Argument &obj = arguments[i];
256 const QAnyStringView name = obj.name;
257 if (!name.isEmpty())
259 writeType(obj.type);
260 m_qml.writeEndObject();
261 }
262 m_qml.writeEndObject();
263 }
264}
265
266void QmlTypesCreator::writeEnums(
267 const Enum::Container &enums, QmlTypesCreator::EnumClassesMode enumClassesMode)
268{
269 for (const Enum &obj : enums) {
271 m_qml.writeStringBinding(S_NAME, obj.name);
272 if (!obj.alias.isEmpty())
273 m_qml.writeStringBinding(S_ALIAS, obj.alias);
274 if (obj.isFlag)
275 m_qml.writeBooleanBinding(S_IS_FLAG, true);
276
277 if (enumClassesMode == EnumClassesMode::Scoped) {
278 if (obj.isClass)
279 m_qml.writeBooleanBinding(S_IS_SCOPED, true);
280 }
281
282 writeType(obj.type);
283 m_qml.writeStringListBinding(S_VALUES, obj.values);
284 m_qml.writeEndObject();
285 }
286}
287
288template<typename Member>
289bool isAllowedInMajorVersion(const Member &memberObject, QTypeRevision maxMajorVersion)
290{
291 const QTypeRevision memberRevision = memberObject.revision;
292 return !memberRevision.hasMajorVersion()
293 || memberRevision.majorVersion() <= maxMajorVersion.majorVersion();
294}
295
296template<typename Members, typename Postprocess>
297Members members(const Members &candidates, QTypeRevision maxMajorVersion, Postprocess &&process)
298{
299 Members classDefMembers;
300
301 for (const auto &member : candidates) {
302 if (isAllowedInMajorVersion(member, maxMajorVersion))
303 classDefMembers.push_back(process(member));
304 }
305
306 return classDefMembers;
307}
308
309template<typename Members>
310Members members(const Members &candidates, QTypeRevision maxMajorVersion)
311{
312 return members(candidates, maxMajorVersion, [](const auto &member) { return member; });
313}
314
315template<typename Members>
316Members constructors(const Members &candidates, QTypeRevision maxMajorVersion)
317{
318 return members(candidates, maxMajorVersion, [](const auto &member) {
319 auto ctor = member;
320 ctor.isConstructor = true;
321 return ctor;
322 });
323}
324
325void QmlTypesCreator::writeRootMethods(const MetaType &classDef)
326{
327 // Hide destroyed() signals
328 Method::Container componentSignals = members(classDef.sigs(), m_version);
329 for (auto it = componentSignals.begin(); it != componentSignals.end();) {
330 if (it->name == "destroyed"_L1)
331 it = componentSignals.erase(it);
332 else
333 ++it;
334 }
335 writeMethods(componentSignals, S_SIGNAL);
336
337 // Hide deleteLater() methods
338 Method::Container componentMethods = members(classDef.methods(), m_version);
339 for (auto it = componentMethods.begin(); it != componentMethods.end();) {
340 if (it->name == "deleteLater"_L1)
341 it = componentMethods.erase(it);
342 else
343 ++it;
344 }
345
346 // Add toString()
347 Method toStringMethod;
348 toStringMethod.name = "toString"_L1;
349 toStringMethod.access = Access::Public;
350 toStringMethod.returnType = "QString"_L1;
351 componentMethods.push_back(std::move(toStringMethod));
352
353 // Add destroy(int)
354 Method destroyMethodWithArgument;
355 destroyMethodWithArgument.name = "destroy"_L1;
356 destroyMethodWithArgument.access = Access::Public;
357 Argument delayArgument;
358 delayArgument.name = "delay"_L1;
359 delayArgument.type = "int"_L1;
360 destroyMethodWithArgument.arguments.push_back(std::move(delayArgument));
361 componentMethods.push_back(std::move(destroyMethodWithArgument));
362
363 // Add destroy()
364 Method destroyMethod;
365 destroyMethod.name = "destroy"_L1;
366 destroyMethod.access = Access::Public;
367 destroyMethod.isCloned = true;
368 componentMethods.push_back(std::move(destroyMethod));
369
370 writeMethods(componentMethods, S_METHOD);
371};
372
373void QmlTypesCreator::writeComponent(const QmlTypesClassDescription &collector)
374{
376
377 writeClassProperties(collector);
378
379 if (const MetaType &classDef = collector.resolvedClass; !classDef.isEmpty()) {
380 writeEnums(
381 classDef.enums(),
383 ? EnumClassesMode::Scoped
384 : EnumClassesMode::Unscoped);
385
386 writeProperties(members(classDef.properties(), m_version));
387
388 if (collector.isRootClass) {
389 writeRootMethods(classDef);
390 } else {
391 writeMethods(members(classDef.sigs(), m_version), S_SIGNAL);
392 writeMethods(members(classDef.methods(), m_version), S_METHOD);
393 }
394
395 writeMethods(constructors(classDef.constructors(), m_version), S_METHOD);
396 }
397 m_qml.writeEndObject();
398}
399
400void QmlTypesCreator::writeComponents()
401{
402 for (const MetaType &component : std::as_const(m_ownTypes)) {
403 QmlTypesClassDescription collector;
404 collector.collect(component, m_ownTypes, m_foreignTypes,
406
407 writeComponent(collector);
408
409 if (collector.resolvedClass != component
410 && std::binary_search(
411 m_referencedTypes.begin(), m_referencedTypes.end(),
412 component.qualifiedClassName())) {
413
414 // This type is referenced from elsewhere and has a QML_FOREIGN of its own. We need to
415 // also generate a description of the local type then. All the QML_* macros are
416 // ignored, and the result is an anonymous type.
417
418 QmlTypesClassDescription collector;
419 collector.collectLocalAnonymous(component, m_ownTypes, m_foreignTypes, m_version);
420 Q_ASSERT(!collector.isRootClass);
421
422 writeComponent(collector);
423 }
424 }
425}
426
427bool QmlTypesCreator::generate(const QString &outFileName)
428{
429 m_qml.writeStartDocument();
430 m_qml.writeLibraryImport("QtQuick.tooling", 1, 2);
431 m_qml.write(
432 "\n// This file describes the plugin-supplied types contained in the library."
433 "\n// It is used for QML tooling purposes only."
434 "\n//"
435 "\n// This file was auto-generated by qmltyperegistrar.\n\n");
437
438 writeComponents();
439
440 m_qml.writeEndObject();
441
442 QSaveFile file(outFileName);
444 return false;
445
446 if (file.write(m_output) != m_output.size())
447 return false;
448
449 return file.commit();
450}
451
453
static JNINativeMethod methods[]
\inmodule QtCore
constexpr QChar back() const
Returns the last character in the string view.
Definition qstring.h:122
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
constexpr QAnyStringView chopped(qsizetype n) const
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
iterator end()
Definition qlist.h:626
iterator begin()
Definition qlist.h:625
void writeStringListBinding(QByteArrayView name, const QList< QAnyStringView > &elements)
void write(QByteArrayView data)
void writeLibraryImport(QByteArrayView uri, int majorVersion, int minorVersion, QByteArrayView as={})
void writeArrayBinding(QByteArrayView name, const QByteArrayList &elements)
void writeStartObject(QByteArrayView component)
void writeBooleanBinding(QByteArrayView name, bool value)
void writeStringBinding(QByteArrayView name, QAnyStringView value)
void writeNumberBinding(QByteArrayView name, qint64 value)
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
iterator erase(const_iterator i)
Definition qset.h:145
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
constexpr bool hasMajorVersion() const
Returns true if the major version is known, otherwise false.
constexpr quint8 minorVersion() const
Returns the minor version encoded in the revision.
constexpr bool isValid() const
Returns true if the major version or the minor version is known, otherwise false.
constexpr Integer toEncodedVersion() const
Transforms the revision into an integer value, encoding the minor version into the least significant ...
constexpr quint8 majorVersion() const
Returns the major version encoded in the revision.
bool generate(const QString &outFileName)
list append(new Employee("Blackpool", "Stephen"))
QSet< QString >::iterator it
QList< QVariant > arguments
static constexpr QLatin1StringView S_FILE
static constexpr QLatin1StringView S_EXTENSION_IS_JAVA_SCRIPT
static constexpr QLatin1StringView S_NOTIFY
static constexpr QLatin1StringView S_SIGNAL
static constexpr QLatin1StringView S_IS_SINGLETON
static constexpr QLatin1StringView S_IS_CONSTRUCTOR
static constexpr QLatin1StringView S_ACCESS_SEMANTICS
static constexpr QLatin1StringView S_IS_READONLY
static constexpr QLatin1StringView S_ENUM
static constexpr QLatin1StringView S_READ
static constexpr QLatin1StringView S_VALUE_TYPE
static constexpr QLatin1StringView S_PROPERTY
static constexpr QLatin1StringView S_INDEX
static constexpr QLatin1StringView S_IS_CREATABLE
static constexpr QLatin1StringView S_RESET
static constexpr QLatin1StringView S_TYPE
static constexpr QLatin1StringView S_MODULE
static constexpr QLatin1StringView S_PARAMETER
static constexpr QLatin1StringView S_IS_LIST
static constexpr QLatin1StringView S_IS_CLONED
static constexpr QLatin1StringView S_IS_REQUIRED
static constexpr QLatin1StringView S_IMMEDIATE_NAMES
static constexpr QLatin1StringView S_WRITE
static constexpr QLatin1StringView S_IS_JAVASCRIPT_FUNCTION
static constexpr QLatin1StringView S_EXPORTS
static constexpr QLatin1StringView S_REVISION
static constexpr QLatin1StringView S_DEFAULT_PROPERTY
static constexpr QLatin1StringView S_DEFERRED_NAMES
static constexpr QLatin1StringView S_METHOD
static constexpr QLatin1StringView S_IS_POINTER
static constexpr QLatin1StringView S_ALIAS
static constexpr QLatin1StringView S_VALUES
static constexpr QLatin1StringView S_IS_FLAG
static constexpr QLatin1StringView S_ALIASES
static constexpr QLatin1StringView S_COMPONENT
static constexpr QLatin1StringView S_PROTOTYPE
static constexpr QLatin1StringView S_EXPORT_META_OBJECT_REVISIONS
static constexpr QLatin1StringView S_ATTACHED_TYPE
static constexpr QLatin1StringView S_IS_FINAL
static constexpr QLatin1StringView S_HAS_CUSTOM_PARSER
static constexpr QLatin1StringView S_PARENT_PROPERTY
static constexpr QLatin1StringView S_IS_CONSTANT
static constexpr QLatin1StringView S_PRIVATE_CLASS
static constexpr QLatin1StringView S_EXTENSION_IS_NAMESPACE
static constexpr QLatin1StringView S_IS_SCOPED
static constexpr QLatin1StringView S_BINDABLE
static constexpr QLatin1StringView S_EXTENSION
static constexpr QLatin1StringView S_IS_STRUCTURED
static constexpr QLatin1StringView S_NAME
static constexpr QLatin1StringView S_INTERFACES
auto processAsUtf8(StringView string, Handler &&handler)
Combined button and popup list for selecting options.
static const QCssKnownValue properties[NumProperties - 1]
GLuint index
[2]
GLuint GLuint end
GLenum type
GLuint name
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
GLuint entry
static qreal component(const QPointF &point, unsigned int i)
QDebug warning(QAnyStringView fileName, int lineNumber)
Members members(const Members &candidates, QTypeRevision maxMajorVersion, Postprocess &&process)
bool isAllowedInMajorVersion(const Member &memberObject, QTypeRevision maxMajorVersion)
static QString convertPrivateClassToUsableForm(QAnyStringView s)
Members constructors(const Members &candidates, QTypeRevision maxMajorVersion)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned short quint16
Definition qtypes.h:48
ptrdiff_t qsizetype
Definition qtypes.h:165
ReturnedValue read(const char *data)
QFile file
[0]
gzip write("uncompressed data")
QQuickView * view
[0]
char * toString(const MyType &t)
[31]
std::vector< Argument > Container
QAnyStringView name
std::vector< Enum > Container
QAnyStringView name
std::vector< Method > Container
QList< QAnyStringView > implementsInterfaces
QList< QAnyStringView > primitiveAliases
void collect(const MetaType &classDef, const QVector< MetaType > &types, const QVector< MetaType > &foreign, CollectMode mode, QTypeRevision defaultRevision)
QList< QAnyStringView > immediateNames
QList< QAnyStringView > elementNames
QList< QAnyStringView > deferredNames
void collectLocalAnonymous(const MetaType &classDef, const QVector< MetaType > &types, const QVector< MetaType > &foreign, QTypeRevision defaultRevision)