1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "fakemetaobject.h"
27 #include <QCryptographicHash>
28 
29 using namespace LanguageUtils;
30 
FakeMetaEnum()31 FakeMetaEnum::FakeMetaEnum()
32 {}
33 
FakeMetaEnum(const QString & name)34 FakeMetaEnum::FakeMetaEnum(const QString &name)
35     : m_name(name)
36 {}
37 
isValid() const38 bool FakeMetaEnum::isValid() const
39 { return !m_name.isEmpty(); }
40 
name() const41 QString FakeMetaEnum::name() const
42 { return m_name; }
43 
setName(const QString & name)44 void FakeMetaEnum::setName(const QString &name)
45 { m_name = name; }
46 
addKey(const QString & key,int value)47 void FakeMetaEnum::addKey(const QString &key, int value)
48 { m_keys.append(key); m_values.append(value); }
49 
key(int index) const50 QString FakeMetaEnum::key(int index) const
51 { return m_keys.at(index); }
52 
keyCount() const53 int FakeMetaEnum::keyCount() const
54 { return m_keys.size(); }
55 
keys() const56 QStringList FakeMetaEnum::keys() const
57 { return m_keys; }
58 
hasKey(const QString & key) const59 bool FakeMetaEnum::hasKey(const QString &key) const
60 { return m_keys.contains(key); }
61 
addToHash(QCryptographicHash & hash) const62 void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
63 {
64     int len = m_name.size();
65     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
66     hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
67     len = m_keys.size();
68     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
69     foreach (const QString &key, m_keys) {
70         len = key.size();
71         hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
72         hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
73     }
74     len = m_values.size();
75     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
76     foreach (int value, m_values)
77         hash.addData(reinterpret_cast<const char *>(&value), sizeof(value));
78 }
79 
describe(int baseIndent) const80 QString FakeMetaEnum::describe(int baseIndent) const
81 {
82     QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
83     QString res = QLatin1String("Enum ");
84     res += name();
85     res += QLatin1String(":{");
86     for (int i = 0; i < keyCount(); ++i) {
87         res += newLine;
88         res += QLatin1String("  ");
89         res += key(i);
90         res += QLatin1String(": ");
91         res += QString::number(m_values.value(i, -1));
92     }
93     res += newLine;
94     res += QLatin1Char('}');
95     return res;
96 }
97 
toString() const98 QString FakeMetaEnum::toString() const
99 {
100     return describe();
101 }
102 
FakeMetaMethod(const QString & name,const QString & returnType)103 FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
104     : m_name(name)
105     , m_returnType(returnType)
106     , m_methodTy(FakeMetaMethod::Method)
107     , m_methodAccess(FakeMetaMethod::Public)
108     , m_revision(0)
109 {}
110 
FakeMetaMethod()111 FakeMetaMethod::FakeMetaMethod()
112     : m_methodTy(FakeMetaMethod::Method)
113     , m_methodAccess(FakeMetaMethod::Public)
114     , m_revision(0)
115 {}
116 
methodName() const117 QString FakeMetaMethod::methodName() const
118 { return m_name; }
119 
setMethodName(const QString & name)120 void FakeMetaMethod::setMethodName(const QString &name)
121 { m_name = name; }
122 
setReturnType(const QString & type)123 void FakeMetaMethod::setReturnType(const QString &type)
124 { m_returnType = type; }
125 
parameterNames() const126 QStringList FakeMetaMethod::parameterNames() const
127 { return m_paramNames; }
128 
parameterTypes() const129 QStringList FakeMetaMethod::parameterTypes() const
130 { return m_paramTypes; }
131 
addParameter(const QString & name,const QString & type)132 void FakeMetaMethod::addParameter(const QString &name, const QString &type)
133 { m_paramNames.append(name); m_paramTypes.append(type); }
134 
methodType() const135 int FakeMetaMethod::methodType() const
136 { return m_methodTy; }
137 
setMethodType(int methodType)138 void FakeMetaMethod::setMethodType(int methodType)
139 { m_methodTy = methodType; }
140 
access() const141 int FakeMetaMethod::access() const
142 { return m_methodAccess; }
143 
revision() const144 int FakeMetaMethod::revision() const
145 { return m_revision; }
146 
setRevision(int r)147 void FakeMetaMethod::setRevision(int r)
148 { m_revision = r; }
149 
addToHash(QCryptographicHash & hash) const150 void FakeMetaMethod::addToHash(QCryptographicHash &hash) const
151 {
152     int len = m_name.size();
153     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
154     hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
155     hash.addData(reinterpret_cast<const char *>(&m_methodAccess), sizeof(m_methodAccess));
156     hash.addData(reinterpret_cast<const char *>(&m_methodTy), sizeof(m_methodTy));
157     hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
158     len = m_paramNames.size();
159     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
160     foreach (const QString &pName, m_paramNames) {
161         len = pName.size();
162         hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
163         hash.addData(reinterpret_cast<const char *>(pName.constData()), len * sizeof(QChar));
164     }
165     len = m_paramTypes.size();
166     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
167     foreach (const QString &pType, m_paramTypes) {
168         len = pType.size();
169         hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
170         hash.addData(reinterpret_cast<const char *>(pType.constData()), len * sizeof(QChar));
171     }
172     len = m_returnType.size();
173     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
174     hash.addData(reinterpret_cast<const char *>(m_returnType.constData()), len * sizeof(QChar));
175 }
176 
describe(int baseIndent) const177 QString FakeMetaMethod::describe(int baseIndent) const
178 {
179     QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
180     QString res = QLatin1String("Method {");
181     res += newLine;
182     res += QLatin1String("  methodName:");
183     res += methodName();
184     res += newLine;
185     res += QLatin1String("  methodType:");
186     res += methodType();
187     res += newLine;
188     res += QLatin1String("  parameterNames:[");
189     foreach (const QString &pName, parameterNames()) {
190         res += newLine;
191         res += QLatin1String("    ");
192         res += pName;
193     }
194     res += QLatin1Char(']');
195     res += newLine;
196     res += QLatin1String("  parameterTypes:[");
197     foreach (const QString &pType, parameterTypes()) {
198         res += newLine;
199         res += QLatin1String("    ");
200         res += pType;
201     }
202     res += QLatin1Char(']');
203     res += newLine;
204     res += QLatin1Char('}');
205     return res;
206 }
207 
toString() const208 QString FakeMetaMethod::toString() const
209 {
210     return describe();
211 }
212 
213 
FakeMetaProperty(const QString & name,const QString & type,bool isList,bool isWritable,bool isPointer,int revision)214 FakeMetaProperty::FakeMetaProperty(const QString &name, const QString &type, bool isList,
215                                    bool isWritable, bool isPointer, int revision)
216     : m_propertyName(name)
217     , m_type(type)
218     , m_isList(isList)
219     , m_isWritable(isWritable)
220     , m_isPointer(isPointer)
221     , m_revision(revision)
222 {}
223 
name() const224 QString FakeMetaProperty::name() const
225 { return m_propertyName; }
226 
typeName() const227 QString FakeMetaProperty::typeName() const
228 { return m_type; }
229 
isList() const230 bool FakeMetaProperty::isList() const
231 { return m_isList; }
232 
isWritable() const233 bool FakeMetaProperty::isWritable() const
234 { return m_isWritable; }
235 
isPointer() const236 bool FakeMetaProperty::isPointer() const
237 { return m_isPointer; }
238 
revision() const239 int FakeMetaProperty::revision() const
240 { return m_revision; }
241 
addToHash(QCryptographicHash & hash) const242 void FakeMetaProperty::addToHash(QCryptographicHash &hash) const
243 {
244     int len = m_propertyName.size();
245     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
246     hash.addData(reinterpret_cast<const char *>(m_propertyName.constData()), len * sizeof(QChar));
247     hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
248     int flags = (m_isList ? (1 << 0) : 0)
249             + (m_isPointer ? (1 << 1) : 0)
250             + (m_isWritable ? (1 << 2) : 0);
251     hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
252     len = m_type.size();
253     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
254     hash.addData(reinterpret_cast<const char *>(m_type.constData()), len * sizeof(QChar));
255 }
256 
describe(int baseIndent) const257 QString FakeMetaProperty::describe(int baseIndent) const
258 {
259     auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
260     QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
261     QString res = QLatin1String("Property  {");
262     res += newLine;
263     res += QLatin1String("  name:");
264     res += name();
265     res += newLine;
266     res += QLatin1String("  typeName:");
267     res += typeName();
268     res += newLine;
269     res += QLatin1String("  typeName:");
270     res += QString::number(revision());
271     res += newLine;
272     res += QLatin1String("  isList:");
273     res += boolStr(isList());
274     res += newLine;
275     res += QLatin1String("  isPointer:");
276     res += boolStr(isPointer());
277     res += newLine;
278     res += QLatin1String("  isWritable:");
279     res += boolStr(isWritable());
280     res += newLine;
281     res += QLatin1Char('}');
282     return res;
283 }
284 
toString() const285 QString FakeMetaProperty::toString() const
286 {
287     return describe();
288 }
289 
290 
FakeMetaObject()291 FakeMetaObject::FakeMetaObject() : m_isSingleton(false), m_isCreatable(true), m_isComposite(false)
292 {
293 }
294 
className() const295 QString FakeMetaObject::className() const
296 { return m_className; }
setClassName(const QString & name)297 void FakeMetaObject::setClassName(const QString &name)
298 { m_className = name; }
299 
addExport(const QString & name,const QString & package,ComponentVersion version)300 void FakeMetaObject::addExport(const QString &name, const QString &package, ComponentVersion version)
301 {
302     Export exp;
303     exp.type = name;
304     exp.package = package;
305     exp.version = version;
306     m_exports.append(exp);
307 }
308 
setExportMetaObjectRevision(int exportIndex,int metaObjectRevision)309 void FakeMetaObject::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
310 {
311     m_exports[exportIndex].metaObjectRevision = metaObjectRevision;
312 }
313 
exports() const314 QList<FakeMetaObject::Export> FakeMetaObject::exports() const
315 { return m_exports; }
exportInPackage(const QString & package) const316 FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
317 {
318     foreach (const Export &exp, m_exports) {
319         if (exp.package == package)
320             return exp;
321     }
322     return Export();
323 }
324 
setSuperclassName(const QString & superclass)325 void FakeMetaObject::setSuperclassName(const QString &superclass)
326 { m_superName = superclass; }
superclassName() const327 QString FakeMetaObject::superclassName() const
328 { return m_superName; }
329 
addEnum(const FakeMetaEnum & fakeEnum)330 void FakeMetaObject::addEnum(const FakeMetaEnum &fakeEnum)
331 { m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
enumeratorCount() const332 int FakeMetaObject::enumeratorCount() const
333 { return m_enums.size(); }
enumeratorOffset() const334 int FakeMetaObject::enumeratorOffset() const
335 { return 0; }
enumerator(int index) const336 FakeMetaEnum FakeMetaObject::enumerator(int index) const
337 { return m_enums.at(index); }
enumeratorIndex(const QString & name) const338 int FakeMetaObject::enumeratorIndex(const QString &name) const
339 { return m_enumNameToIndex.value(name, -1); }
340 
addProperty(const FakeMetaProperty & property)341 void FakeMetaObject::addProperty(const FakeMetaProperty &property)
342 { m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); }
propertyCount() const343 int FakeMetaObject::propertyCount() const
344 { return m_props.size(); }
propertyOffset() const345 int FakeMetaObject::propertyOffset() const
346 { return 0; }
property(int index) const347 FakeMetaProperty FakeMetaObject::property(int index) const
348 { return m_props.at(index); }
propertyIndex(const QString & name) const349 int FakeMetaObject::propertyIndex(const QString &name) const
350 { return m_propNameToIdx.value(name, -1); }
351 
addMethod(const FakeMetaMethod & method)352 void FakeMetaObject::addMethod(const FakeMetaMethod &method)
353 { m_methods.append(method); }
methodCount() const354 int FakeMetaObject::methodCount() const
355 { return m_methods.size(); }
methodOffset() const356 int FakeMetaObject::methodOffset() const
357 { return 0; }
method(int index) const358 FakeMetaMethod FakeMetaObject::method(int index) const
359 { return m_methods.at(index); }
methodIndex(const QString & name) const360 int FakeMetaObject::methodIndex(const QString &name) const //If performances becomes an issue, just use a nameToIdx hash
361 {
362     for (int i=0; i<m_methods.count(); i++)
363         if (m_methods[i].methodName() == name)
364             return i;
365     return -1;
366 }
367 
defaultPropertyName() const368 QString FakeMetaObject::defaultPropertyName() const
369 { return m_defaultPropertyName; }
setDefaultPropertyName(const QString & defaultPropertyName)370 void FakeMetaObject::setDefaultPropertyName(const QString &defaultPropertyName)
371 { m_defaultPropertyName = defaultPropertyName; }
372 
attachedTypeName() const373 QString FakeMetaObject::attachedTypeName() const
374 { return m_attachedTypeName; }
setAttachedTypeName(const QString & name)375 void FakeMetaObject::setAttachedTypeName(const QString &name)
376 { m_attachedTypeName = name; }
377 
calculateFingerprint() const378 QByteArray FakeMetaObject::calculateFingerprint() const
379 {
380     QCryptographicHash hash(QCryptographicHash::Sha1);
381     int len = m_className.size();
382     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
383     hash.addData(reinterpret_cast<const char *>(m_className.constData()), len * sizeof(QChar));
384     len = m_attachedTypeName.size();
385     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
386     hash.addData(reinterpret_cast<const char *>(m_attachedTypeName.constData()), len * sizeof(QChar));
387     len = m_defaultPropertyName.size();
388     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
389     hash.addData(reinterpret_cast<const char *>(m_defaultPropertyName.constData()), len * sizeof(QChar));
390     len = m_enumNameToIndex.size();
391     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
392     {
393         QStringList keys(m_enumNameToIndex.keys());
394         keys.sort();
395         foreach (const QString &key, keys) {
396             len = key.size();
397             hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
398             hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
399             int value = m_enumNameToIndex.value(key);
400             hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
401             m_enums.at(value).addToHash(hash);
402         }
403     }
404     len = m_exports.size();
405     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
406     foreach (const Export &e, m_exports)
407         e.addToHash(hash); // normalize order?
408     len = m_exports.size();
409     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
410     foreach (const FakeMetaMethod &m, m_methods)
411         m.addToHash(hash); // normalize order?
412     {
413         QStringList keys(m_propNameToIdx.keys());
414         keys.sort();
415         foreach (const QString &key, keys) {
416             len = key.size();
417             hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
418             hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
419             int value = m_propNameToIdx.value(key);
420             hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
421             m_props.at(value).addToHash(hash);
422         }
423     }
424     len = m_superName.size();
425     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
426     hash.addData(reinterpret_cast<const char *>(m_superName.constData()), len * sizeof(QChar));
427 
428     QByteArray res = hash.result();
429     res.append('F');
430     return res;
431 }
432 
updateFingerprint()433 void FakeMetaObject::updateFingerprint()
434 {
435     m_fingerprint = calculateFingerprint();
436 }
437 
fingerprint() const438 QByteArray FakeMetaObject::fingerprint() const
439 {
440     return m_fingerprint;
441 }
442 
isSingleton() const443 bool FakeMetaObject::isSingleton() const
444 {
445     return m_isSingleton;
446 }
447 
isCreatable() const448 bool FakeMetaObject::isCreatable() const
449 {
450     return m_isCreatable;
451 }
452 
isComposite() const453 bool FakeMetaObject::isComposite() const
454 {
455     return m_isComposite;
456 }
457 
setIsSingleton(bool value)458 void FakeMetaObject::setIsSingleton(bool value)
459 {
460     m_isSingleton = value;
461 }
462 
setIsCreatable(bool value)463 void FakeMetaObject::setIsCreatable(bool value)
464 {
465     m_isCreatable = value;
466 }
467 
setIsComposite(bool value)468 void FakeMetaObject::setIsComposite(bool value)
469 {
470     m_isSingleton = value;
471 }
472 
toString() const473 QString FakeMetaObject::toString() const
474 {
475     return describe();
476 }
477 
describe(bool printDetails,int baseIndent) const478 QString FakeMetaObject::describe(bool printDetails, int baseIndent) const
479 {
480     QString res = QString::fromLatin1("FakeMetaObject@%1")
481          .arg((quintptr)(void *)this, 0, 16);
482     if (!printDetails)
483         return res;
484     auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
485     QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
486     res += QLatin1Char('{');
487     res += newLine;
488     res += QLatin1String("className:");
489     res += className();
490     res += newLine;
491     res += QLatin1String("superClassName:");
492     res += superclassName();
493     res += newLine;
494     res += QLatin1String("isSingleton:");
495     res += boolStr(isSingleton());
496     res += newLine;
497     res += QLatin1String("isCreatable:");
498     res += boolStr(isCreatable());
499     res += newLine;
500     res += QLatin1String("isComposite:");
501     res += boolStr(isComposite());
502     res += newLine;
503     res += QLatin1String("defaultPropertyName:");
504     res += defaultPropertyName();
505     res += newLine;
506     res += QLatin1String("attachedTypeName:");
507     res += attachedTypeName();
508     res += newLine;
509     res += QLatin1String("fingerprint:");
510     res += QString::fromUtf8(fingerprint());
511 
512     res += newLine;
513     res += QLatin1String("exports:[");
514     foreach (const Export &e, exports()) {
515         res += newLine;
516         res += QLatin1String("  ");
517         res += e.describe(baseIndent + 2);
518     }
519     res += QLatin1Char(']');
520 
521     res += newLine;
522     res += QLatin1String("enums:[");
523     for (int iEnum = 0; iEnum < enumeratorCount() ; ++ iEnum) {
524         FakeMetaEnum e = enumerator(enumeratorOffset() + iEnum);
525         res += newLine;
526         res += QLatin1String("  ");
527         res += e.describe(baseIndent + 2);
528     }
529     res += QLatin1Char(']');
530 
531     res += newLine;
532     res += QLatin1String("properties:[");
533     for (int iProp = 0; iProp < propertyCount() ; ++ iProp) {
534         FakeMetaProperty prop = property(propertyOffset() + iProp);
535         res += newLine;
536         res += QLatin1String("  ");
537         res += prop.describe(baseIndent + 2);
538     }
539     res += QLatin1Char(']');
540     res += QLatin1String("methods:[");
541     for (int iMethod = 0; iMethod < methodOffset() ; ++ iMethod) {
542         FakeMetaMethod m = method(methodOffset() + iMethod);
543         res += newLine;
544         res += QLatin1String("  ");
545         m.describe(baseIndent + 2);
546     }
547     res += QLatin1Char(']');
548     res += newLine;
549     res += QLatin1Char('}');
550     return res;
551 }
552 
Export()553 FakeMetaObject::Export::Export()
554     : metaObjectRevision(0)
555 {}
isValid() const556 bool FakeMetaObject::Export::isValid() const
557 { return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
558 
addToHash(QCryptographicHash & hash) const559 void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const
560 {
561     int len = package.size();
562     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
563     hash.addData(reinterpret_cast<const char *>(package.constData()), len * sizeof(QChar));
564     len = type.size();
565     hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
566     hash.addData(reinterpret_cast<const char *>(type.constData()), len * sizeof(QChar));
567     version.addToHash(hash);
568     hash.addData(reinterpret_cast<const char *>(&metaObjectRevision), sizeof(metaObjectRevision));
569 }
570 
describe(int baseIndent) const571 QString FakeMetaObject::Export::describe(int baseIndent) const
572 {
573     QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
574     QString res = QLatin1String("Export {");
575     res += newLine;
576     res += QLatin1String("  package:");
577     res += package;
578     res += newLine;
579     res += QLatin1String("  type:");
580     res += type;
581     res += newLine;
582     res += QLatin1String("  version:");
583     res += version.toString();
584     res += newLine;
585     res += QLatin1String("  metaObjectRevision:");
586     res += QString::number(metaObjectRevision);
587     res += newLine;
588     res += QLatin1String("  isValid:");
589     res += QString::number(isValid());
590     res += newLine;
591     res += QLatin1Char('}');
592     return res;
593 }
594 
toString() const595 QString FakeMetaObject::Export::toString() const
596 {
597     return describe();
598 }
599