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