Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtDeclarative/QtDeclarative>
43#include <QtDeclarative/private/qdeclarativemetatype_p.h>
44#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
45#include <QtDeclarative/QDeclarativeView>
46
47#include <QtGui/QApplication>
48
49#include <QtCore/QSet>
50#include <QtCore/QMetaObject>
51#include <QtCore/QMetaProperty>
52#include <QtCore/QDebug>
53#include <QtCore/private/qobject_p.h>
54#include <QtCore/private/qmetaobject_p.h>
55
56#include <iostream>
57
58#include "qmlstreamwriter.h"
59
60#ifdef QT_SIMULATOR
61#include <QtGui/private/qsimulatorconnection_p.h>
62#endif
63
64#ifdef Q_OS_UNIX
65#include <signal.h>
66#endif
67#ifdef Q_OS_WIN
68#include <crtdbg.h>
69#include <qt_windows.h>
70#endif
71
72QString pluginImportPath;
73bool verbose = false;
74bool creatable = true;
75
76QString currentProperty;
77QString inObjectInstantiation;
78
79void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
80{
81 if (! meta || metas->contains(meta))
82 return;
83
84 // dynamic meta objects break things badly, so just ignore them
85 const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
86 if (!(mop->flags & DynamicMetaObject))
87 metas->insert(meta);
88
89 collectReachableMetaObjects(meta->superClass(), metas);
90}
91
92void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
93{
94 if (! object)
95 return;
96
97 const QMetaObject *meta = object->metaObject();
98 if (verbose)
99 qDebug() << "Processing object" << meta->className();
100 collectReachableMetaObjects(meta, metas);
101
102 for (int index = 0; index < meta->propertyCount(); ++index) {
103 QMetaProperty prop = meta->property(index);
104 if (QDeclarativeMetaType::isQObject(prop.userType())) {
105 if (verbose)
106 qDebug() << " Processing property" << prop.name();
107 currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
108
109 // if the property was not initialized during construction,
110 // accessing a member of oo is going to cause a segmentation fault
111 QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
112 if (oo && !metas->contains(oo->metaObject()))
113 collectReachableMetaObjects(oo, metas);
114 currentProperty.clear();
115 }
116 }
117}
118
119void collectReachableMetaObjects(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
120{
121 collectReachableMetaObjects(ty->metaObject(), metas);
122 if (ty->attachedPropertiesType())
123 collectReachableMetaObjects(ty->attachedPropertiesType(), metas);
124}
125
126/* We want to add the MetaObject for 'Qt' to the list, this is a
127 simple way to access it.
128*/
129class FriendlyQObject: public QObject
130{
131public:
132 static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
133};
134
135/* When we dump a QMetaObject, we want to list all the types it is exported as.
136 To do this, we need to find the QDeclarativeTypes associated with this
137 QMetaObject.
138*/
139static QHash<QByteArray, QSet<const QDeclarativeType *> > qmlTypesByCppName;
140
141static QHash<QByteArray, QByteArray> cppToId;
142
143/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
144 maps it to how it should appear in the description file.
145
146 These names need to be unique globally, so we don't change the C++ symbol's
147 name much. It is mostly used to for explicit translations such as
148 QString->string and translations for extended QML objects.
149*/
150QByteArray convertToId(const QByteArray &cppName)
151{
152 return cppToId.value(cppName, cppName);
153}
154
155QByteArray convertToId(const QMetaObject *mo)
156{
157 QByteArray className(mo->className());
158 if (!className.isEmpty())
159 return convertToId(className);
160
161 // likely a metaobject generated for an extended qml object
162 if (mo->superClass()) {
163 className = convertToId(mo->superClass());
164 className.append("_extended");
165 return className;
166 }
167
168 static QHash<const QMetaObject *, QByteArray> generatedNames;
169 className = generatedNames.value(mo);
170 if (!className.isEmpty())
171 return className;
172
173 qWarning() << "Found a QMetaObject without a className, generating a random name";
174 className = QByteArray("error-unknown-name-");
175 className.append(QByteArray::number(generatedNames.size()));
176 generatedNames.insert(mo, className);
177 return className;
178}
179
180QSet<const QMetaObject *> collectReachableMetaObjects(const QList<QDeclarativeType *> &skip = QList<QDeclarativeType *>())
181{
182 QSet<const QMetaObject *> metas;
183 metas.insert(FriendlyQObject::qtMeta());
184
185 QHash<QByteArray, QSet<QByteArray> > extensions;
186 foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
187 qmlTypesByCppName[ty->metaObject()->className()].insert(ty);
188 if (ty->isExtendedType()) {
189 extensions[ty->typeName()].insert(ty->metaObject()->className());
190 }
191 collectReachableMetaObjects(ty, &metas);
192 }
193
194 // Adjust exports of the base object if there are extensions.
195 // For each export of a base object there can be a single extension object overriding it.
196 // Example: QDeclarativeGraphicsWidget overrides the QtQuick/QGraphicsWidget export
197 // of QGraphicsWidget.
198 foreach (const QByteArray &baseCpp, extensions.keys()) {
199 QSet<const QDeclarativeType *> baseExports = qmlTypesByCppName.value(baseCpp);
200
201 const QSet<QByteArray> extensionCppNames = extensions.value(baseCpp);
202 foreach (const QByteArray &extensionCppName, extensionCppNames) {
203 const QSet<const QDeclarativeType *> extensionExports = qmlTypesByCppName.value(extensionCppName);
204
205 // remove extension exports from base imports
206 // unfortunately the QDeclarativeType pointers don't match, so can't use QSet::substract
207 QSet<const QDeclarativeType *> newBaseExports;
208 foreach (const QDeclarativeType *baseExport, baseExports) {
209 bool match = false;
210 foreach (const QDeclarativeType *extensionExport, extensionExports) {
211 if (baseExport->qmlTypeName() == extensionExport->qmlTypeName()
212 && baseExport->majorVersion() == extensionExport->majorVersion()
213 && baseExport->minorVersion() == extensionExport->minorVersion()) {
214 match = true;
215 break;
216 }
217 }
218 if (!match)
219 newBaseExports.insert(baseExport);
220 }
221 baseExports = newBaseExports;
222 }
223 qmlTypesByCppName[baseCpp] = baseExports;
224 }
225
226 if (creatable) {
227 // find even more QMetaObjects by instantiating QML types and running
228 // over the instances
229 foreach (QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
230 if (skip.contains(ty))
231 continue;
232 if (ty->isExtendedType())
233 continue;
234 if (!ty->isCreatable())
235 continue;
236 if (ty->typeName() == "QDeclarativeComponent")
237 continue;
238
239 QByteArray tyName = ty->qmlTypeName();
240 tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
241 if (tyName.isEmpty())
242 continue;
243
244 inObjectInstantiation = tyName;
245 QObject *object = ty->create();
246 inObjectInstantiation.clear();
247
248 if (object)
249 collectReachableMetaObjects(object, &metas);
250 else
251 qWarning() << "Could not create" << tyName;
252 }
253 }
254
255 return metas;
256}
257
258
259class Dumper
260{
261 QmlStreamWriter *qml;
262 QString relocatableModuleUri;
263
264public:
265 Dumper(QmlStreamWriter *qml) : qml(qml) {}
266
267 void setRelocatableModuleUri(const QString &uri)
268 {
269 relocatableModuleUri = uri;
270 }
271
272 void dump(const QMetaObject *meta)
273 {
274 qml->writeStartObject("Component");
275
276 QByteArray id = convertToId(meta);
277 qml->writeScriptBinding(QLatin1String("name"), enquote(id));
278
279 for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
280 QMetaClassInfo classInfo = meta->classInfo(index);
281 if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
282 qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
283 break;
284 }
285 }
286
287 if (meta->superClass())
288 qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass())));
289
290 QSet<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(meta->className());
291 if (!qmlTypes.isEmpty()) {
292 QHash<QString, const QDeclarativeType *> exports;
293
294 foreach (const QDeclarativeType *qmlTy, qmlTypes) {
295 QString qmlTyName = qmlTy->qmlTypeName();
296 // some qmltype names are missing the actual names, ignore that import
297 if (qmlTyName.endsWith('/'))
298 continue;
299 if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) {
300 qmlTyName.remove(0, relocatableModuleUri.size() + 1);
301 }
302 if (qmlTyName.startsWith("./")) {
303 qmlTyName.remove(0, 2);
304 }
305 const QString exportString = enquote(
306 QString("%1 %2.%3").arg(
307 qmlTyName,
308 QString::number(qmlTy->majorVersion()),
309 QString::number(qmlTy->minorVersion())));
310 exports.insert(exportString, qmlTy);
311 }
312
313 // ensure exports are sorted and don't change order when the plugin is dumped again
314 QStringList exportStrings = exports.keys();
315 qSort(exportStrings);
316 qml->writeArrayBinding(QLatin1String("exports"), exportStrings);
317
318 // write meta object revisions
319 QStringList metaObjectRevisions;
320 foreach (const QString &exportString, exportStrings) {
321 int metaObjectRevision = exports[exportString]->metaObjectRevision();
322 metaObjectRevisions += QString::number(metaObjectRevision);
323 }
324 qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), metaObjectRevisions);
325
326 if (const QMetaObject *attachedType = (*qmlTypes.begin())->attachedPropertiesType()) {
327 // Can happen when a type is registered that returns itself as attachedPropertiesType()
328 // because there is no creatable type to attach to.
329 if (attachedType != meta) {
330 qml->writeScriptBinding(QLatin1String("attachedType"), enquote(
331 convertToId(attachedType)));
332 }
333 }
334 }
335
336 for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
337 dump(meta->enumerator(index));
338
339 for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
340 dump(meta->property(index));
341
342 for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
343 dump(meta->method(index));
344
345 qml->writeEndObject();
346 }
347
348 void writeEasingCurve()
349 {
350 qml->writeStartObject("Component");
351 qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve")));
352 qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QDeclarativeEasingValueType")));
353 qml->writeEndObject();
354 }
355
356private:
357 static QString enquote(const QString &string)
358 {
359 return QString("\"%1\"").arg(string);
360 }
361
362 /* Removes pointer and list annotations from a type name, returning
363 what was removed in isList and isPointer
364 */
365 static void removePointerAndList(QByteArray *typeName, bool *isList, bool *isPointer)
366 {
367 static QByteArray declListPrefix = "QDeclarativeListProperty<";
368
369 if (typeName->endsWith('*')) {
370 *isPointer = true;
371 typeName->truncate(typeName->length() - 1);
372 removePointerAndList(typeName, isList, isPointer);
373 } else if (typeName->startsWith(declListPrefix)) {
374 *isList = true;
375 typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
376 *typeName = typeName->mid(declListPrefix.size());
377 removePointerAndList(typeName, isList, isPointer);
378 }
379
380 *typeName = convertToId(*typeName);
381 }
382
383 void writeTypeProperties(QByteArray typeName, bool isWritable)
384 {
385 bool isList = false, isPointer = false;
386 removePointerAndList(&typeName, &isList, &isPointer);
387
388 qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
389 if (isList)
390 qml->writeScriptBinding(QLatin1String("isList"), QLatin1String("true"));
391 if (!isWritable)
392 qml->writeScriptBinding(QLatin1String("isReadonly"), QLatin1String("true"));
393 if (isPointer)
394 qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
395 }
396
397 void dump(const QMetaProperty &prop)
398 {
399 qml->writeStartObject("Property");
400
401 qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
402#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
403 if (int revision = prop.revision())
404 qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
405#endif
406 writeTypeProperties(prop.typeName(), prop.isWritable());
407
408 qml->writeEndObject();
409 }
410
411 void dump(const QMetaMethod &meth)
412 {
413 if (meth.methodType() == QMetaMethod::Signal) {
414 if (meth.access() != QMetaMethod::Protected)
415 return; // nothing to do.
416 } else if (meth.access() != QMetaMethod::Public) {
417 return; // nothing to do.
418 }
419
420 QByteArray name = meth.signature();
421 int lparenIndex = name.indexOf('(');
422 if (lparenIndex == -1) {
423 return; // invalid signature
424 }
425 name = name.left(lparenIndex);
426
427 if (meth.methodType() == QMetaMethod::Signal)
428 qml->writeStartObject(QLatin1String("Signal"));
429 else
430 qml->writeStartObject(QLatin1String("Method"));
431
432 qml->writeScriptBinding(QLatin1String("name"), enquote(name));
433
434#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
435 if (int revision = meth.revision())
436 qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
437#endif
438
439 const QString typeName = convertToId(meth.typeName());
440 if (! typeName.isEmpty())
441 qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
442
443 for (int i = 0; i < meth.parameterTypes().size(); ++i) {
444 QByteArray argName = meth.parameterNames().at(i);
445
446 qml->writeStartObject(QLatin1String("Parameter"));
447 if (! argName.isEmpty())
448 qml->writeScriptBinding(QLatin1String("name"), enquote(argName));
449 writeTypeProperties(meth.parameterTypes().at(i), true);
450 qml->writeEndObject();
451 }
452
453 qml->writeEndObject();
454 }
455
456 void dump(const QMetaEnum &e)
457 {
458 qml->writeStartObject(QLatin1String("Enum"));
459 qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name())));
460
461 QList<QPair<QString, QString> > namesValues;
462 for (int index = 0; index < e.keyCount(); ++index) {
463 namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index))));
464 }
465
466 qml->writeScriptObjectLiteralBinding(QLatin1String("values"), namesValues);
467 qml->writeEndObject();
468 }
469};
470
471
472enum ExitCode {
473 EXIT_INVALIDARGUMENTS = 1,
474 EXIT_SEGV = 2,
475 EXIT_IMPORTERROR = 3
476};
477
478#ifdef Q_OS_UNIX
479void sigSegvHandler(int) {
480 fprintf(stderr, "Error: SEGV\n");
481 if (!currentProperty.isEmpty())
482 fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData());
483 if (!inObjectInstantiation.isEmpty())
484 fprintf(stderr, "While instantiating the object '%s'.\n", inObjectInstantiation.toLatin1().constData());
485 exit(EXIT_SEGV);
486}
487#endif
488
489void printUsage(const QString &appName)
490{
491 qWarning() << qPrintable(QString(
492 "Usage: %1 [-v] [-noinstantiate] [-[non]relocatable] module.uri version [module/import/path]\n"
493 " %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
494 " %1 [-v] -builtins\n"
495 "Example: %1 Qt.labs.particles 4.7 /home/user/dev/qt-install/imports").arg(
496 appName));
497}
498
499int main(int argc, char *argv[])
500{
501#ifdef Q_OS_WIN
502 // we do not want windows popping up if the module loaded triggers an assert
503 SetErrorMode(SEM_NOGPFAULTERRORBOX);
504 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
505 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
506 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
507#endif
508#ifdef Q_OS_UNIX
509 // qmldump may crash, but we don't want any crash handlers to pop up
510 // therefore we intercept the segfault and just exit() ourselves
511 struct sigaction sigAction;
512
513 sigemptyset(&sigAction.sa_mask);
514 sigAction.sa_handler = &sigSegvHandler;
515 sigAction.sa_flags = 0;
516
517 sigaction(SIGSEGV, &sigAction, 0);
518#endif
519
520#ifdef QT_SIMULATOR
521 // Running this application would bring up the Qt Simulator (since it links QtGui), avoid that!
522 QtSimulatorPrivate::SimulatorConnection::createStubInstance();
523#endif
524 QApplication app(argc, argv);
525 const QStringList args = app.arguments();
526 const QString appName = QFileInfo(app.applicationFilePath()).baseName();
527 if (args.size() < 2) {
528 printUsage(appName);
529 return EXIT_INVALIDARGUMENTS;
530 }
531
532 QString pluginImportUri;
533 QString pluginImportVersion;
534 bool relocatable = true;
535 enum Action { Uri, Path, Builtins };
536 Action action = Uri;
537 {
538 QStringList positionalArgs;
539 foreach (const QString &arg, args) {
540 if (!arg.startsWith(QLatin1Char('-'))) {
541 positionalArgs.append(arg);
542 continue;
543 }
544
545 if (arg == QLatin1String("--notrelocatable")
546 || arg == QLatin1String("-notrelocatable")
547 || arg == QLatin1String("--nonrelocatable")
548 || arg == QLatin1String("-nonrelocatable")) {
549 relocatable = false;
550 } else if (arg == QLatin1String("--relocatable")
551 || arg == QLatin1String("-relocatable")) {
552 relocatable = true;
553 } else if (arg == QLatin1String("--path")
554 || arg == QLatin1String("-path")) {
555 action = Path;
556 } else if (arg == QLatin1String("--builtins")
557 || arg == QLatin1String("-builtins")) {
558 action = Builtins;
559 } else if (arg == QLatin1String("-v")) {
560 verbose = true;
561 } else if (arg == QLatin1String("--noinstantiate")
562 || arg == QLatin1String("-noinstantiate")) {
563 creatable = false;
564 } else {
565 qWarning() << "Invalid argument: " << arg;
566 return EXIT_INVALIDARGUMENTS;
567 }
568 }
569
570 if (action == Uri) {
571 if (positionalArgs.size() != 3 && positionalArgs.size() != 4) {
572 qWarning() << "Incorrect number of positional arguments";
573 return EXIT_INVALIDARGUMENTS;
574 }
575 pluginImportUri = positionalArgs[1];
576 pluginImportVersion = positionalArgs[2];
577 if (positionalArgs.size() >= 4)
578 pluginImportPath = positionalArgs[3];
579 } else if (action == Path) {
580 if (positionalArgs.size() != 2 && positionalArgs.size() != 3) {
581 qWarning() << "Incorrect number of positional arguments";
582 return EXIT_INVALIDARGUMENTS;
583 }
584 pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]);
585 if (positionalArgs.size() == 3)
586 pluginImportVersion = positionalArgs[2];
587 } else if (action == Builtins) {
588 if (positionalArgs.size() != 1) {
589 qWarning() << "Incorrect number of positional arguments";
590 return EXIT_INVALIDARGUMENTS;
591 }
592 }
593 }
594
595 QDeclarativeView view;
596 QDeclarativeEngine *engine = view.engine();
597 if (!pluginImportPath.isEmpty()) {
598 QDir cur = QDir::current();
599 cur.cd(pluginImportPath);
600 pluginImportPath = cur.absolutePath();
601 QDir::setCurrent(pluginImportPath);
602 engine->addImportPath(pluginImportPath);
603 }
604
605 // find all QMetaObjects reachable from the builtin module
606 QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects();
607 QList<QDeclarativeType *> defaultTypes = QDeclarativeMetaType::qmlTypes();
608
609 // this will hold the meta objects we want to dump information of
610 QSet<const QMetaObject *> metas;
611
612 if (action == Builtins) {
613 metas = defaultReachable;
614 } else {
615 // find a valid QtQuick import
616 QByteArray importCode;
617 QDeclarativeType *qtObjectType = QDeclarativeMetaType::qmlType(&QObject::staticMetaObject);
618 if (!qtObjectType) {
619 qWarning() << "Could not find QtObject type";
620 importCode = QByteArray("import QtQuick 1.0\n");
621 } else {
622 QByteArray module = qtObjectType->qmlTypeName();
623 module = module.mid(0, module.lastIndexOf('/'));
624 importCode = QString("import %1 %2.%3\n").arg(module,
625 QString::number(qtObjectType->majorVersion()),
626 QString::number(qtObjectType->minorVersion())).toUtf8();
627 }
628
629 // find all QMetaObjects reachable when the specified module is imported
630 if (action != Path) {
631 importCode += QString("import %0 %1\n").arg(pluginImportUri, pluginImportVersion).toAscii();
632 } else {
633 // pluginImportVersion can be empty
634 importCode += QString("import \".\" %2\n").arg(pluginImportVersion).toAscii();
635 }
636
637 // create a component with these imports to make sure the imports are valid
638 // and to populate the declarative meta type system
639 {
640 QByteArray code = importCode;
641 code += "QtObject {}";
642 QDeclarativeComponent c(engine);
643
644 c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/typelist.qml"));
645 c.create();
646 if (!c.errors().isEmpty()) {
647 foreach (const QDeclarativeError &error, c.errors())
648 qWarning() << error.toString();
649 return EXIT_IMPORTERROR;
650 }
651 }
652
653 QSet<const QMetaObject *> candidates = collectReachableMetaObjects(defaultTypes);
654 candidates.subtract(defaultReachable);
655
656 // Also eliminate meta objects with the same classname.
657 // This is required because extended objects seem not to share
658 // a single meta object instance.
659 QSet<QByteArray> defaultReachableNames;
660 foreach (const QMetaObject *mo, defaultReachable)
661 defaultReachableNames.insert(QByteArray(mo->className()));
662 foreach (const QMetaObject *mo, candidates) {
663 if (!defaultReachableNames.contains(mo->className()))
664 metas.insert(mo);
665 }
666 }
667
668 // setup static rewrites of type names
669 cppToId.insert("QString", "string");
670 cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
671
672 // start dumping data
673 QByteArray bytes;
674 QmlStreamWriter qml(&bytes);
675
676 qml.writeStartDocument();
677 qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 1);
678 qml.write("\n"
679 "// This file describes the plugin-supplied types contained in the library.\n"
680 "// It is used for QML tooling purposes only.\n"
681 "\n");
682 qml.writeStartObject("Module");
683
684 // put the metaobjects into a map so they are always dumped in the same order
685 QMap<QString, const QMetaObject *> nameToMeta;
686 foreach (const QMetaObject *meta, metas)
687 nameToMeta.insert(convertToId(meta), meta);
688
689 Dumper dumper(&qml);
690 if (relocatable)
691 dumper.setRelocatableModuleUri(pluginImportUri);
692 foreach (const QMetaObject *meta, nameToMeta) {
693 dumper.dump(meta);
694 }
695
696 // define QEasingCurve as an extension of QDeclarativeEasingValueType, this way
697 // properties using the QEasingCurve type get useful type information.
698 if (pluginImportUri.isEmpty())
699 dumper.writeEasingCurve();
700
701 qml.writeEndObject();
702 qml.writeEndDocument();
703
704 std::cout << bytes.constData() << std::flush;
705
706 // workaround to avoid crashes on exit
707 QTimer timer;
708 timer.setSingleShot(true);
709 timer.setInterval(0);
710 QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
711 timer.start();
712
713 return app.exec();
714}
715

Warning: That file was not part of the compilation database. It may have many parsing errors.