Support enum return types in Q_INVOKABLE functions.
[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 = QMetaObjectPrivate::signalIndex(p.notifySignal());
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 = QMetaObjectPrivate::signalIndex(p.notifySignal());
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 /*! \internal
332
333     \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
334     This is different from QMetaMethod::methodIndex().
335 */
336 void QQmlPropertyCache::appendProperty(const QString &name,
337                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
338 {
339     QQmlPropertyData data;
340     data.propType = propType;
341     data.coreIndex = coreIndex;
342     data.notifyIndex = notifyIndex;
343     data.flags = flags;
344
345     QHashedString string(name);
346     if (QQmlPropertyData **old = stringCache.value(string)) {
347         data.overrideIndexIsProperty = !(*old)->isFunction();
348         data.overrideIndex = (*old)->coreIndex;
349     }
350
351     propertyIndexCache.append(data);
352
353     stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
354 }
355
356 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
357                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
358 {
359     QQmlPropertyData data;
360     data.propType = propType;
361     data.coreIndex = coreIndex;
362     data.notifyIndex = notifyIndex;
363     data.flags = flags;
364
365     if (QQmlPropertyData **old = stringCache.value(name)) {
366         data.overrideIndexIsProperty = !(*old)->isFunction();
367         data.overrideIndex = (*old)->coreIndex;
368     }
369
370     propertyIndexCache.append(data);
371
372     stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
373 }
374
375 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
376                                      const int *types, const QList<QByteArray> &names)
377 {
378     QQmlPropertyData data;
379     data.propType = QVariant::Invalid;
380     data.coreIndex = coreIndex;
381     data.flags = flags;
382     data.arguments = 0;
383
384     QQmlPropertyData handler = data;
385     handler.flags |= QQmlPropertyData::IsSignalHandler;
386
387     if (types) {
388         int argumentCount = *types;
389         typedef QQmlPropertyCacheMethodArguments A;
390         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
391         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
392         args->names = new QList<QByteArray>(names);
393         args->next = argumentsCache;
394         argumentsCache = args;
395         data.arguments = args;
396     }
397
398     QString handlerName = QLatin1String("on") + name;
399     handlerName[2] = handlerName[2].toUpper();
400
401     QHashedString string(name);
402     if (QQmlPropertyData **old = stringCache.value(string)) {
403         data.overrideIndexIsProperty = !(*old)->isFunction();
404         data.overrideIndex = (*old)->coreIndex;
405     }
406
407     methodIndexCache.append(data);
408     signalHandlerIndexCache.append(handler);
409
410     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
411     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
412 }
413
414 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
415                                      const int *types, const QList<QByteArray> &names)
416 {
417     QQmlPropertyData data;
418     data.propType = QVariant::Invalid;
419     data.coreIndex = coreIndex;
420     data.flags = flags;
421     data.arguments = 0;
422
423     QQmlPropertyData handler = data;
424     handler.flags |= QQmlPropertyData::IsSignalHandler;
425
426     if (types) {
427         int argumentCount = *types;
428         typedef QQmlPropertyCacheMethodArguments A;
429         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
430         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
431         args->names = new QList<QByteArray>(names);
432         args->next = argumentsCache;
433         argumentsCache = args;
434         data.arguments = args;
435     }
436
437     QString handlerName = QLatin1String("on") + name.toUtf16();
438     handlerName[2] = handlerName[2].toUpper();
439
440     if (QQmlPropertyData **old = stringCache.value(name)) {
441         data.overrideIndexIsProperty = !(*old)->isFunction();
442         data.overrideIndex = (*old)->coreIndex;
443     }
444
445     methodIndexCache.append(data);
446     signalHandlerIndexCache.append(handler);
447
448     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
449     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
450 }
451
452 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
453                                      const QList<QByteArray> &names)
454 {
455     int argumentCount = names.count();
456
457     QQmlPropertyData data;
458     data.propType = QMetaType::QVariant;
459     data.coreIndex = coreIndex;
460
461     typedef QQmlPropertyCacheMethodArguments A;
462     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
463     args->arguments[0] = argumentCount;
464     for (int ii = 0; ii < argumentCount; ++ii)
465         args->arguments[ii + 1] = QMetaType::QVariant;
466     args->names = 0;
467     if (argumentCount)
468         args->names = new QList<QByteArray>(names);
469     args->next = argumentsCache;
470     argumentsCache = args;
471     data.arguments = args;
472
473     data.flags = flags;
474
475     QHashedString string(name);
476     if (QQmlPropertyData **old = stringCache.value(string)) {
477         data.overrideIndexIsProperty = !(*old)->isFunction();
478         data.overrideIndex = (*old)->coreIndex;
479     }
480
481     methodIndexCache.append(data);
482
483     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
484 }
485
486 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
487                                      const QList<QByteArray> &names)
488 {
489     int argumentCount = names.count();
490
491     QQmlPropertyData data;
492     data.propType = QMetaType::QVariant;
493     data.coreIndex = coreIndex;
494
495     typedef QQmlPropertyCacheMethodArguments A;
496     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
497     args->arguments[0] = argumentCount;
498     for (int ii = 0; ii < argumentCount; ++ii)
499         args->arguments[ii + 1] = QMetaType::QVariant;
500     args->names = 0;
501     if (argumentCount)
502         args->names = new QList<QByteArray>(names);
503     args->next = argumentsCache;
504     argumentsCache = args;
505     data.arguments = args;
506
507     data.flags = flags;
508
509     if (QQmlPropertyData **old = stringCache.value(name)) {
510         data.overrideIndexIsProperty = !(*old)->isFunction();
511         data.overrideIndex = (*old)->coreIndex;
512     }
513
514     methodIndexCache.append(data);
515
516     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
517 }
518
519 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
520 const QMetaObject *QQmlPropertyCache::metaObject() const
521 {
522     return _metaObject;
523 }
524
525 // Returns this property cache's metaObject, creating it if necessary.
526 const QMetaObject *QQmlPropertyCache::createMetaObject()
527 {
528     if (!_metaObject) {
529         _ownMetaObject = true;
530
531         QMetaObjectBuilder builder;
532         toMetaObjectBuilder(builder);
533         builder.setSuperClass(_parent->createMetaObject());
534         _metaObject = builder.toMetaObject();
535     }
536
537     return _metaObject;
538 }
539
540 // Returns the name of the default property for this cache
541 QString QQmlPropertyCache::defaultPropertyName() const
542 {
543     return _defaultPropertyName;
544 }
545
546 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
547 {
548     return property(defaultPropertyName());
549 }
550
551 QQmlPropertyCache *QQmlPropertyCache::parent() const
552 {
553     return _parent;
554 }
555
556 // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
557 // QML
558 const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
559 {
560     while (_parent && (_metaObject == 0 || _ownMetaObject))
561         return _parent->firstCppMetaObject();
562     return _metaObject;
563 }
564
565 QQmlPropertyCache *
566 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
567                                          QQmlPropertyData::Flag propertyFlags,
568                                          QQmlPropertyData::Flag methodFlags,
569                                          QQmlPropertyData::Flag signalFlags)
570 {
571     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
572 }
573
574 QQmlPropertyCache *
575 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
576                                          int revision,
577                                          QQmlPropertyData::Flag propertyFlags,
578                                          QQmlPropertyData::Flag methodFlags,
579                                          QQmlPropertyData::Flag signalFlags)
580 {
581     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
582
583     // Reserve enough space in the name hash for all the methods (including signals), all the
584     // signal handlers and all the properties.  This assumes no name clashes, but this is the
585     // common case.
586     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
587                                          QMetaObjectPrivate::get(metaObject)->signalCount +
588                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
589
590     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
591
592     return rv;
593 }
594
595 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
596                                        int revision, 
597                                        QQmlPropertyData::Flag propertyFlags,
598                                        QQmlPropertyData::Flag methodFlags,
599                                        QQmlPropertyData::Flag signalFlags)
600 {
601     Q_UNUSED(revision);
602     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
603
604     _metaObject = metaObject;
605
606     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
607
608     allowedRevisionCache.append(0);
609
610     int methodCount = metaObject->methodCount();
611     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
612     int signalCount = metaObjectSignalCount(metaObject);
613     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
614
615     QQmlAccessorProperties::Properties accessorProperties;
616
617     if (classInfoCount) {
618         int classInfoOffset = metaObject->classInfoOffset();
619         bool hasFastProperty = false;
620         for (int ii = 0; ii < classInfoCount; ++ii) {
621             int idx = ii + classInfoOffset;
622
623             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
624                 hasFastProperty = true;
625             } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
626                 _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
627             }
628         }
629
630         if (hasFastProperty) {
631             accessorProperties = QQmlAccessorProperties::properties(metaObject);
632             if (accessorProperties.count == 0)
633                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
634                        "installed property accessors", metaObject->className());
635         } else {
636 #ifndef QT_NO_DEBUG
637             accessorProperties = QQmlAccessorProperties::properties(metaObject);
638             if (accessorProperties.count != 0)
639                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
640                        "FastProperty class info", metaObject->className());
641 #endif
642         }
643     }
644
645     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
646     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
647     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
648     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
649
650     int methodOffset = metaObject->methodOffset();
651     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
652
653     // update() should have reserved enough space in the vector that this doesn't cause a realloc
654     // and invalidate the stringCache.
655     methodIndexCache.resize(methodCount - methodIndexCacheStart);
656     signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
657     int signalHandlerIndex = signalOffset;
658     for (int ii = methodOffset; ii < methodCount; ++ii) {
659         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
660             continue;
661         QMetaMethod m = metaObject->method(ii);
662         if (m.access() == QMetaMethod::Private) 
663             continue;
664
665         // Extract method name
666         // It's safe to keep the raw name pointer
667         Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
668         const char *rawName = m.name().constData();
669         const char *cptr = rawName;
670         char utf8 = 0;
671         while (*cptr) {
672             utf8 |= *cptr & 0x80;
673             ++cptr;
674         }
675
676         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
677         QQmlPropertyData *sigdata = 0;
678
679         data->lazyLoad(m);
680
681         if (data->isSignal())
682             data->flags |= signalFlags;
683         else
684             data->flags |= methodFlags;
685
686         if (!dynamicMetaObject)
687             data->flags |= QQmlPropertyData::IsDirect;
688
689         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
690         data->metaObjectOffset = allowedRevisionCache.count() - 1;
691
692         if (data->isSignal()) {
693             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
694             *sigdata = *data;
695             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
696         }
697
698         QQmlPropertyData *old = 0;
699
700         if (utf8) {
701             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
702             if (QQmlPropertyData **it = stringCache.value(methodName))
703                 old = *it;
704             stringCache.insert(methodName, data);
705
706             if (data->isSignal()) {
707                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
708                 stringCache.insert(on, sigdata);
709                 ++signalHandlerIndex;
710             }
711         } else {
712             QHashedCStringRef methodName(rawName, cptr - rawName);
713             if (QQmlPropertyData **it = stringCache.value(methodName))
714                 old = *it;
715             stringCache.insert(methodName, data);
716
717             if (data->isSignal()) {
718                 int length = methodName.length();
719
720                 QVarLengthArray<char, 128> str(length+3);
721                 str[0] = 'o';
722                 str[1] = 'n';
723                 str[2] = toupper(rawName[0]);
724                 if (length > 1)
725                     memcpy(&str[3], &rawName[1], length - 1);
726                 str[length + 2] = '\0';
727
728                 QHashedString on(QString::fromLatin1(str.data()));
729                 stringCache.insert(on, sigdata);
730                 ++signalHandlerIndex;
731             }
732         }
733
734         if (old) {
735             // We only overload methods in the same class, exactly like C++
736             if (old->isFunction() && old->coreIndex >= methodOffset)
737                 data->flags |= QQmlPropertyData::IsOverload;
738             data->overrideIndexIsProperty = !old->isFunction();
739             data->overrideIndex = old->coreIndex;
740         }
741     }
742
743     int propCount = metaObject->propertyCount();
744     int propOffset = metaObject->propertyOffset();
745
746     // update() should have reserved enough space in the vector that this doesn't cause a realloc
747     // and invalidate the stringCache.
748     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
749     for (int ii = propOffset; ii < propCount; ++ii) {
750         QMetaProperty p = metaObject->property(ii);
751         if (!p.isScriptable())
752             continue;
753
754         const char *str = p.name();
755         char utf8 = 0;
756         const char *cptr = str;
757         while (*cptr != 0) {
758             utf8 |= *cptr & 0x80;
759             ++cptr;
760         }
761
762         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
763
764         data->lazyLoad(p, engine);
765         data->flags |= propertyFlags;
766
767         if (!dynamicMetaObject) 
768             data->flags |= QQmlPropertyData::IsDirect;
769
770         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
771         data->metaObjectOffset = allowedRevisionCache.count() - 1;
772
773         QQmlPropertyData *old = 0;
774
775         if (utf8) {
776             QHashedString propName(QString::fromUtf8(str, cptr - str));
777             if (QQmlPropertyData **it = stringCache.value(propName))
778                 old = *it;
779             stringCache.insert(propName, data);
780         } else {
781             QHashedCStringRef propName(str, cptr - str);
782             if (QQmlPropertyData **it = stringCache.value(propName))
783                 old = *it;
784             stringCache.insert(propName, data);
785         }
786
787         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
788
789         // Fast properties may not be overrides or revisioned
790         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
791
792         if (accessorProperty) {
793             data->flags |= QQmlPropertyData::HasAccessors;
794             data->accessors = accessorProperty->accessors;
795             data->accessorData = accessorProperty->data;
796         } else if (old) {
797             data->overrideIndexIsProperty = !old->isFunction();
798             data->overrideIndex = old->coreIndex;
799         }
800     }
801 }
802
803 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
804 {
805     Q_ASSERT(data->notFullyResolved());
806
807     data->propType = QMetaType::type(data->propTypeName);
808
809     if (!data->isFunction())
810         data->flags |= flagsForPropertyType(data->propType, engine);
811
812     data->flags &= ~QQmlPropertyData::NotFullyResolved;
813 }
814
815 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
816 {
817     if (!metaObject)
818         return;
819
820     updateRecur(engine, metaObject->superClass());
821
822     append(engine, metaObject, -1);
823 }
824
825 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
826 {
827     Q_ASSERT(engine);
828     Q_ASSERT(metaObject);
829     Q_ASSERT(stringCache.isEmpty());
830
831     // Preallocate enough space in the index caches for all the properties/methods/signals that
832     // are not cached in a parent cache so that the caches never need to be reallocated as this
833     // would invalidate pointers stored in the stringCache.
834     int pc = metaObject->propertyCount();
835     int mc = metaObject->methodCount();
836     int sc = metaObjectSignalCount(metaObject);
837     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
838     methodIndexCache.reserve(mc - methodIndexCacheStart);
839     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
840
841     // Reserve enough space in the stringCache for all properties/methods/signals including those
842     // cached in a parent cache.
843     stringCache.reserve(pc + mc + sc);
844
845     updateRecur(engine,metaObject);
846 }
847
848 /*! \internal
849     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
850     This is different from QMetaMethod::methodIndex().
851 */
852 QQmlPropertyData *
853 QQmlPropertyCache::signal(int index) const
854 {
855     if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
856         return 0;
857
858     if (index < signalHandlerIndexCacheStart)
859         return _parent->signal(index);
860
861     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
862     if (rv->notFullyResolved()) resolve(rv);
863     Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
864     return rv;
865 }
866
867 int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
868 {
869     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
870         return index;
871
872     if (index < methodIndexCacheStart)
873         return _parent->methodIndexToSignalIndex(index);
874
875     return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
876 }
877
878 QQmlPropertyData *
879 QQmlPropertyCache::property(int index) const
880 {
881     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
882         return 0;
883     
884     if (index < propertyIndexCacheStart)
885         return _parent->property(index);
886
887     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
888     if (rv->notFullyResolved()) resolve(rv);
889     return rv;
890 }
891
892 QQmlPropertyData *
893 QQmlPropertyCache::method(int index) const
894 {
895     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
896         return 0;
897
898     if (index < methodIndexCacheStart)
899         return _parent->method(index);
900
901     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
902     if (rv->notFullyResolved()) resolve(rv);
903     return rv;
904 }
905
906 QQmlPropertyData *
907 QQmlPropertyCache::property(const QHashedStringRef &str) const
908 {
909     QQmlPropertyData **rv = stringCache.value(str);
910     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
911     return rv?*rv:0;
912 }
913
914 QQmlPropertyData *
915 QQmlPropertyCache::property(const QHashedCStringRef &str) const
916 {
917     QQmlPropertyData **rv = stringCache.value(str);
918     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
919     return rv?*rv:0;
920 }
921
922 QQmlPropertyData *
923 QQmlPropertyCache::property(const QString &str) const
924 {
925     QQmlPropertyData **rv = stringCache.value(str);
926     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
927     return rv?*rv:0;
928 }
929
930 QString QQmlPropertyData::name(QObject *object)
931 {
932     if (!object)
933         return QString();
934
935     return name(object->metaObject());
936 }
937
938 QString QQmlPropertyData::name(const QMetaObject *metaObject)
939 {
940     if (!metaObject || coreIndex == -1)
941         return QString();
942
943     if (flags & IsFunction) {
944         QMetaMethod m = metaObject->method(coreIndex);
945
946         return QString::fromUtf8(m.name().constData());
947     } else {
948         QMetaProperty p = metaObject->property(coreIndex);
949         return QString::fromUtf8(p.name());
950     }
951 }
952
953 QStringList QQmlPropertyCache::propertyNames() const
954 {
955     QStringList keys;
956     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
957         keys.append(iter.key());
958     return keys;
959 }
960
961 struct StaticQtMetaObject : public QObject
962 {
963     static const QMetaObject *get()
964         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
965 };
966
967 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
968 {
969     QByteArray scope;
970     QByteArray name;
971     int scopeIdx = str.lastIndexOf("::");
972     if (scopeIdx != -1) {
973         scope = str.left(scopeIdx);
974         name = str.mid(scopeIdx + 2);
975     } else { 
976         name = str;
977     }
978     const QMetaObject *meta;
979     if (scope == "Qt")
980         meta = StaticQtMetaObject::get();
981     else
982         meta = metaobj;
983     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
984         QMetaEnum m = meta->enumerator(i);
985         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
986             return QVariant::Int;
987     }
988     return type;
989 }
990
991 /*! \internal
992     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
993     This is different from QMetaMethod::methodIndex().
994 */
995 QList<QByteArray> QQmlPropertyCache::signalParameterNames(QObject *object, int index)
996 {
997     QQmlData *data = QQmlData::get(object, false);
998     if (data->propertyCache) {
999         QQmlPropertyData *p = data->propertyCache->signal(index);
1000         if (!p->hasArguments())
1001             return QList<QByteArray>();
1002     }
1003
1004     return QMetaObjectPrivate::signal(object->metaObject(), index).parameterNames();
1005 }
1006
1007 // Returns an array of the arguments for method \a index.  The first entry in the array
1008 // is the number of arguments.
1009 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
1010                                                      QVarLengthArray<int, 9> &dummy,
1011                                                      QByteArray *unknownTypeError)
1012 {
1013     Q_ASSERT(object && index >= 0);
1014
1015     QQmlData *ddata = QQmlData::get(object, false);
1016
1017     if (ddata && ddata->propertyCache) {
1018         typedef QQmlPropertyCacheMethodArguments A;
1019
1020         QQmlPropertyCache *c = ddata->propertyCache;
1021         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
1022
1023         while (index < c->methodIndexCacheStart)
1024             c = c->_parent;
1025
1026         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
1027
1028         if (rv->arguments)  
1029             return static_cast<A *>(rv->arguments)->arguments;
1030
1031         const QMetaObject *metaObject = c->createMetaObject();
1032         Q_ASSERT(metaObject);
1033         QMetaMethod m = metaObject->method(index);
1034
1035         int argc = m.parameterCount();
1036         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1037         args->arguments[0] = argc;
1038         args->names = 0;
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                 free(args);
1057                 return 0;
1058             }
1059             args->arguments[ii + 1] = type;
1060         }
1061
1062         rv->arguments = args;
1063         args->next = c->argumentsCache;
1064         c->argumentsCache = args;
1065         return static_cast<A *>(rv->arguments)->arguments;
1066
1067     } else {
1068         QMetaMethod m = object->metaObject()->method(index);
1069         int argc = m.parameterCount();
1070         dummy.resize(argc + 1);
1071         dummy[0] = argc;
1072         QList<QByteArray> argTypeNames; // Only loaded if needed
1073
1074         for (int ii = 0; ii < argc; ++ii) {
1075             int type = m.parameterType(ii);
1076             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1077             if (flags & QMetaType::IsEnumeration)
1078                 type = QVariant::Int;
1079             else if (type == QMetaType::UnknownType ||
1080                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1081                       type != qMetaTypeId<QJSValue>())) {
1082                 //the UserType clause is to catch registered QFlags)
1083                 if (argTypeNames.isEmpty())
1084                     argTypeNames = m.parameterTypes();
1085                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1086             }
1087             if (type == QMetaType::UnknownType) {
1088                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1089                 return 0;
1090             }
1091             dummy[ii + 1] = type;
1092         }
1093
1094         return dummy.data();
1095     }
1096 }
1097
1098 // Returns the return type of the method.
1099 int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
1100                                         QByteArray *unknownTypeError)
1101 {
1102     Q_ASSERT(object && data.coreIndex >= 0);
1103
1104     int type = data.propType;
1105
1106     const char *propTypeName = 0;
1107
1108     if (type == QMetaType::UnknownType) {
1109         // Find the return type name from the method info
1110         QMetaMethod m;
1111
1112         QQmlData *ddata = QQmlData::get(object, false);
1113         if (ddata && ddata->propertyCache) {
1114             QQmlPropertyCache *c = ddata->propertyCache;
1115             Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
1116
1117             while (data.coreIndex < c->methodIndexCacheStart)
1118                 c = c->_parent;
1119
1120             const QMetaObject *metaObject = c->createMetaObject();
1121             Q_ASSERT(metaObject);
1122             m = metaObject->method(data.coreIndex);
1123         } else {
1124             m = object->metaObject()->method(data.coreIndex);
1125         }
1126
1127         type = m.returnType();
1128         propTypeName = m.typeName();
1129     }
1130
1131     QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1132     if (flags & QMetaType::IsEnumeration) {
1133         type = QVariant::Int;
1134     } else if (type == QMetaType::UnknownType ||
1135                (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1136                type != qMetaTypeId<QJSValue>())) {
1137         //the UserType clause is to catch registered QFlags
1138         type = EnumType(object->metaObject(), propTypeName, type);
1139     }
1140
1141     if (type == QMetaType::UnknownType) {
1142         if (unknownTypeError) *unknownTypeError = propTypeName;
1143     }
1144
1145     return type;
1146 }
1147
1148 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1149 {
1150     Q_ASSERT(metaObject);
1151
1152     QQmlPropertyData rv;
1153     {
1154         const QMetaObject *cmo = metaObject;
1155         const QByteArray propertyName = property.toUtf8();
1156         while (cmo) {
1157             int idx = cmo->indexOfProperty(propertyName);
1158             if (idx != -1) {
1159                 QMetaProperty p = cmo->property(idx);
1160                 if (p.isScriptable()) {
1161                     rv.load(p);
1162                     return rv;
1163                 } else {
1164                     while (cmo && cmo->propertyOffset() >= idx)
1165                         cmo = cmo->superClass();
1166                 }
1167             } else {
1168                 cmo = 0;
1169             }
1170         }
1171     }
1172
1173     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1174     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1175     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1176     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1177
1178     int methodCount = metaObject->methodCount();
1179     for (int ii = methodCount - 1; ii >= 0; --ii) {
1180         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1181             continue;
1182         QMetaMethod m = metaObject->method(ii);
1183         if (m.access() == QMetaMethod::Private)
1184             continue;
1185         QString methodName = QString::fromUtf8(m.name().constData());
1186
1187         if (methodName == property) {
1188             rv.load(m);
1189             return rv;
1190         }
1191     }
1192
1193     return rv;
1194 }
1195
1196 inline const QString &qQmlPropertyCacheToString(const QString &string)
1197 {
1198     return string;
1199 }
1200
1201 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1202 {
1203     return QV8Engine::toStringStatic(string.string());
1204 }
1205
1206 template<typename T>
1207 QQmlPropertyData *
1208 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1209 {
1210     QQmlPropertyCache *cache = 0;
1211
1212     QQmlData *ddata = QQmlData::get(obj, false);
1213
1214     if (ddata && ddata->propertyCache) {
1215         cache = ddata->propertyCache;
1216     } else if (engine) {
1217         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1218         cache = ep->cache(obj);
1219         if (cache) {
1220             ddata = QQmlData::get(obj, true);
1221             cache->addref();
1222             ddata->propertyCache = cache;
1223         }
1224     }
1225
1226     QQmlPropertyData *rv = 0;
1227
1228     if (cache) {
1229         rv = cache->property(name);
1230     } else {
1231         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1232         if (local.isValid())
1233             rv = &local;
1234     }
1235
1236     return rv;
1237 }
1238
1239 QQmlPropertyData *
1240 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
1241                                     const QHashedV8String &name, QQmlPropertyData &local)
1242 {
1243     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1244 }
1245
1246 QQmlPropertyData *
1247 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1248                                     const QString &name, QQmlPropertyData &local)
1249 {
1250     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1251 }
1252
1253 static inline const QMetaObjectPrivate *priv(const uint* data)
1254 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1255
1256 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1257 {
1258     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1259 }
1260
1261 const char *QQmlPropertyCache::className() const
1262 {
1263     if (!_ownMetaObject && _metaObject)
1264         return _metaObject->className();
1265     else
1266         return _dynamicClassName.constData();
1267 }
1268
1269 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1270 {
1271     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1272                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1273         return lhs.second->coreIndex < rhs.second->coreIndex;
1274     } };
1275
1276     struct Insert { static void in(QQmlPropertyCache *This,
1277                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1278                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1279                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1280         if (data->isSignalHandler())
1281             return;
1282
1283         if (data->isFunction()) {
1284             if (data->coreIndex < This->methodIndexCacheStart)
1285                 return;
1286
1287             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1288             // Overrides can cause the entry to already exist
1289             if (!methods.contains(entry)) methods.append(entry);
1290
1291             data = This->overrideData(data);
1292             if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1293         } else {
1294             if (data->coreIndex < This->propertyIndexCacheStart)
1295                 return;
1296
1297             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1298             // Overrides can cause the entry to already exist
1299             if (!properties.contains(entry)) properties.append(entry);
1300
1301             data = This->overrideData(data);
1302             if (data) Insert::in(This, properties, methods, iter, data);
1303         }
1304
1305     } };
1306
1307     builder.setClassName(_dynamicClassName);
1308
1309     QList<QPair<QString, QQmlPropertyData *> > properties;
1310     QList<QPair<QString, QQmlPropertyData *> > methods;
1311
1312     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1313         Insert::in(this, properties, methods, iter, iter.value());
1314
1315     Q_ASSERT(properties.count() == propertyIndexCache.count());
1316     Q_ASSERT(methods.count() == methodIndexCache.count());
1317
1318     qSort(properties.begin(), properties.end(), Sort::lt);
1319     qSort(methods.begin(), methods.end(), Sort::lt);
1320
1321     for (int ii = 0; ii < properties.count(); ++ii) {
1322         QQmlPropertyData *data = properties.at(ii).second;
1323
1324         int notifierId = -1;
1325         if (data->notifyIndex != -1)
1326             notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
1327
1328         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1329                                                             QMetaType::typeName(data->propType),
1330                                                             notifierId);
1331
1332         property.setReadable(true);
1333         property.setWritable(data->isWritable());
1334         property.setResettable(data->isResettable());
1335     }
1336
1337     for (int ii = 0; ii < methods.count(); ++ii) {
1338         QQmlPropertyData *data = methods.at(ii).second;
1339
1340         QByteArray returnType;
1341         if (data->propType != 0)
1342             returnType = QMetaType::typeName(data->propType);
1343
1344         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1345
1346         QQmlPropertyCacheMethodArguments *arguments = 0;
1347         if (data->hasArguments()) {
1348             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1349
1350             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1351                 if (ii != 0) signature.append(",");
1352                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1353             }
1354         }
1355
1356         signature.append(")");
1357
1358         QMetaMethodBuilder method;
1359         if (data->isSignal()) {
1360             method = builder.addSignal(signature);
1361         } else {
1362             method = builder.addSlot(signature);
1363         }
1364         method.setAccess(QMetaMethod::Protected);
1365
1366         if (arguments && arguments->names)
1367             method.setParameterNames(*arguments->names);
1368
1369         if (!returnType.isEmpty())
1370             method.setReturnType(returnType);
1371     }
1372
1373     if (!_defaultPropertyName.isEmpty()) {
1374         QQmlPropertyData *dp = property(_defaultPropertyName);
1375         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1376             Q_ASSERT(!dp->isFunction());
1377             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1378         }
1379     }
1380 }
1381
1382 // Returns true if \a from is assignable to a property of type \a to
1383 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1384 {
1385     Q_ASSERT(!from.isNull() && !to.isNull());
1386
1387     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1388         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1389     } };
1390
1391     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1392     if (tom == &QObject::staticMetaObject) return true;
1393
1394     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1395         QQmlPropertyCache *fromp = from._m.asT1();
1396         QQmlPropertyCache *top = to._m.asT1();
1397
1398         while (fromp) {
1399             if (fromp == top) return true;
1400             fromp = fromp->parent();
1401         }
1402     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1403         QQmlPropertyCache *fromp = from._m.asT1();
1404
1405         while (fromp) {
1406             const QMetaObject *fromm = fromp->metaObject();
1407             if (fromm && I::equal(fromm, tom)) return true;
1408             fromp = fromp->parent();
1409         }
1410     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1411         const QMetaObject *fromm = from._m.asT2();
1412
1413         if (!tom) return false;
1414
1415         while (fromm) {
1416             if (I::equal(fromm, tom)) return true;
1417             fromm = fromm->superClass();
1418         }
1419     } else { // QMetaObject -> QMetaObject
1420         const QMetaObject *fromm = from._m.asT2();
1421
1422         while (fromm) {
1423             if (I::equal(fromm, tom)) return true;
1424             fromm = fromm->superClass();
1425         }
1426     }
1427
1428     return false;
1429 }
1430
1431 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1432 {
1433     if (_m.isNull()) return 0;
1434     if (_m.isT1()) return _m.asT1();
1435     else return e->cache(_m.asT2());
1436 }
1437
1438 QT_END_NAMESPACE