Simplify method name extraction in property cache
[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         // It's safe to keep the raw name pointer
662         Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
663         const char *rawName = m.name().constData();
664         const char *cptr = rawName;
665         char utf8 = 0;
666         while (*cptr) {
667             utf8 |= *cptr & 0x80;
668             ++cptr;
669         }
670
671         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
672         QQmlPropertyData *sigdata = 0;
673
674         data->lazyLoad(m);
675
676         if (data->isSignal())
677             data->flags |= signalFlags;
678         else
679             data->flags |= methodFlags;
680
681         if (!dynamicMetaObject)
682             data->flags |= QQmlPropertyData::IsDirect;
683
684         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
685         data->metaObjectOffset = allowedRevisionCache.count() - 1;
686
687         if (data->isSignal()) {
688             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
689             *sigdata = *data;
690             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
691         }
692
693         QQmlPropertyData *old = 0;
694
695         if (utf8) {
696             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
697             if (QQmlPropertyData **it = stringCache.value(methodName))
698                 old = *it;
699             stringCache.insert(methodName, data);
700
701             if (data->isSignal()) {
702                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
703                 stringCache.insert(on, sigdata);
704                 ++signalHandlerIndex;
705             }
706         } else {
707             QHashedCStringRef methodName(rawName, cptr - rawName);
708             if (QQmlPropertyData **it = stringCache.value(methodName))
709                 old = *it;
710             stringCache.insert(methodName, data);
711
712             if (data->isSignal()) {
713                 int length = methodName.length();
714
715                 QVarLengthArray<char, 128> str(length+3);
716                 str[0] = 'o';
717                 str[1] = 'n';
718                 str[2] = toupper(rawName[0]);
719                 if (length > 1)
720                     memcpy(&str[3], &rawName[1], length - 1);
721                 str[length + 2] = '\0';
722
723                 QHashedString on(QString::fromLatin1(str.data()));
724                 stringCache.insert(on, sigdata);
725                 ++signalHandlerIndex;
726             }
727         }
728
729         if (old) {
730             // We only overload methods in the same class, exactly like C++
731             if (old->isFunction() && old->coreIndex >= methodOffset)
732                 data->flags |= QQmlPropertyData::IsOverload;
733             data->overrideIndexIsProperty = !old->isFunction();
734             data->overrideIndex = old->coreIndex;
735         }
736     }
737
738     int propCount = metaObject->propertyCount();
739     int propOffset = metaObject->propertyOffset();
740
741     // update() should have reserved enough space in the vector that this doesn't cause a realloc
742     // and invalidate the stringCache.
743     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
744     for (int ii = propOffset; ii < propCount; ++ii) {
745         QMetaProperty p = metaObject->property(ii);
746         if (!p.isScriptable())
747             continue;
748
749         const char *str = p.name();
750         char utf8 = 0;
751         const char *cptr = str;
752         while (*cptr != 0) {
753             utf8 |= *cptr & 0x80;
754             ++cptr;
755         }
756
757         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
758
759         data->lazyLoad(p, engine);
760         data->flags |= propertyFlags;
761
762         if (!dynamicMetaObject) 
763             data->flags |= QQmlPropertyData::IsDirect;
764
765         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
766         data->metaObjectOffset = allowedRevisionCache.count() - 1;
767
768         QQmlPropertyData *old = 0;
769
770         if (utf8) {
771             QHashedString propName(QString::fromUtf8(str, cptr - str));
772             if (QQmlPropertyData **it = stringCache.value(propName))
773                 old = *it;
774             stringCache.insert(propName, data);
775         } else {
776             QHashedCStringRef propName(str, cptr - str);
777             if (QQmlPropertyData **it = stringCache.value(propName))
778                 old = *it;
779             stringCache.insert(propName, data);
780         }
781
782         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
783
784         // Fast properties may not be overrides or revisioned
785         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
786
787         if (accessorProperty) {
788             data->flags |= QQmlPropertyData::HasAccessors;
789             data->accessors = accessorProperty->accessors;
790             data->accessorData = accessorProperty->data;
791         } else if (old) {
792             data->overrideIndexIsProperty = !old->isFunction();
793             data->overrideIndex = old->coreIndex;
794         }
795     }
796 }
797
798 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
799 {
800     Q_ASSERT(data->notFullyResolved());
801
802     data->propType = QMetaType::type(data->propTypeName);
803
804     if (!data->isFunction())
805         data->flags |= flagsForPropertyType(data->propType, engine);
806
807     data->flags &= ~QQmlPropertyData::NotFullyResolved;
808 }
809
810 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
811 {
812     if (!metaObject)
813         return;
814
815     updateRecur(engine, metaObject->superClass());
816
817     append(engine, metaObject, -1);
818 }
819
820 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
821 {
822     Q_ASSERT(engine);
823     Q_ASSERT(metaObject);
824     Q_ASSERT(stringCache.isEmpty());
825
826     // Preallocate enough space in the index caches for all the properties/methods/signals that
827     // are not cached in a parent cache so that the caches never need to be reallocated as this
828     // would invalidate pointers stored in the stringCache.
829     int pc = metaObject->propertyCount();
830     int mc = metaObject->methodCount();
831     int sc = metaObjectSignalCount(metaObject);
832     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
833     methodIndexCache.reserve(mc - methodIndexCacheStart);
834     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
835
836     // Reserve enough space in the stringCache for all properties/methods/signals including those
837     // cached in a parent cache.
838     stringCache.reserve(pc + mc + sc);
839
840     updateRecur(engine,metaObject);
841 }
842
843 QQmlPropertyData *
844 QQmlPropertyCache::property(int index) const
845 {
846     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
847         return 0;
848     
849     if (index < propertyIndexCacheStart)
850         return _parent->property(index);
851
852     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
853     if (rv->notFullyResolved()) resolve(rv);
854     return rv;
855 }
856
857 QQmlPropertyData *
858 QQmlPropertyCache::method(int index) const
859 {
860     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
861         return 0;
862
863     if (index < methodIndexCacheStart)
864         return _parent->method(index);
865
866     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
867     if (rv->notFullyResolved()) resolve(rv);
868     return rv;
869 }
870
871 QQmlPropertyData *
872 QQmlPropertyCache::property(const QHashedStringRef &str) const
873 {
874     QQmlPropertyData **rv = stringCache.value(str);
875     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
876     return rv?*rv:0;
877 }
878
879 QQmlPropertyData *
880 QQmlPropertyCache::property(const QHashedCStringRef &str) const
881 {
882     QQmlPropertyData **rv = stringCache.value(str);
883     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
884     return rv?*rv:0;
885 }
886
887 QQmlPropertyData *
888 QQmlPropertyCache::property(const QString &str) const
889 {
890     QQmlPropertyData **rv = stringCache.value(str);
891     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
892     return rv?*rv:0;
893 }
894
895 QString QQmlPropertyData::name(QObject *object)
896 {
897     if (!object)
898         return QString();
899
900     return name(object->metaObject());
901 }
902
903 QString QQmlPropertyData::name(const QMetaObject *metaObject)
904 {
905     if (!metaObject || coreIndex == -1)
906         return QString();
907
908     if (flags & IsFunction) {
909         QMetaMethod m = metaObject->method(coreIndex);
910
911         return QString::fromUtf8(m.name().constData());
912     } else {
913         QMetaProperty p = metaObject->property(coreIndex);
914         return QString::fromUtf8(p.name());
915     }
916 }
917
918 QStringList QQmlPropertyCache::propertyNames() const
919 {
920     QStringList keys;
921     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
922         keys.append(iter.key());
923     return keys;
924 }
925
926 struct StaticQtMetaObject : public QObject
927 {
928     static const QMetaObject *get()
929         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
930 };
931
932 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
933 {
934     QByteArray scope;
935     QByteArray name;
936     int scopeIdx = str.lastIndexOf("::");
937     if (scopeIdx != -1) {
938         scope = str.left(scopeIdx);
939         name = str.mid(scopeIdx + 2);
940     } else { 
941         name = str;
942     }
943     const QMetaObject *meta;
944     if (scope == "Qt")
945         meta = StaticQtMetaObject::get();
946     else
947         meta = metaobj;
948     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
949         QMetaEnum m = meta->enumerator(i);
950         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
951             return QVariant::Int;
952     }
953     return type;
954 }
955
956 QList<QByteArray> QQmlPropertyCache::methodParameterNames(QObject *object, int index)
957 {
958     QQmlData *data = QQmlData::get(object, false);
959     if (data->propertyCache) {
960         QQmlPropertyData *p = data->propertyCache->method(index);
961         if (!p->hasArguments())
962             return QList<QByteArray>();
963     }
964
965     return object->metaObject()->method(index).parameterNames();
966 }
967
968 // Returns an array of the arguments for method \a index.  The first entry in the array
969 // is the number of arguments.
970 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
971                                                      QVarLengthArray<int, 9> &dummy,
972                                                      QByteArray *unknownTypeError)
973 {
974     Q_ASSERT(object && index >= 0);
975
976     QQmlData *ddata = QQmlData::get(object, false);
977
978     if (ddata && ddata->propertyCache) {
979         typedef QQmlPropertyCacheMethodArguments A;
980
981         QQmlPropertyCache *c = ddata->propertyCache;
982         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
983
984         while (index < c->methodIndexCacheStart)
985             c = c->_parent;
986
987         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
988
989         if (rv->arguments)  
990             return static_cast<A *>(rv->arguments)->arguments;
991
992         const QMetaObject *metaObject = c->createMetaObject();
993         Q_ASSERT(metaObject);
994         QMetaMethod m = metaObject->method(index);
995
996         int argc = m.parameterCount();
997         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
998         args->arguments[0] = argc;
999         args->names = 0;
1000         QList<QByteArray> argTypeNames; // Only loaded if needed
1001
1002         for (int ii = 0; ii < argc; ++ii) {
1003             int type = m.parameterType(ii);
1004             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1005             if (flags & QMetaType::IsEnumeration)
1006                 type = QVariant::Int;
1007             else if (type == QMetaType::UnknownType ||
1008                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1009                       type != qMetaTypeId<QJSValue>())) {
1010                 //the UserType clause is to catch registered QFlags
1011                 if (argTypeNames.isEmpty())
1012                     argTypeNames = m.parameterTypes();
1013                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1014             }
1015             if (type == QMetaType::UnknownType) {
1016                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1017                 free(args);
1018                 return 0;
1019             }
1020             args->arguments[ii + 1] = type;
1021         }
1022
1023         rv->arguments = args;
1024         args->next = c->argumentsCache;
1025         c->argumentsCache = args;
1026         return static_cast<A *>(rv->arguments)->arguments;
1027
1028     } else {
1029         QMetaMethod m = object->metaObject()->method(index);
1030         int argc = m.parameterCount();
1031         dummy.resize(argc + 1);
1032         dummy[0] = argc;
1033         QList<QByteArray> argTypeNames; // Only loaded if needed
1034
1035         for (int ii = 0; ii < argc; ++ii) {
1036             int type = m.parameterType(ii);
1037             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1038             if (flags & QMetaType::IsEnumeration)
1039                 type = QVariant::Int;
1040             else if (type == QMetaType::UnknownType ||
1041                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1042                       type != qMetaTypeId<QJSValue>())) {
1043                 //the UserType clause is to catch registered QFlags)
1044                 if (argTypeNames.isEmpty())
1045                     argTypeNames = m.parameterTypes();
1046                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1047             }
1048             if (type == QMetaType::UnknownType) {
1049                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1050                 return 0;
1051             }
1052             dummy[ii + 1] = type;
1053         }
1054
1055         return dummy.data();
1056     }
1057 }
1058
1059 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1060 {
1061     Q_ASSERT(metaObject);
1062
1063     QQmlPropertyData rv;
1064     {
1065         const QMetaObject *cmo = metaObject;
1066         const QByteArray propertyName = property.toUtf8();
1067         while (cmo) {
1068             int idx = cmo->indexOfProperty(propertyName);
1069             if (idx != -1) {
1070                 QMetaProperty p = cmo->property(idx);
1071                 if (p.isScriptable()) {
1072                     rv.load(p);
1073                     return rv;
1074                 } else {
1075                     while (cmo && cmo->propertyOffset() >= idx)
1076                         cmo = cmo->superClass();
1077                 }
1078             } else {
1079                 cmo = 0;
1080             }
1081         }
1082     }
1083
1084     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1085     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1086     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1087     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1088
1089     int methodCount = metaObject->methodCount();
1090     for (int ii = methodCount - 1; ii >= 0; --ii) {
1091         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1092             continue;
1093         QMetaMethod m = metaObject->method(ii);
1094         if (m.access() == QMetaMethod::Private)
1095             continue;
1096         QString methodName = QString::fromUtf8(m.name().constData());
1097
1098         if (methodName == property) {
1099             rv.load(m);
1100             return rv;
1101         }
1102     }
1103
1104     return rv;
1105 }
1106
1107 inline const QString &qQmlPropertyCacheToString(const QString &string)
1108 {
1109     return string;
1110 }
1111
1112 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1113 {
1114     return QV8Engine::toStringStatic(string.string());
1115 }
1116
1117 template<typename T>
1118 QQmlPropertyData *
1119 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1120 {
1121     QQmlPropertyCache *cache = 0;
1122
1123     QQmlData *ddata = QQmlData::get(obj, false);
1124
1125     if (ddata && ddata->propertyCache) {
1126         cache = ddata->propertyCache;
1127     } else if (engine) {
1128         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1129         cache = ep->cache(obj);
1130         if (cache) {
1131             ddata = QQmlData::get(obj, true);
1132             cache->addref();
1133             ddata->propertyCache = cache;
1134         }
1135     }
1136
1137     QQmlPropertyData *rv = 0;
1138
1139     if (cache) {
1140         rv = cache->property(name);
1141     } else {
1142         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1143         if (local.isValid())
1144             rv = &local;
1145     }
1146
1147     return rv;
1148 }
1149
1150 QQmlPropertyData *
1151 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
1152                                     const QHashedV8String &name, QQmlPropertyData &local)
1153 {
1154     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1155 }
1156
1157 QQmlPropertyData *
1158 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1159                                     const QString &name, QQmlPropertyData &local)
1160 {
1161     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1162 }
1163
1164 static inline const QMetaObjectPrivate *priv(const uint* data)
1165 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1166
1167 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1168 {
1169     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1170 }
1171
1172 const char *QQmlPropertyCache::className() const
1173 {
1174     if (!_ownMetaObject && _metaObject)
1175         return _metaObject->className();
1176     else
1177         return _dynamicClassName.constData();
1178 }
1179
1180 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1181 {
1182     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1183                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1184         return lhs.second->coreIndex < rhs.second->coreIndex;
1185     } };
1186
1187     struct Insert { static void in(QQmlPropertyCache *This,
1188                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1189                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1190                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1191         if (data->isSignalHandler())
1192             return;
1193
1194         if (data->isFunction()) {
1195             if (data->coreIndex < This->methodIndexCacheStart)
1196                 return;
1197
1198             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1199             // Overrides can cause the entry to already exist
1200             if (!methods.contains(entry)) methods.append(entry);
1201
1202             QQmlPropertyData *olddata = data;
1203             data = This->overrideData(data);
1204             if (data) Insert::in(This, properties, methods, iter, data);
1205         } else {
1206             if (data->coreIndex < This->propertyIndexCacheStart)
1207                 return;
1208
1209             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1210             // Overrides can cause the entry to already exist
1211             if (!properties.contains(entry)) properties.append(entry);
1212
1213             QQmlPropertyData *olddata = data;
1214             data = This->overrideData(data);
1215             if (data) Insert::in(This, properties, methods, iter, data);
1216         }
1217
1218     } };
1219
1220     builder.setClassName(_dynamicClassName);
1221
1222     QList<QPair<QString, QQmlPropertyData *> > properties;
1223     QList<QPair<QString, QQmlPropertyData *> > methods;
1224
1225     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1226         Insert::in(this, properties, methods, iter, iter.value());
1227
1228     Q_ASSERT(properties.count() == propertyIndexCache.count());
1229     Q_ASSERT(methods.count() == methodIndexCache.count());
1230
1231     qSort(properties.begin(), properties.end(), Sort::lt);
1232     qSort(methods.begin(), methods.end(), Sort::lt);
1233
1234     for (int ii = 0; ii < properties.count(); ++ii) {
1235         QQmlPropertyData *data = properties.at(ii).second;
1236
1237         int notifierId = -1;
1238         if (data->notifyIndex != -1)
1239             notifierId = data->notifyIndex - methodIndexCacheStart;
1240
1241         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1242                                                             QMetaType::typeName(data->propType),
1243                                                             notifierId);
1244
1245         property.setReadable(true);
1246         property.setWritable(data->isWritable());
1247         property.setResettable(data->isResettable());
1248     }
1249
1250     for (int ii = 0; ii < methods.count(); ++ii) {
1251         QQmlPropertyData *data = methods.at(ii).second;
1252
1253         QByteArray returnType;
1254         if (data->propType != 0)
1255             returnType = QMetaType::typeName(data->propType);
1256
1257         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1258
1259         QQmlPropertyCacheMethodArguments *arguments = 0;
1260         if (data->hasArguments()) {
1261             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1262
1263             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1264                 if (ii != 0) signature.append(",");
1265                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1266             }
1267         }
1268
1269         signature.append(")");
1270
1271         QMetaMethodBuilder method;
1272         if (data->isSignal()) {
1273             method = builder.addSignal(signature);
1274         } else {
1275             method = builder.addSlot(signature);
1276         }
1277         method.setAccess(QMetaMethod::Protected);
1278
1279         if (arguments && arguments->names)
1280             method.setParameterNames(*arguments->names);
1281
1282         if (!returnType.isEmpty())
1283             method.setReturnType(returnType);
1284     }
1285
1286     if (!_defaultPropertyName.isEmpty()) {
1287         QQmlPropertyData *dp = property(_defaultPropertyName);
1288         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1289             Q_ASSERT(!dp->isFunction());
1290             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1291         }
1292     }
1293 }
1294
1295 // Returns true if \a from is assignable to a property of type \a to
1296 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1297 {
1298     Q_ASSERT(!from.isNull() && !to.isNull());
1299
1300     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1301         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1302     } };
1303
1304     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1305     if (tom == &QObject::staticMetaObject) return true;
1306
1307     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1308         QQmlPropertyCache *fromp = from._m.asT1();
1309         QQmlPropertyCache *top = to._m.asT1();
1310
1311         while (fromp) {
1312             if (fromp == top) return true;
1313             fromp = fromp->parent();
1314         }
1315     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1316         QQmlPropertyCache *fromp = from._m.asT1();
1317
1318         while (fromp) {
1319             const QMetaObject *fromm = fromp->metaObject();
1320             if (fromm && I::equal(fromm, tom)) return true;
1321             fromp = fromp->parent();
1322         }
1323     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1324         const QMetaObject *fromm = from._m.asT2();
1325
1326         if (!tom) return false;
1327
1328         while (fromm) {
1329             if (I::equal(fromm, tom)) return true;
1330             fromm = fromm->superClass();
1331         }
1332     } else { // QMetaObject -> QMetaObject
1333         const QMetaObject *fromm = from._m.asT2();
1334
1335         while (fromm) {
1336             if (I::equal(fromm, tom)) return true;
1337             fromm = fromm->superClass();
1338         }
1339     }
1340
1341     return false;
1342 }
1343
1344 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1345 {
1346     if (_m.isNull()) return 0;
1347     if (_m.isT1()) return _m.asT1();
1348     else return e->cache(_m.asT2());
1349 }
1350
1351 QT_END_NAMESPACE