Lazily create QMetaObjects
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlpropertycache_p.h"
43
44 #include "qqmlengine_p.h"
45 #include "qqmlbinding_p.h"
46 #include <private/qv8engine_p.h>
47
48 #include <private/qmetaobject_p.h>
49 #include <private/qqmlaccessors_p.h>
50 #include <private/qmetaobjectbuilder_p.h>
51
52 #include <QtCore/qdebug.h>
53
54 #include <ctype.h> // for toupper
55
56 #ifdef Q_CC_MSVC
57 // nonstandard extension used : zero-sized array in struct/union.
58 #  pragma warning( disable : 4200 )
59 #endif
60
61 Q_DECLARE_METATYPE(QJSValue)
62 Q_DECLARE_METATYPE(QQmlV8Handle);
63
64 QT_BEGIN_NAMESPACE
65
66 #define Q_INT16_MAX 32767
67
68 class QQmlPropertyCacheMethodArguments 
69 {
70 public:
71     QQmlPropertyCacheMethodArguments *next;
72
73     QList<QByteArray> *names;
74     int arguments[0];
75 };
76
77 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
78 // to load
79 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
80 {
81     QQmlPropertyData::Flags flags;
82
83     if (p.isConstant())
84         flags |= QQmlPropertyData::IsConstant;
85     if (p.isWritable())
86         flags |= QQmlPropertyData::IsWritable;
87     if (p.isResettable())
88         flags |= QQmlPropertyData::IsResettable;
89     if (p.isFinal())
90         flags |= QQmlPropertyData::IsFinal;
91     if (p.isEnumType())
92         flags |= QQmlPropertyData::IsEnumType;
93
94     return flags;
95 }
96
97 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
98 // load
99 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
100 {
101     Q_ASSERT(propType != -1);
102
103     QQmlPropertyData::Flags flags;
104
105     if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
106         flags |= QQmlPropertyData::IsQObjectDerived;
107     } else if (propType == QMetaType::QVariant) {
108         flags |= QQmlPropertyData::IsQVariant;
109     } else if (propType < (int)QVariant::UserType) {
110     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
111         flags |= QQmlPropertyData::IsQmlBinding;
112     } else if (propType == qMetaTypeId<QJSValue>()) {
113         flags |= QQmlPropertyData::IsQJSValue;
114     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
115         flags |= QQmlPropertyData::IsV8Handle;
116     } else {
117         QQmlMetaType::TypeCategory cat = 
118             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
119                    : QQmlMetaType::typeCategory(propType);
120
121         if (cat == QQmlMetaType::Object)
122             flags |= QQmlPropertyData::IsQObjectDerived;
123         else if (cat == QQmlMetaType::List)
124             flags |= QQmlPropertyData::IsQList;
125     }
126
127     return flags;
128 }
129
130 static int metaObjectSignalCount(const QMetaObject *metaObject)
131 {
132     int signalCount = 0;
133     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
134         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
135     return signalCount;
136 }
137
138 QQmlPropertyData::Flags
139 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
140 {
141     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
142 }
143
144 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
145 {
146     Q_UNUSED(engine);
147
148     coreIndex = p.propertyIndex();
149     notifyIndex = p.notifySignalIndex();
150     Q_ASSERT(p.revision() <= Q_INT16_MAX);
151     revision = p.revision();
152
153     flags = fastFlagsForProperty(p);
154
155     int type = p.type();
156     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
157         propType = type;
158         flags |= QQmlPropertyData::IsQObjectDerived;
159     } else if (type == QMetaType::QVariant) {
160         propType = type;
161         flags |= QQmlPropertyData::IsQVariant;
162     } else if (type == QVariant::UserType || type == -1) {
163         propTypeName = p.typeName();
164         flags |= QQmlPropertyData::NotFullyResolved;
165     } else {
166         propType = type;
167     }
168 }
169
170 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
171 {
172     propType = p.userType();
173     coreIndex = p.propertyIndex();
174     notifyIndex = p.notifySignalIndex();
175     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
176     Q_ASSERT(p.revision() <= Q_INT16_MAX);
177     revision = p.revision();
178 }
179
180 void QQmlPropertyData::load(const QMetaMethod &m)
181 {
182     coreIndex = m.methodIndex();
183     arguments = 0;
184     flags |= IsFunction;
185     if (m.methodType() == QMetaMethod::Signal)
186         flags |= IsSignal;
187     propType = m.returnType();
188
189     if (m.parameterCount()) {
190         flags |= HasArguments;
191         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
192             flags |= IsV8Function;
193         }
194     }
195
196     if (m.attributes() & QMetaMethod::Cloned)
197         flags |= IsCloned;
198
199     Q_ASSERT(m.revision() <= Q_INT16_MAX);
200     revision = m.revision();
201 }
202
203 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
204 {
205     coreIndex = m.methodIndex();
206     arguments = 0;
207     flags |= IsFunction;
208     if (m.methodType() == QMetaMethod::Signal)
209         flags |= IsSignal;
210     propType = QMetaType::Void;
211
212     const char *returnType = m.typeName();
213     Q_ASSERT(returnType != 0);
214     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
215         propTypeName = returnType;
216         flags |= NotFullyResolved;
217     }
218
219     if (m.parameterCount()) {
220         flags |= HasArguments;
221         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
222             flags |= IsV8Function;
223         }
224     }
225
226     if (m.attributes() & QMetaMethod::Cloned)
227         flags |= IsCloned;
228
229     Q_ASSERT(m.revision() <= Q_INT16_MAX);
230     revision = m.revision();
231 }
232
233 /*!
234 Creates a new empty QQmlPropertyCache.
235 */
236 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
237 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
238   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
239 {
240     Q_ASSERT(engine);
241 }
242
243 /*!
244 Creates a new QQmlPropertyCache of \a metaObject.
245 */
246 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
247 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
248   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
249 {
250     Q_ASSERT(engine);
251     Q_ASSERT(metaObject);
252
253     update(engine, metaObject);
254 }
255
256 QQmlPropertyCache::~QQmlPropertyCache()
257 {
258     clear();
259
260     QQmlPropertyCacheMethodArguments *args = argumentsCache;
261     while (args) {
262         QQmlPropertyCacheMethodArguments *next = args->next;
263         if (args->names) delete args->names;
264         free(args);
265         args = next;
266     }
267
268     // We must clear this prior to releasing the parent incase it is a
269     // linked hash
270     stringCache.clear();
271     if (_parent) _parent->release();
272
273     if (_ownMetaObject) free((void *)_metaObject);
274     _metaObject = 0;
275     _parent = 0;
276     engine = 0;
277 }
278
279 void QQmlPropertyCache::destroy()
280 {
281     Q_ASSERT(engine || constructor.IsEmpty());
282     if (constructor.IsEmpty())
283         delete this;
284     else
285         QQmlEnginePrivate::deleteInEngineThread(engine, this);
286 }
287
288 // This is inherited from QQmlCleanup, so it should only clear the things
289 // that are tied to the specific QQmlEngine.
290 void QQmlPropertyCache::clear()
291 {
292     qPersistentDispose(constructor);
293     engine = 0;
294 }
295
296 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
297 {
298     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
299     cache->_parent = this;
300     cache->_parent->addref();
301     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
302     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
303     cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
304     cache->stringCache.linkAndReserve(stringCache, reserve);
305     cache->allowedRevisionCache = allowedRevisionCache;
306     cache->_metaObject = _metaObject;
307     cache->_defaultPropertyName = _defaultPropertyName;
308
309     // We specifically do *NOT* copy the constructor
310
311     return cache;
312 }
313
314 QQmlPropertyCache *QQmlPropertyCache::copy()
315 {
316     return copy(0);
317 }
318
319 QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
320                                                      int signalCount)
321 {
322     QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
323     rv->propertyIndexCache.reserve(propertyCount);
324     rv->methodIndexCache.reserve(methodCount);
325     rv->signalHandlerIndexCache.reserve(signalCount);
326     rv->_metaObject = 0;
327
328     return rv;
329 }
330
331 void QQmlPropertyCache::appendProperty(const QString &name,
332                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
333 {
334     QQmlPropertyData data;
335     data.propType = propType;
336     data.coreIndex = coreIndex;
337     data.notifyIndex = notifyIndex;
338     data.flags = flags;
339
340     QHashedString string(name);
341     if (QQmlPropertyData **old = stringCache.value(string)) {
342         data.overrideIndexIsProperty = !(*old)->isFunction();
343         data.overrideIndex = (*old)->coreIndex;
344     }
345
346     propertyIndexCache.append(data);
347
348     stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
349 }
350
351 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
352                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
353 {
354     QQmlPropertyData data;
355     data.propType = propType;
356     data.coreIndex = coreIndex;
357     data.notifyIndex = notifyIndex;
358     data.flags = flags;
359
360     if (QQmlPropertyData **old = stringCache.value(name)) {
361         data.overrideIndexIsProperty = !(*old)->isFunction();
362         data.overrideIndex = (*old)->coreIndex;
363     }
364
365     propertyIndexCache.append(data);
366
367     stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
368 }
369
370 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
371                                      const int *types, const QList<QByteArray> &names)
372 {
373     QQmlPropertyData data;
374     data.propType = QVariant::Invalid;
375     data.coreIndex = coreIndex;
376     data.flags = flags;
377     data.arguments = 0;
378
379     QQmlPropertyData handler = data;
380     handler.flags |= QQmlPropertyData::IsSignalHandler;
381
382     if (types) {
383         int argumentCount = *types;
384         typedef QQmlPropertyCacheMethodArguments A;
385         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
386         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
387         args->names = new QList<QByteArray>(names);
388         args->next = argumentsCache;
389         argumentsCache = args;
390         data.arguments = args;
391     }
392
393     QString handlerName = QLatin1String("on") + name;
394     handlerName[2] = handlerName[2].toUpper();
395
396     QHashedString string(name);
397     if (QQmlPropertyData **old = stringCache.value(string)) {
398         data.overrideIndexIsProperty = !(*old)->isFunction();
399         data.overrideIndex = (*old)->coreIndex;
400     }
401
402     methodIndexCache.append(data);
403     signalHandlerIndexCache.append(handler);
404
405     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
406     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
407 }
408
409 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
410                                      const int *types, const QList<QByteArray> &names)
411 {
412     QQmlPropertyData data;
413     data.propType = QVariant::Invalid;
414     data.coreIndex = coreIndex;
415     data.flags = flags;
416     data.arguments = 0;
417
418     QQmlPropertyData handler = data;
419     handler.flags |= QQmlPropertyData::IsSignalHandler;
420
421     if (types) {
422         int argumentCount = *types;
423         typedef QQmlPropertyCacheMethodArguments A;
424         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
425         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
426         args->names = new QList<QByteArray>(names);
427         args->next = argumentsCache;
428         argumentsCache = args;
429         data.arguments = args;
430     }
431
432     QString handlerName = QLatin1String("on") + name.toUtf16();
433     handlerName[2] = handlerName[2].toUpper();
434
435     if (QQmlPropertyData **old = stringCache.value(name)) {
436         data.overrideIndexIsProperty = !(*old)->isFunction();
437         data.overrideIndex = (*old)->coreIndex;
438     }
439
440     methodIndexCache.append(data);
441     signalHandlerIndexCache.append(handler);
442
443     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
444     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
445 }
446
447 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
448                                      const QList<QByteArray> &names)
449 {
450     int argumentCount = names.count();
451
452     QQmlPropertyData data;
453     data.propType = QMetaType::QVariant;
454     data.coreIndex = coreIndex;
455
456     typedef QQmlPropertyCacheMethodArguments A;
457     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
458     args->arguments[0] = argumentCount;
459     for (int ii = 0; ii < argumentCount; ++ii)
460         args->arguments[ii + 1] = QMetaType::QVariant;
461     args->names = 0;
462     if (argumentCount)
463         args->names = new QList<QByteArray>(names);
464     args->next = argumentsCache;
465     argumentsCache = args;
466     data.arguments = args;
467
468     data.flags = flags;
469
470     QHashedString string(name);
471     if (QQmlPropertyData **old = stringCache.value(string)) {
472         data.overrideIndexIsProperty = !(*old)->isFunction();
473         data.overrideIndex = (*old)->coreIndex;
474     }
475
476     methodIndexCache.append(data);
477
478     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
479 }
480
481 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
482                                      const QList<QByteArray> &names)
483 {
484     int argumentCount = names.count();
485
486     QQmlPropertyData data;
487     data.propType = QMetaType::QVariant;
488     data.coreIndex = coreIndex;
489
490     typedef QQmlPropertyCacheMethodArguments A;
491     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
492     args->arguments[0] = argumentCount;
493     for (int ii = 0; ii < argumentCount; ++ii)
494         args->arguments[ii + 1] = QMetaType::QVariant;
495     args->names = 0;
496     if (argumentCount)
497         args->names = new QList<QByteArray>(names);
498     args->next = argumentsCache;
499     argumentsCache = args;
500     data.arguments = args;
501
502     data.flags = flags;
503
504     if (QQmlPropertyData **old = stringCache.value(name)) {
505         data.overrideIndexIsProperty = !(*old)->isFunction();
506         data.overrideIndex = (*old)->coreIndex;
507     }
508
509     methodIndexCache.append(data);
510
511     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
512 }
513
514 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
515 const QMetaObject *QQmlPropertyCache::metaObject() const
516 {
517     return _metaObject;
518 }
519
520 // Returns this property cache's metaObject, creating it if necessary.
521 const QMetaObject *QQmlPropertyCache::createMetaObject()
522 {
523     if (!_metaObject) {
524         _ownMetaObject = true;
525
526         QMetaObjectBuilder builder;
527         toMetaObjectBuilder(builder);
528         builder.setSuperClass(_parent->createMetaObject());
529         _metaObject = builder.toMetaObject();
530     }
531
532     return _metaObject;
533 }
534
535 // Returns the name of the default property for this cache
536 QString QQmlPropertyCache::defaultPropertyName() const
537 {
538     return _defaultPropertyName;
539 }
540
541 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
542 {
543     return property(defaultPropertyName());
544 }
545
546 QQmlPropertyCache *QQmlPropertyCache::parent() const
547 {
548     return _parent;
549 }
550
551 // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
552 // QML
553 const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
554 {
555     while (_parent && (_metaObject == 0 || _ownMetaObject))
556         return _parent->firstCppMetaObject();
557     return _metaObject;
558 }
559
560 QQmlPropertyCache *
561 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
562                                          QQmlPropertyData::Flag propertyFlags,
563                                          QQmlPropertyData::Flag methodFlags,
564                                          QQmlPropertyData::Flag signalFlags)
565 {
566     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
567 }
568
569 QQmlPropertyCache *
570 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
571                                          int revision,
572                                          QQmlPropertyData::Flag propertyFlags,
573                                          QQmlPropertyData::Flag methodFlags,
574                                          QQmlPropertyData::Flag signalFlags)
575 {
576     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
577
578     // Reserve enough space in the name hash for all the methods (including signals), all the
579     // signal handlers and all the properties.  This assumes no name clashes, but this is the
580     // common case.
581     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
582                                          QMetaObjectPrivate::get(metaObject)->signalCount +
583                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
584
585     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
586
587     return rv;
588 }
589
590 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
591                                        int revision, 
592                                        QQmlPropertyData::Flag propertyFlags,
593                                        QQmlPropertyData::Flag methodFlags,
594                                        QQmlPropertyData::Flag signalFlags)
595 {
596     Q_UNUSED(revision);
597     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
598
599     _metaObject = metaObject;
600
601     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
602
603     allowedRevisionCache.append(0);
604
605     int methodCount = metaObject->methodCount();
606     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
607     int signalCount = metaObjectSignalCount(metaObject);
608     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
609
610     QQmlAccessorProperties::Properties accessorProperties;
611
612     if (classInfoCount) {
613         int classInfoOffset = metaObject->classInfoOffset();
614         bool hasFastProperty = false;
615         for (int ii = 0; ii < classInfoCount; ++ii) {
616             int idx = ii + classInfoOffset;
617
618             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
619                 hasFastProperty = true;
620             } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
621                 _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
622             }
623         }
624
625         if (hasFastProperty) {
626             accessorProperties = QQmlAccessorProperties::properties(metaObject);
627             if (accessorProperties.count == 0)
628                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
629                        "installed property accessors", metaObject->className());
630         } else {
631 #ifndef QT_NO_DEBUG
632             accessorProperties = QQmlAccessorProperties::properties(metaObject);
633             if (accessorProperties.count != 0)
634                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
635                        "FastProperty class info", metaObject->className());
636 #endif
637         }
638     }
639
640     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
641     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
642     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
643     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
644
645     int methodOffset = metaObject->methodOffset();
646     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
647
648     // update() should have reserved enough space in the vector that this doesn't cause a realloc
649     // and invalidate the stringCache.
650     methodIndexCache.resize(methodCount - methodIndexCacheStart);
651     signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
652     int signalHandlerIndex = signalOffset;
653     for (int ii = methodOffset; ii < methodCount; ++ii) {
654         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
655             continue;
656         QMetaMethod m = metaObject->method(ii);
657         if (m.access() == QMetaMethod::Private) 
658             continue;
659
660         // Extract method name
661         const char *signature;
662         if (QMetaObjectPrivate::get(metaObject)->revision >= 7) {
663             // Safe to use the raw name pointer
664             signature = m.name().constData();
665         } else {
666             // Safe to use the raw signature pointer
667             signature = m.methodSignature().constData();
668         }
669         const char *cptr = signature;
670         char utf8 = 0;
671         while (*cptr && *cptr != '(') {
672             Q_ASSERT(*cptr != 0);
673             utf8 |= *cptr & 0x80;
674             ++cptr;
675         }
676
677         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
678         QQmlPropertyData *sigdata = 0;
679
680         data->lazyLoad(m);
681
682         if (data->isSignal())
683             data->flags |= signalFlags;
684         else
685             data->flags |= methodFlags;
686
687         if (!dynamicMetaObject)
688             data->flags |= QQmlPropertyData::IsDirect;
689
690         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
691         data->metaObjectOffset = allowedRevisionCache.count() - 1;
692
693         if (data->isSignal()) {
694             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
695             *sigdata = *data;
696             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
697         }
698
699         QQmlPropertyData *old = 0;
700
701         if (utf8) {
702             QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
703             if (QQmlPropertyData **it = stringCache.value(methodName))
704                 old = *it;
705             stringCache.insert(methodName, data);
706
707             if (data->isSignal()) {
708                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
709                 stringCache.insert(on, sigdata);
710                 ++signalHandlerIndex;
711             }
712         } else {
713             QHashedCStringRef methodName(signature, cptr - signature);
714             if (QQmlPropertyData **it = stringCache.value(methodName))
715                 old = *it;
716             stringCache.insert(methodName, data);
717
718             if (data->isSignal()) {
719                 int length = methodName.length();
720
721                 QVarLengthArray<char, 128> str(length+3);
722                 str[0] = 'o';
723                 str[1] = 'n';
724                 str[2] = toupper(signature[0]);
725                 if (length > 1)
726                     memcpy(&str[3], &signature[1], length - 1);
727                 str[length + 2] = '\0';
728
729                 QHashedString on(QString::fromLatin1(str.data()));
730                 stringCache.insert(on, sigdata);
731                 ++signalHandlerIndex;
732             }
733         }
734
735         if (old) {
736             // We only overload methods in the same class, exactly like C++
737             if (old->isFunction() && old->coreIndex >= methodOffset)
738                 data->flags |= QQmlPropertyData::IsOverload;
739             data->overrideIndexIsProperty = !old->isFunction();
740             data->overrideIndex = old->coreIndex;
741         }
742     }
743
744     int propCount = metaObject->propertyCount();
745     int propOffset = metaObject->propertyOffset();
746
747     // update() should have reserved enough space in the vector that this doesn't cause a realloc
748     // and invalidate the stringCache.
749     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
750     for (int ii = propOffset; ii < propCount; ++ii) {
751         QMetaProperty p = metaObject->property(ii);
752         if (!p.isScriptable())
753             continue;
754
755         const char *str = p.name();
756         char utf8 = 0;
757         const char *cptr = str;
758         while (*cptr != 0) {
759             utf8 |= *cptr & 0x80;
760             ++cptr;
761         }
762
763         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
764
765         data->lazyLoad(p, engine);
766         data->flags |= propertyFlags;
767
768         if (!dynamicMetaObject) 
769             data->flags |= QQmlPropertyData::IsDirect;
770
771         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
772         data->metaObjectOffset = allowedRevisionCache.count() - 1;
773
774         QQmlPropertyData *old = 0;
775
776         if (utf8) {
777             QHashedString propName(QString::fromUtf8(str, cptr - str));
778             if (QQmlPropertyData **it = stringCache.value(propName))
779                 old = *it;
780             stringCache.insert(propName, data);
781         } else {
782             QHashedCStringRef propName(str, cptr - str);
783             if (QQmlPropertyData **it = stringCache.value(propName))
784                 old = *it;
785             stringCache.insert(propName, data);
786         }
787
788         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
789
790         // Fast properties may not be overrides or revisioned
791         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
792
793         if (accessorProperty) {
794             data->flags |= QQmlPropertyData::HasAccessors;
795             data->accessors = accessorProperty->accessors;
796             data->accessorData = accessorProperty->data;
797         } else if (old) {
798             data->overrideIndexIsProperty = !old->isFunction();
799             data->overrideIndex = old->coreIndex;
800         }
801     }
802 }
803
804 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
805 {
806     Q_ASSERT(data->notFullyResolved());
807
808     data->propType = QMetaType::type(data->propTypeName);
809
810     if (!data->isFunction())
811         data->flags |= flagsForPropertyType(data->propType, engine);
812
813     data->flags &= ~QQmlPropertyData::NotFullyResolved;
814 }
815
816 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
817 {
818     if (!metaObject)
819         return;
820
821     updateRecur(engine, metaObject->superClass());
822
823     append(engine, metaObject, -1);
824 }
825
826 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
827 {
828     Q_ASSERT(engine);
829     Q_ASSERT(metaObject);
830     Q_ASSERT(stringCache.isEmpty());
831
832     // Preallocate enough space in the index caches for all the properties/methods/signals that
833     // are not cached in a parent cache so that the caches never need to be reallocated as this
834     // would invalidate pointers stored in the stringCache.
835     int pc = metaObject->propertyCount();
836     int mc = metaObject->methodCount();
837     int sc = metaObjectSignalCount(metaObject);
838     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
839     methodIndexCache.reserve(mc - methodIndexCacheStart);
840     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
841
842     // Reserve enough space in the stringCache for all properties/methods/signals including those
843     // cached in a parent cache.
844     stringCache.reserve(pc + mc + sc);
845
846     updateRecur(engine,metaObject);
847 }
848
849 QQmlPropertyData *
850 QQmlPropertyCache::property(int index) const
851 {
852     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
853         return 0;
854     
855     if (index < propertyIndexCacheStart)
856         return _parent->property(index);
857
858     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
859     if (rv->notFullyResolved()) resolve(rv);
860     return rv;
861 }
862
863 QQmlPropertyData *
864 QQmlPropertyCache::method(int index) const
865 {
866     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
867         return 0;
868
869     if (index < methodIndexCacheStart)
870         return _parent->method(index);
871
872     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
873     if (rv->notFullyResolved()) resolve(rv);
874     return rv;
875 }
876
877 QQmlPropertyData *
878 QQmlPropertyCache::property(const QHashedStringRef &str) const
879 {
880     QQmlPropertyData **rv = stringCache.value(str);
881     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
882     return rv?*rv:0;
883 }
884
885 QQmlPropertyData *
886 QQmlPropertyCache::property(const QHashedCStringRef &str) const
887 {
888     QQmlPropertyData **rv = stringCache.value(str);
889     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
890     return rv?*rv:0;
891 }
892
893 QQmlPropertyData *
894 QQmlPropertyCache::property(const QString &str) const
895 {
896     QQmlPropertyData **rv = stringCache.value(str);
897     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
898     return rv?*rv:0;
899 }
900
901 QString QQmlPropertyData::name(QObject *object)
902 {
903     if (!object)
904         return QString();
905
906     return name(object->metaObject());
907 }
908
909 QString QQmlPropertyData::name(const QMetaObject *metaObject)
910 {
911     if (!metaObject || coreIndex == -1)
912         return QString();
913
914     if (flags & IsFunction) {
915         QMetaMethod m = metaObject->method(coreIndex);
916
917         return QString::fromUtf8(m.name().constData());
918     } else {
919         QMetaProperty p = metaObject->property(coreIndex);
920         return QString::fromUtf8(p.name());
921     }
922 }
923
924 QStringList QQmlPropertyCache::propertyNames() const
925 {
926     QStringList keys;
927     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
928         keys.append(iter.key());
929     return keys;
930 }
931
932 struct StaticQtMetaObject : public QObject
933 {
934     static const QMetaObject *get()
935         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
936 };
937
938 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
939 {
940     QByteArray scope;
941     QByteArray name;
942     int scopeIdx = str.lastIndexOf("::");
943     if (scopeIdx != -1) {
944         scope = str.left(scopeIdx);
945         name = str.mid(scopeIdx + 2);
946     } else { 
947         name = str;
948     }
949     const QMetaObject *meta;
950     if (scope == "Qt")
951         meta = StaticQtMetaObject::get();
952     else
953         meta = metaobj;
954     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
955         QMetaEnum m = meta->enumerator(i);
956         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
957             return QVariant::Int;
958     }
959     return type;
960 }
961
962 QList<QByteArray> QQmlPropertyCache::methodParameterNames(QObject *object, int index)
963 {
964     QQmlData *data = QQmlData::get(object, false);
965     if (data->propertyCache) {
966         QQmlPropertyData *p = data->propertyCache->method(index);
967         if (!p->hasArguments())
968             return QList<QByteArray>();
969     }
970
971     return object->metaObject()->method(index).parameterNames();
972 }
973
974 // Returns an array of the arguments for method \a index.  The first entry in the array
975 // is the number of arguments.
976 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
977                                                      QVarLengthArray<int, 9> &dummy,
978                                                      QByteArray *unknownTypeError)
979 {
980     Q_ASSERT(object && index >= 0);
981
982     QQmlData *ddata = QQmlData::get(object, false);
983
984     if (ddata && ddata->propertyCache) {
985         typedef QQmlPropertyCacheMethodArguments A;
986
987         QQmlPropertyCache *c = ddata->propertyCache;
988         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
989
990         while (index < c->methodIndexCacheStart)
991             c = c->_parent;
992
993         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
994
995         if (rv->arguments)  
996             return static_cast<A *>(rv->arguments)->arguments;
997
998         const QMetaObject *metaObject = c->createMetaObject();
999         Q_ASSERT(metaObject);
1000         QMetaMethod m = metaObject->method(index);
1001
1002         int argc = m.parameterCount();
1003         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1004         args->arguments[0] = argc;
1005         args->names = 0;
1006         QList<QByteArray> argTypeNames; // Only loaded if needed
1007
1008         for (int ii = 0; ii < argc; ++ii) {
1009             int type = m.parameterType(ii);
1010             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1011             if (flags & QMetaType::IsEnumeration)
1012                 type = QVariant::Int;
1013             else if (type == QMetaType::UnknownType ||
1014                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1015                       type != qMetaTypeId<QJSValue>())) {
1016                 //the UserType clause is to catch registered QFlags
1017                 if (argTypeNames.isEmpty())
1018                     argTypeNames = m.parameterTypes();
1019                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1020             }
1021             if (type == QMetaType::UnknownType) {
1022                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1023                 free(args);
1024                 return 0;
1025             }
1026             args->arguments[ii + 1] = type;
1027         }
1028
1029         rv->arguments = args;
1030         args->next = c->argumentsCache;
1031         c->argumentsCache = args;
1032         return static_cast<A *>(rv->arguments)->arguments;
1033
1034     } else {
1035         QMetaMethod m = object->metaObject()->method(index);
1036         int argc = m.parameterCount();
1037         dummy.resize(argc + 1);
1038         dummy[0] = argc;
1039         QList<QByteArray> argTypeNames; // Only loaded if needed
1040
1041         for (int ii = 0; ii < argc; ++ii) {
1042             int type = m.parameterType(ii);
1043             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1044             if (flags & QMetaType::IsEnumeration)
1045                 type = QVariant::Int;
1046             else if (type == QMetaType::UnknownType ||
1047                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1048                       type != qMetaTypeId<QJSValue>())) {
1049                 //the UserType clause is to catch registered QFlags)
1050                 if (argTypeNames.isEmpty())
1051                     argTypeNames = m.parameterTypes();
1052                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1053             }
1054             if (type == QMetaType::UnknownType) {
1055                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1056                 return 0;
1057             }
1058             dummy[ii + 1] = type;
1059         }
1060
1061         return dummy.data();
1062     }
1063 }
1064
1065 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1066 {
1067     Q_ASSERT(metaObject);
1068
1069     QQmlPropertyData rv;
1070     {
1071         const QMetaObject *cmo = metaObject;
1072         const QByteArray propertyName = property.toUtf8();
1073         while (cmo) {
1074             int idx = cmo->indexOfProperty(propertyName);
1075             if (idx != -1) {
1076                 QMetaProperty p = cmo->property(idx);
1077                 if (p.isScriptable()) {
1078                     rv.load(p);
1079                     return rv;
1080                 } else {
1081                     while (cmo && cmo->propertyOffset() >= idx)
1082                         cmo = cmo->superClass();
1083                 }
1084             } else {
1085                 cmo = 0;
1086             }
1087         }
1088     }
1089
1090     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1091     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1092     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1093     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1094
1095     int methodCount = metaObject->methodCount();
1096     for (int ii = methodCount - 1; ii >= 0; --ii) {
1097         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1098             continue;
1099         QMetaMethod m = metaObject->method(ii);
1100         if (m.access() == QMetaMethod::Private)
1101             continue;
1102         QString methodName = QString::fromUtf8(m.name().constData());
1103
1104         if (methodName == property) {
1105             rv.load(m);
1106             return rv;
1107         }
1108     }
1109
1110     return rv;
1111 }
1112
1113 inline const QString &qQmlPropertyCacheToString(const QString &string)
1114 {
1115     return string;
1116 }
1117
1118 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1119 {
1120     return QV8Engine::toStringStatic(string.string());
1121 }
1122
1123 template<typename T>
1124 QQmlPropertyData *
1125 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1126 {
1127     QQmlPropertyCache *cache = 0;
1128
1129     QQmlData *ddata = QQmlData::get(obj, false);
1130
1131     if (ddata && ddata->propertyCache) {
1132         cache = ddata->propertyCache;
1133     } else if (engine) {
1134         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1135         cache = ep->cache(obj);
1136         if (cache) {
1137             ddata = QQmlData::get(obj, true);
1138             cache->addref();
1139             ddata->propertyCache = cache;
1140         }
1141     }
1142
1143     QQmlPropertyData *rv = 0;
1144
1145     if (cache) {
1146         rv = cache->property(name);
1147     } else {
1148         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1149         if (local.isValid())
1150             rv = &local;
1151     }
1152
1153     return rv;
1154 }
1155
1156 QQmlPropertyData *
1157 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
1158                                     const QHashedV8String &name, QQmlPropertyData &local)
1159 {
1160     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1161 }
1162
1163 QQmlPropertyData *
1164 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1165                                     const QString &name, QQmlPropertyData &local)
1166 {
1167     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1168 }
1169
1170 static inline const QMetaObjectPrivate *priv(const uint* data)
1171 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1172
1173 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1174 {
1175     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1176 }
1177
1178 const char *QQmlPropertyCache::className() const
1179 {
1180     if (!_ownMetaObject && _metaObject)
1181         return _metaObject->className();
1182     else
1183         return _dynamicClassName.constData();
1184 }
1185
1186 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1187 {
1188     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1189                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1190         return lhs.second->coreIndex < rhs.second->coreIndex;
1191     } };
1192
1193     struct Insert { static void in(QQmlPropertyCache *This,
1194                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1195                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1196                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1197         if (data->isSignalHandler())
1198             return;
1199
1200         if (data->isFunction()) {
1201             if (data->coreIndex < This->methodIndexCacheStart)
1202                 return;
1203
1204             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1205             // Overrides can cause the entry to already exist
1206             if (!methods.contains(entry)) methods.append(entry);
1207
1208             QQmlPropertyData *olddata = data;
1209             data = This->overrideData(data);
1210             if (data) Insert::in(This, properties, methods, iter, data);
1211         } else {
1212             if (data->coreIndex < This->propertyIndexCacheStart)
1213                 return;
1214
1215             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1216             // Overrides can cause the entry to already exist
1217             if (!properties.contains(entry)) properties.append(entry);
1218
1219             QQmlPropertyData *olddata = data;
1220             data = This->overrideData(data);
1221             if (data) Insert::in(This, properties, methods, iter, data);
1222         }
1223
1224     } };
1225
1226     builder.setClassName(_dynamicClassName);
1227
1228     QList<QPair<QString, QQmlPropertyData *> > properties;
1229     QList<QPair<QString, QQmlPropertyData *> > methods;
1230
1231     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1232         Insert::in(this, properties, methods, iter, iter.value());
1233
1234     Q_ASSERT(properties.count() == propertyIndexCache.count());
1235     Q_ASSERT(methods.count() == methodIndexCache.count());
1236
1237     qSort(properties.begin(), properties.end(), Sort::lt);
1238     qSort(methods.begin(), methods.end(), Sort::lt);
1239
1240     for (int ii = 0; ii < properties.count(); ++ii) {
1241         QQmlPropertyData *data = properties.at(ii).second;
1242
1243         int notifierId = -1;
1244         if (data->notifyIndex != -1)
1245             notifierId = data->notifyIndex - methodIndexCacheStart;
1246
1247         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1248                                                             QMetaType::typeName(data->propType),
1249                                                             notifierId);
1250
1251         property.setReadable(true);
1252         property.setWritable(data->isWritable());
1253         property.setResettable(data->isResettable());
1254     }
1255
1256     for (int ii = 0; ii < methods.count(); ++ii) {
1257         QQmlPropertyData *data = methods.at(ii).second;
1258
1259         QByteArray returnType;
1260         if (data->propType != 0)
1261             returnType = QMetaType::typeName(data->propType);
1262
1263         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1264
1265         QQmlPropertyCacheMethodArguments *arguments = 0;
1266         if (data->hasArguments()) {
1267             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1268
1269             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1270                 if (ii != 0) signature.append(",");
1271                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1272             }
1273         }
1274
1275         signature.append(")");
1276
1277         QMetaMethodBuilder method;
1278         if (data->isSignal()) {
1279             method = builder.addSignal(signature);
1280         } else {
1281             method = builder.addSlot(signature);
1282         }
1283         method.setAccess(QMetaMethod::Protected);
1284
1285         if (arguments && arguments->names)
1286             method.setParameterNames(*arguments->names);
1287
1288         if (!returnType.isEmpty())
1289             method.setReturnType(returnType);
1290     }
1291
1292     if (!_defaultPropertyName.isEmpty()) {
1293         QQmlPropertyData *dp = property(_defaultPropertyName);
1294         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1295             Q_ASSERT(!dp->isFunction());
1296             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1297         }
1298     }
1299 }
1300
1301 // Returns true if \a from is assignable to a property of type \a to
1302 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1303 {
1304     Q_ASSERT(!from.isNull() && !to.isNull());
1305
1306     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1307         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1308     } };
1309
1310     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1311     if (tom == &QObject::staticMetaObject) return true;
1312
1313     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1314         QQmlPropertyCache *fromp = from._m.asT1();
1315         QQmlPropertyCache *top = to._m.asT1();
1316
1317         while (fromp) {
1318             if (fromp == top) return true;
1319             fromp = fromp->parent();
1320         }
1321     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1322         QQmlPropertyCache *fromp = from._m.asT1();
1323
1324         while (fromp) {
1325             const QMetaObject *fromm = fromp->metaObject();
1326             if (fromm && I::equal(fromm, tom)) return true;
1327             fromp = fromp->parent();
1328         }
1329     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1330         const QMetaObject *fromm = from._m.asT2();
1331
1332         if (!tom) return false;
1333
1334         while (fromm) {
1335             if (I::equal(fromm, tom)) return true;
1336             fromm = fromm->superClass();
1337         }
1338     } else { // QMetaObject -> QMetaObject
1339         const QMetaObject *fromm = from._m.asT2();
1340
1341         while (fromm) {
1342             if (I::equal(fromm, tom)) return true;
1343             fromm = fromm->superClass();
1344         }
1345     }
1346
1347     return false;
1348 }
1349
1350 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1351 {
1352     if (_m.isNull()) return 0;
1353     if (_m.isT1()) return _m.asT1();
1354     else return e->cache(_m.asT2());
1355 }
1356
1357 QT_END_NAMESPACE