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
148 if (!collector.isCreatable || collector.isSingleton)
150
151 if (collector.isStructured)
153
154 if (collector.isSingleton)
156
157 if (collector.hasCustomParser)
159
161
162 if (!collector.attachedType.isEmpty())
164}
165
166void QmlTypesCreator::writeType(QAnyStringView type)
167{
168 ResolvedTypeAlias resolved(type, m_usingDeclarations);
169 if (resolved.type.isEmpty())
170 return;
171
172 m_qml.writeStringBinding(S_TYPE, resolved.type);
173 if (resolved.isList)
174 m_qml.writeBooleanBinding(S_IS_LIST, true);
175 if (resolved.isPointer)
177 if (resolved.isConstant)
179}
180
181void QmlTypesCreator::writeProperties(const Property::Container &properties)
182{
183 for (const Property &obj : properties) {
184 const QAnyStringView name = obj.name;
187 if (obj.revision.isValid())
188 m_qml.writeNumberBinding(S_REVISION, obj.revision.toEncodedVersion<int>());
189
190 writeType(obj.type);
191
192 const auto bindable = obj.bindable;
193 if (!bindable.isEmpty())
194 m_qml.writeStringBinding(S_BINDABLE, bindable);
195 const auto read = obj.read;
196 if (!read.isEmpty())
198 const auto write = obj.write;
199 if (!write.isEmpty())
201 const auto reset = obj.reset;
202 if (!reset.isEmpty())
204 const auto notify = obj.notify;
205 if (!notify.isEmpty())
206 m_qml.writeStringBinding(S_NOTIFY, notify);
207 const auto index = obj.index;
208 if (index != -1) {
210 }
211 const auto privateClass = obj.privateClass;
212 if (!privateClass.isEmpty()) {
213 m_qml.writeStringBinding(
215 }
216
217 if (obj.write.isEmpty() && obj.member.isEmpty())
219
220 if (obj.isFinal)
221 m_qml.writeBooleanBinding(S_IS_FINAL, true);
222
223 if (obj.isConstant)
225
226 if (obj.isRequired)
228
229 m_qml.writeEndObject();
230 }
231}
232
233void QmlTypesCreator::writeMethods(const Method::Container &methods, QLatin1StringView type)
234{
235 for (const Method &obj : methods) {
236 const QAnyStringView name = obj.name;
237 if (name.isEmpty())
238 continue;
239
240 const auto revision = obj.revision;
241 m_qml.writeStartObject(type);
243 if (revision.isValid())
244 m_qml.writeNumberBinding(S_REVISION, revision.toEncodedVersion<int>());
245 writeType(obj.returnType);
246
247 if (obj.isCloned)
248 m_qml.writeBooleanBinding(S_IS_CLONED, true);
249 if (obj.isConstructor)
251 if (obj.isJavaScriptFunction)
253
254 const Argument::Container &arguments = obj.arguments;
255 for (qsizetype i = 0, end = arguments.size(); i != end; ++i) {
256 const Argument &obj = arguments[i];
258 const QAnyStringView name = obj.name;
259 if (!name.isEmpty())
261 writeType(obj.type);
262 m_qml.writeEndObject();
263 }
264 m_qml.writeEndObject();
265 }
266}
267
268void QmlTypesCreator::writeEnums(
269 const Enum::Container &enums, QmlTypesCreator::EnumClassesMode enumClassesMode)
270{
271 for (const Enum &obj : enums) {
273 m_qml.writeStringBinding(S_NAME, obj.name);
274 if (!obj.alias.isEmpty())
275 m_qml.writeStringBinding(S_ALIAS, obj.alias);
276 if (obj.isFlag)
277 m_qml.writeBooleanBinding(S_IS_FLAG, true);
278
279 if (enumClassesMode == EnumClassesMode::Scoped) {
280 if (obj.isClass)
281 m_qml.writeBooleanBinding(S_IS_SCOPED, true);
282 }
283
284 writeType(obj.type);
285 m_qml.writeStringListBinding(S_VALUES, obj.values);
286 m_qml.writeEndObject();
287 }
288}
289
290template<typename Member>
291bool isAllowedInMajorVersion(const Member &memberObject, QTypeRevision maxMajorVersion)
292{
293 const QTypeRevision memberRevision = memberObject.revision;
294 return !memberRevision.hasMajorVersion()
295 || memberRevision.majorVersion() <= maxMajorVersion.majorVersion();
296}
297
298template<typename Members, typename Postprocess>
299Members members(const Members &candidates, QTypeRevision maxMajorVersion, Postprocess &&process)
300{
301 Members classDefMembers;
302
303 for (const auto &member : candidates) {
304 if (isAllowedInMajorVersion(member, maxMajorVersion))
305 classDefMembers.push_back(process(member));
306 }
307
308 return classDefMembers;
309}
310
311template<typename Members>
312Members members(const Members &candidates, QTypeRevision maxMajorVersion)
313{
314 return members(candidates, maxMajorVersion, [](const auto &member) { return member; });
315}
316
317template<typename Members>
318Members constructors(const Members &candidates, QTypeRevision maxMajorVersion)
319{
320 return members(candidates, maxMajorVersion, [](const auto &member) {
321 auto ctor = member;
322 ctor.isConstructor = true;
323 return ctor;
324 });
325}
326
327void QmlTypesCreator::writeRootMethods(const MetaType &classDef)
328{
329 // Hide destroyed() signals
330 Method::Container componentSignals = members(classDef.sigs(), m_version);
331 for (auto it = componentSignals.begin(); it != componentSignals.end();) {
332 if (it->name == "destroyed"_L1)
333 it = componentSignals.erase(it);
334 else
335 ++it;
336 }
337 writeMethods(componentSignals, S_SIGNAL);
338
339 // Hide deleteLater() methods
340 Method::Container componentMethods = members(classDef.methods(), m_version);
341 for (auto it = componentMethods.begin(); it != componentMethods.end();) {
342 if (it->name == "deleteLater"_L1)
343 it = componentMethods.erase(it);
344 else
345 ++it;
346 }
347
348 // Add toString()
349 Method toStringMethod;
350 toStringMethod.name = "toString"_L1;
351 toStringMethod.access = Access::Public;
352 toStringMethod.returnType = "QString"_L1;
353 componentMethods.push_back(std::move(toStringMethod));
354
355 // Add destroy(int)
356 Method destroyMethodWithArgument;
357 destroyMethodWithArgument.name = "destroy"_L1;
358 destroyMethodWithArgument.access = Access::Public;
359 Argument delayArgument;
360 delayArgument.name = "delay"_L1;
361 delayArgument.type = "int"_L1;
362 destroyMethodWithArgument.arguments.push_back(std::move(delayArgument));
363 componentMethods.push_back(std::move(destroyMethodWithArgument));
364
365 // Add destroy()
366 Method destroyMethod;
367 destroyMethod.name = "destroy"_L1;
368 destroyMethod.access = Access::Public;
369 destroyMethod.isCloned = true;
370 componentMethods.push_back(std::move(destroyMethod));
371
372 writeMethods(componentMethods, S_METHOD);
373};
374
375void QmlTypesCreator::writeComponent(const QmlTypesClassDescription &collector)
376{
378
379 writeClassProperties(collector);
380
381 if (const MetaType &classDef = collector.resolvedClass; !classDef.isEmpty()) {
382 writeEnums(
383 classDef.enums(),
385 ? EnumClassesMode::Scoped
386 : EnumClassesMode::Unscoped);
387
388 writeProperties(members(classDef.properties(), m_version));
389
390 if (collector.isRootClass) {
391 writeRootMethods(classDef);
392 } else {
393 writeMethods(members(classDef.sigs(), m_version), S_SIGNAL);
394 writeMethods(members(classDef.methods(), m_version), S_METHOD);
395 }
396
397 writeMethods(constructors(classDef.constructors(), m_version), S_METHOD);
398 }
399 m_qml.writeEndObject();
400}
401
402void QmlTypesCreator::writeComponents()
403{
404 for (const MetaType &component : std::as_const(m_ownTypes)) {
405 QmlTypesClassDescription collector;
406 collector.collect(component, m_ownTypes, m_foreignTypes,
408
409 writeComponent(collector);
410
411 if (collector.resolvedClass != component
412 && std::binary_search(
413 m_referencedTypes.begin(), m_referencedTypes.end(),
414 component.qualifiedClassName())) {
415
416 // This type is referenced from elsewhere and has a QML_FOREIGN of its own. We need to
417 // also generate a description of the local type then. All the QML_* macros are
418 // ignored, and the result is an anonymous type.
419
420 QmlTypesClassDescription collector;
421 collector.collectLocalAnonymous(component, m_ownTypes, m_foreignTypes, m_version);
422 Q_ASSERT(!collector.isRootClass);
423
424 writeComponent(collector);
425 }
426 }
427}
428
429bool QmlTypesCreator::generate(const QString &outFileName)
430{
431 m_qml.writeStartDocument();
432 m_qml.writeLibraryImport("QtQuick.tooling", 1, 2);
433 m_qml.write(
434 "\n// This file describes the plugin-supplied types contained in the library."
435 "\n// It is used for QML tooling purposes only."
436 "\n//"
437 "\n// This file was auto-generated by qmltyperegistrar.\n\n");
439
440 writeComponents();
441
442 m_qml.writeEndObject();
443
444 QSaveFile file(outFileName);
446 return false;
447
448 if (file.write(m_output) != m_output.size())
449 return false;
450
451 return file.commit();
452}
453
455
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:495
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:906
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:398
bool isEmpty() const noexcept
Definition qlist.h:402
iterator end()
Definition qlist.h:627
iterator begin()
Definition qlist.h:626
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:137
iterator end()
Definition qset.h:141
iterator erase(const_iterator i)
Definition qset.h:146
\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_IS_PROPERTY_CONSTANT
static constexpr QLatin1StringView S_ENUM
static constexpr QLatin1StringView S_IS_TYPE_CONSTANT
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_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)