QtQuick: Fix warnings about unused variables.
[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 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1099 {
1100     Q_ASSERT(metaObject);
1101
1102     QQmlPropertyData rv;
1103     {
1104         const QMetaObject *cmo = metaObject;
1105         const QByteArray propertyName = property.toUtf8();
1106         while (cmo) {
1107             int idx = cmo->indexOfProperty(propertyName);
1108             if (idx != -1) {
1109                 QMetaProperty p = cmo->property(idx);
1110                 if (p.isScriptable()) {
1111                     rv.load(p);
1112                     return rv;
1113                 } else {
1114                     while (cmo && cmo->propertyOffset() >= idx)
1115                         cmo = cmo->superClass();
1116                 }
1117             } else {
1118                 cmo = 0;
1119             }
1120         }
1121     }
1122
1123     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1124     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1125     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1126     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1127
1128     int methodCount = metaObject->methodCount();
1129     for (int ii = methodCount - 1; ii >= 0; --ii) {
1130         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1131             continue;
1132         QMetaMethod m = metaObject->method(ii);
1133         if (m.access() == QMetaMethod::Private)
1134             continue;
1135         QString methodName = QString::fromUtf8(m.name().constData());
1136
1137         if (methodName == property) {
1138             rv.load(m);
1139             return rv;
1140         }
1141     }
1142
1143     return rv;
1144 }
1145
1146 inline const QString &qQmlPropertyCacheToString(const QString &string)
1147 {
1148     return string;
1149 }
1150
1151 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1152 {
1153     return QV8Engine::toStringStatic(string.string());
1154 }
1155
1156 template<typename T>
1157 QQmlPropertyData *
1158 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1159 {
1160     QQmlPropertyCache *cache = 0;
1161
1162     QQmlData *ddata = QQmlData::get(obj, false);
1163
1164     if (ddata && ddata->propertyCache) {
1165         cache = ddata->propertyCache;
1166     } else if (engine) {
1167         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1168         cache = ep->cache(obj);
1169         if (cache) {
1170             ddata = QQmlData::get(obj, true);
1171             cache->addref();
1172             ddata->propertyCache = cache;
1173         }
1174     }
1175
1176     QQmlPropertyData *rv = 0;
1177
1178     if (cache) {
1179         rv = cache->property(name);
1180     } else {
1181         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1182         if (local.isValid())
1183             rv = &local;
1184     }
1185
1186     return rv;
1187 }
1188
1189 QQmlPropertyData *
1190 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
1191                                     const QHashedV8String &name, QQmlPropertyData &local)
1192 {
1193     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1194 }
1195
1196 QQmlPropertyData *
1197 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1198                                     const QString &name, QQmlPropertyData &local)
1199 {
1200     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1201 }
1202
1203 static inline const QMetaObjectPrivate *priv(const uint* data)
1204 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1205
1206 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1207 {
1208     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1209 }
1210
1211 const char *QQmlPropertyCache::className() const
1212 {
1213     if (!_ownMetaObject && _metaObject)
1214         return _metaObject->className();
1215     else
1216         return _dynamicClassName.constData();
1217 }
1218
1219 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1220 {
1221     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1222                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1223         return lhs.second->coreIndex < rhs.second->coreIndex;
1224     } };
1225
1226     struct Insert { static void in(QQmlPropertyCache *This,
1227                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1228                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1229                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1230         if (data->isSignalHandler())
1231             return;
1232
1233         if (data->isFunction()) {
1234             if (data->coreIndex < This->methodIndexCacheStart)
1235                 return;
1236
1237             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1238             // Overrides can cause the entry to already exist
1239             if (!methods.contains(entry)) methods.append(entry);
1240
1241             data = This->overrideData(data);
1242             if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1243         } else {
1244             if (data->coreIndex < This->propertyIndexCacheStart)
1245                 return;
1246
1247             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1248             // Overrides can cause the entry to already exist
1249             if (!properties.contains(entry)) properties.append(entry);
1250
1251             data = This->overrideData(data);
1252             if (data) Insert::in(This, properties, methods, iter, data);
1253         }
1254
1255     } };
1256
1257     builder.setClassName(_dynamicClassName);
1258
1259     QList<QPair<QString, QQmlPropertyData *> > properties;
1260     QList<QPair<QString, QQmlPropertyData *> > methods;
1261
1262     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1263         Insert::in(this, properties, methods, iter, iter.value());
1264
1265     Q_ASSERT(properties.count() == propertyIndexCache.count());
1266     Q_ASSERT(methods.count() == methodIndexCache.count());
1267
1268     qSort(properties.begin(), properties.end(), Sort::lt);
1269     qSort(methods.begin(), methods.end(), Sort::lt);
1270
1271     for (int ii = 0; ii < properties.count(); ++ii) {
1272         QQmlPropertyData *data = properties.at(ii).second;
1273
1274         int notifierId = -1;
1275         if (data->notifyIndex != -1)
1276             notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
1277
1278         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1279                                                             QMetaType::typeName(data->propType),
1280                                                             notifierId);
1281
1282         property.setReadable(true);
1283         property.setWritable(data->isWritable());
1284         property.setResettable(data->isResettable());
1285     }
1286
1287     for (int ii = 0; ii < methods.count(); ++ii) {
1288         QQmlPropertyData *data = methods.at(ii).second;
1289
1290         QByteArray returnType;
1291         if (data->propType != 0)
1292             returnType = QMetaType::typeName(data->propType);
1293
1294         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1295
1296         QQmlPropertyCacheMethodArguments *arguments = 0;
1297         if (data->hasArguments()) {
1298             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1299
1300             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1301                 if (ii != 0) signature.append(",");
1302                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1303             }
1304         }
1305
1306         signature.append(")");
1307
1308         QMetaMethodBuilder method;
1309         if (data->isSignal()) {
1310             method = builder.addSignal(signature);
1311         } else {
1312             method = builder.addSlot(signature);
1313         }
1314         method.setAccess(QMetaMethod::Protected);
1315
1316         if (arguments && arguments->names)
1317             method.setParameterNames(*arguments->names);
1318
1319         if (!returnType.isEmpty())
1320             method.setReturnType(returnType);
1321     }
1322
1323     if (!_defaultPropertyName.isEmpty()) {
1324         QQmlPropertyData *dp = property(_defaultPropertyName);
1325         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1326             Q_ASSERT(!dp->isFunction());
1327             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1328         }
1329     }
1330 }
1331
1332 // Returns true if \a from is assignable to a property of type \a to
1333 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1334 {
1335     Q_ASSERT(!from.isNull() && !to.isNull());
1336
1337     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1338         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1339     } };
1340
1341     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1342     if (tom == &QObject::staticMetaObject) return true;
1343
1344     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1345         QQmlPropertyCache *fromp = from._m.asT1();
1346         QQmlPropertyCache *top = to._m.asT1();
1347
1348         while (fromp) {
1349             if (fromp == top) return true;
1350             fromp = fromp->parent();
1351         }
1352     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1353         QQmlPropertyCache *fromp = from._m.asT1();
1354
1355         while (fromp) {
1356             const QMetaObject *fromm = fromp->metaObject();
1357             if (fromm && I::equal(fromm, tom)) return true;
1358             fromp = fromp->parent();
1359         }
1360     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1361         const QMetaObject *fromm = from._m.asT2();
1362
1363         if (!tom) return false;
1364
1365         while (fromm) {
1366             if (I::equal(fromm, tom)) return true;
1367             fromm = fromm->superClass();
1368         }
1369     } else { // QMetaObject -> QMetaObject
1370         const QMetaObject *fromm = from._m.asT2();
1371
1372         while (fromm) {
1373             if (I::equal(fromm, tom)) return true;
1374             fromm = fromm->superClass();
1375         }
1376     }
1377
1378     return false;
1379 }
1380
1381 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1382 {
1383     if (_m.isNull()) return 0;
1384     if (_m.isT1()) return _m.asT1();
1385     else return e->cache(_m.asT2());
1386 }
1387
1388 QT_END_NAMESPACE