Fix leak introduced in 0853343c33e394f35c31c161b019b2aed17f9256.
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.cpp
index 8167280..50674fa 100644 (file)
 
 #include "qqmlpropertycache_p.h"
 
-#include "qqmlengine_p.h"
-#include "qqmlbinding_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
 #include <private/qv8engine_p.h>
 
 #include <private/qmetaobject_p.h>
 #include <private/qqmlaccessors_p.h>
 #include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlrewrite_p.h>
 
 #include <QtCore/qdebug.h>
 
 #include <ctype.h> // for toupper
+#include <limits.h>
 
 #ifdef Q_CC_MSVC
 // nonstandard extension used : zero-sized array in struct/union.
@@ -65,11 +68,17 @@ QT_BEGIN_NAMESPACE
 
 #define Q_INT16_MAX 32767
 
-class QQmlPropertyCacheMethodArguments 
+class QQmlPropertyCacheMethodArguments
 {
 public:
     QQmlPropertyCacheMethodArguments *next;
 
+    //for signal handler rewrites
+    QString *signalParameterStringForJS;
+    int signalParameterCountForJS:30;
+    int parameterError:1;
+    int argumentsValid:1;
+
     QList<QByteArray> *names;
     int arguments[0];
 };
@@ -94,7 +103,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
     return flags;
 }
 
-// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
+// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
 // load
 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
 {
@@ -102,7 +111,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en
 
     QQmlPropertyData::Flags flags;
 
-    if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
+    if (propType == QMetaType::QObjectStar) {
         flags |= QQmlPropertyData::IsQObjectDerived;
     } else if (propType == QMetaType::QVariant) {
         flags |= QQmlPropertyData::IsQVariant;
@@ -114,7 +123,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en
     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
         flags |= QQmlPropertyData::IsV8Handle;
     } else {
-        QQmlMetaType::TypeCategory cat = 
+        QQmlMetaType::TypeCategory cat =
             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
                    : QQmlMetaType::typeCategory(propType);
 
@@ -146,14 +155,14 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
     Q_UNUSED(engine);
 
     coreIndex = p.propertyIndex();
-    notifyIndex = p.notifySignalIndex();
+    notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
     Q_ASSERT(p.revision() <= Q_INT16_MAX);
     revision = p.revision();
 
     flags = fastFlagsForProperty(p);
 
     int type = p.type();
-    if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
+    if (type == QMetaType::QObjectStar) {
         propType = type;
         flags |= QQmlPropertyData::IsQObjectDerived;
     } else if (type == QMetaType::QVariant) {
@@ -171,7 +180,7 @@ void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
 {
     propType = p.userType();
     coreIndex = p.propertyIndex();
-    notifyIndex = p.notifySignalIndex();
+    notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
     Q_ASSERT(p.revision() <= Q_INT16_MAX);
     revision = p.revision();
@@ -210,7 +219,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
     propType = QMetaType::Void;
 
     const char *returnType = m.typeName();
-    Q_ASSERT(returnType != 0);
+    if (!returnType)
+        returnType = "\0";
     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
         propTypeName = returnType;
         flags |= NotFullyResolved;
@@ -235,7 +245,8 @@ Creates a new empty QQmlPropertyCache.
 */
 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
-  signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+  signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+  _metaObject(0), argumentsCache(0)
 {
     Q_ASSERT(engine);
 }
@@ -245,7 +256,8 @@ Creates a new QQmlPropertyCache of \a metaObject.
 */
 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
-  signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+  signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+  _metaObject(0), argumentsCache(0)
 {
     Q_ASSERT(engine);
     Q_ASSERT(metaObject);
@@ -260,6 +272,7 @@ QQmlPropertyCache::~QQmlPropertyCache()
     QQmlPropertyCacheMethodArguments *args = argumentsCache;
     while (args) {
         QQmlPropertyCacheMethodArguments *next = args->next;
+        if (args->signalParameterStringForJS) delete args->signalParameterStringForJS;
         if (args->names) delete args->names;
         free(args);
         args = next;
@@ -328,6 +341,11 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyC
     return rv;
 }
 
+/*! \internal
+
+    \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
 void QQmlPropertyCache::appendProperty(const QString &name,
                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
 {
@@ -337,15 +355,14 @@ void QQmlPropertyCache::appendProperty(const QString &name,
     data.notifyIndex = notifyIndex;
     data.flags = flags;
 
-    QHashedString string(name);
-    if (QQmlPropertyData **old = stringCache.value(string)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int index = propertyIndexCache.count();
     propertyIndexCache.append(data);
 
-    stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+    setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
 }
 
 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
@@ -357,14 +374,14 @@ void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
     data.notifyIndex = notifyIndex;
     data.flags = flags;
 
-    if (QQmlPropertyData **old = stringCache.value(name)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int index = propertyIndexCache.count();
     propertyIndexCache.append(data);
 
-    stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+    setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
 }
 
 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
@@ -384,26 +401,31 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor
         typedef QQmlPropertyCacheMethodArguments A;
         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+        args->argumentsValid = true;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
         args->names = new QList<QByteArray>(names);
         args->next = argumentsCache;
         argumentsCache = args;
         data.arguments = args;
     }
 
-    QString handlerName = QLatin1String("on") + name;
-    handlerName[2] = handlerName[2].toUpper();
-
-    QHashedString string(name);
-    if (QQmlPropertyData **old = stringCache.value(string)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int methodIndex = methodIndexCache.count();
     methodIndexCache.append(data);
+
+    int signalHandlerIndex = signalHandlerIndexCache.count();
     signalHandlerIndexCache.append(handler);
 
-    stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
-    stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+    QString handlerName = QLatin1String("on") + name;
+    handlerName[2] = handlerName[2].toUpper();
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+    setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
 }
 
 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
@@ -423,25 +445,31 @@ void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flag
         typedef QQmlPropertyCacheMethodArguments A;
         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+        args->argumentsValid = true;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
         args->names = new QList<QByteArray>(names);
         args->next = argumentsCache;
         argumentsCache = args;
         data.arguments = args;
     }
 
-    QString handlerName = QLatin1String("on") + name.toUtf16();
-    handlerName[2] = handlerName[2].toUpper();
-
-    if (QQmlPropertyData **old = stringCache.value(name)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int methodIndex = methodIndexCache.count();
     methodIndexCache.append(data);
+
+    int signalHandlerIndex = signalHandlerIndexCache.count();
     signalHandlerIndexCache.append(handler);
 
-    stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
-    stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+    QString handlerName = QLatin1String("on") + name.toUtf16();
+    handlerName[2] = handlerName[2].toUpper();
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+    setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
 }
 
 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
@@ -458,6 +486,10 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
     args->arguments[0] = argumentCount;
     for (int ii = 0; ii < argumentCount; ++ii)
         args->arguments[ii + 1] = QMetaType::QVariant;
+    args->argumentsValid = true;
+    args->signalParameterStringForJS = 0;
+    args->signalParameterCountForJS = 0;
+    args->parameterError = false;
     args->names = 0;
     if (argumentCount)
         args->names = new QList<QByteArray>(names);
@@ -467,15 +499,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
 
     data.flags = flags;
 
-    QHashedString string(name);
-    if (QQmlPropertyData **old = stringCache.value(string)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int methodIndex = methodIndexCache.count();
     methodIndexCache.append(data);
 
-    stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
 }
 
 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
@@ -492,6 +523,10 @@ void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flag
     args->arguments[0] = argumentCount;
     for (int ii = 0; ii < argumentCount; ++ii)
         args->arguments[ii + 1] = QMetaType::QVariant;
+    args->argumentsValid = true;
+    args->signalParameterStringForJS = 0;
+    args->signalParameterCountForJS = 0;
+    args->parameterError = false;
     args->names = 0;
     if (argumentCount)
         args->names = new QList<QByteArray>(names);
@@ -501,14 +536,14 @@ void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flag
 
     data.flags = flags;
 
-    if (QQmlPropertyData **old = stringCache.value(name)) {
-        data.overrideIndexIsProperty = !(*old)->isFunction();
-        data.overrideIndex = (*old)->coreIndex;
-    }
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
 
+    int methodIndex = methodIndexCache.count();
     methodIndexCache.append(data);
 
-    stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
 }
 
 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
@@ -540,7 +575,7 @@ QString QQmlPropertyCache::defaultPropertyName() const
 
 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
 {
-    return property(defaultPropertyName());
+    return property(defaultPropertyName(), 0, 0);
 }
 
 QQmlPropertyCache *QQmlPropertyCache::parent() const
@@ -587,8 +622,8 @@ QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObje
     return rv;
 }
 
-void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
-                                       int revision, 
+void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
+                                       int revision,
                                        QQmlPropertyData::Flag propertyFlags,
                                        QQmlPropertyData::Flag methodFlags,
                                        QQmlPropertyData::Flag signalFlags)
@@ -654,7 +689,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
             continue;
         QMetaMethod m = metaObject->method(ii);
-        if (m.access() == QMetaMethod::Private) 
+        if (m.access() == QMetaMethod::Private)
             continue;
 
         // Extract method name
@@ -694,20 +729,20 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
 
         if (utf8) {
             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
-            if (QQmlPropertyData **it = stringCache.value(methodName))
-                old = *it;
-            stringCache.insert(methodName, data);
+            if (StringCache::mapped_type *it = stringCache.value(methodName))
+                old = it->second;
+            setNamedProperty(methodName, ii, data, (old != 0));
 
             if (data->isSignal()) {
                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
-                stringCache.insert(on, sigdata);
+                setNamedProperty(on, ii, sigdata, (old != 0));
                 ++signalHandlerIndex;
             }
         } else {
             QHashedCStringRef methodName(rawName, cptr - rawName);
-            if (QQmlPropertyData **it = stringCache.value(methodName))
-                old = *it;
-            stringCache.insert(methodName, data);
+            if (StringCache::mapped_type *it = stringCache.value(methodName))
+                old = it->second;
+            setNamedProperty(methodName, ii, data, (old != 0));
 
             if (data->isSignal()) {
                 int length = methodName.length();
@@ -721,7 +756,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
                 str[length + 2] = '\0';
 
                 QHashedString on(QString::fromLatin1(str.data()));
-                stringCache.insert(on, sigdata);
+                setNamedProperty(on, ii, data, (old != 0));
                 ++signalHandlerIndex;
             }
         }
@@ -730,8 +765,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
             // We only overload methods in the same class, exactly like C++
             if (old->isFunction() && old->coreIndex >= methodOffset)
                 data->flags |= QQmlPropertyData::IsOverload;
-            data->overrideIndexIsProperty = !old->isFunction();
-            data->overrideIndex = old->coreIndex;
+
+            data->markAsOverrideOf(old);
         }
     }
 
@@ -759,7 +794,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         data->lazyLoad(p, engine);
         data->flags |= propertyFlags;
 
-        if (!dynamicMetaObject) 
+        if (!dynamicMetaObject)
             data->flags |= QQmlPropertyData::IsDirect;
 
         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
@@ -769,14 +804,14 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
 
         if (utf8) {
             QHashedString propName(QString::fromUtf8(str, cptr - str));
-            if (QQmlPropertyData **it = stringCache.value(propName))
-                old = *it;
-            stringCache.insert(propName, data);
+            if (StringCache::mapped_type *it = stringCache.value(propName))
+                old = it->second;
+            setNamedProperty(propName, ii, data, (old != 0));
         } else {
             QHashedCStringRef propName(str, cptr - str);
-            if (QQmlPropertyData **it = stringCache.value(propName))
-                old = *it;
-            stringCache.insert(propName, data);
+            if (StringCache::mapped_type *it = stringCache.value(propName))
+                old = it->second;
+            setNamedProperty(propName, ii, data, (old != 0));
         }
 
         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
@@ -789,12 +824,19 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
             data->accessors = accessorProperty->accessors;
             data->accessorData = accessorProperty->data;
         } else if (old) {
-            data->overrideIndexIsProperty = !old->isFunction();
-            data->overrideIndex = old->coreIndex;
+            data->markAsOverrideOf(old);
         }
     }
 }
 
+QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
+{
+    if (p && p->notFullyResolved())
+        resolve(p);
+
+    return p;
+}
+
 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
 {
     Q_ASSERT(data->notFullyResolved());
@@ -840,18 +882,48 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject
     updateRecur(engine,metaObject);
 }
 
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QQmlPropertyData *
+QQmlPropertyCache::signal(int index, QQmlPropertyCache **c) const
+{
+    if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+        return 0;
+
+    if (index < signalHandlerIndexCacheStart)
+        return _parent->signal(index, c);
+
+    QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+    if (rv->notFullyResolved()) resolve(rv);
+    Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
+    if (c) *c = const_cast<QQmlPropertyCache *>(this);
+    return rv;
+}
+
+int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
+{
+    if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+        return index;
+
+    if (index < methodIndexCacheStart)
+        return _parent->methodIndexToSignalIndex(index);
+
+    return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
+}
+
 QQmlPropertyData *
 QQmlPropertyCache::property(int index) const
 {
     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
         return 0;
-    
+
     if (index < propertyIndexCacheStart)
         return _parent->property(index);
 
     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
-    if (rv->notFullyResolved()) resolve(rv);
-    return rv;
+    return ensureResolved(rv);
 }
 
 QQmlPropertyData *
@@ -864,32 +936,60 @@ QQmlPropertyCache::method(int index) const
         return _parent->method(index);
 
     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
-    if (rv->notFullyResolved()) resolve(rv);
-    return rv;
+    return ensureResolved(rv);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedStringRef &str) const
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    QQmlData *data = (object ? QQmlData::get(object) : 0);
+    const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0);
+    return findProperty(it, vmemo, context);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedCStringRef &str) const
+namespace {
+
+inline bool contextHasNoExtensions(QQmlContextData *context)
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    // This context has no extension if its parent is the engine's rootContext,
+    // which has children but no imports
+    return (!context->parent || !context->parent->imports);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QString &str) const
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    return (prop->isFunction() ? vmemo->methodCount()
+                               : prop->isSignalHandler() ? vmemo->signalCount()
+                                                         : vmemo->propertyCount());
+}
+
+}
+
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
+{
+    StringCache::ConstIterator end = stringCache.end();
+
+    if (it != end) {
+        if (vmemo && context && !contextHasNoExtensions(context)) {
+            // Find the highest property offset known to the supplied context
+            do {
+                if (vmemo->ctxt == context)
+                    break;
+
+                vmemo = vmemo->parentVMEMetaObject();
+            } while (vmemo);
+        }
+
+        do {
+            // Is this property available to this context?
+            const StringCache::mapped_type &property(it.value());
+            if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo)))
+                return ensureResolved(property.second);
+
+            it = stringCache.findNext(it);
+        } while (it != end);
+    }
+
+    return 0;
 }
 
 QString QQmlPropertyData::name(QObject *object)
@@ -915,10 +1015,18 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject)
     }
 }
 
+void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+{
+    overrideIndexIsProperty = !predecessor->isFunction();
+    overrideIndex = predecessor->coreIndex;
+
+    predecessor->flags |= QQmlPropertyData::IsOverridden;
+}
+
 QStringList QQmlPropertyCache::propertyNames() const
 {
     QStringList keys;
-    for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
+    for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
         keys.append(iter.key());
     return keys;
 }
@@ -937,7 +1045,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
     if (scopeIdx != -1) {
         scope = str.left(scopeIdx);
         name = str.mid(scopeIdx + 2);
-    } else { 
+    } else {
         name = str;
     }
     const QMetaObject *meta;
@@ -953,21 +1061,72 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
     return type;
 }
 
-QList<QByteArray> QQmlPropertyCache::methodParameterNames(QObject *object, int index)
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString)
 {
-    QQmlData *data = QQmlData::get(object, false);
-    if (data->propertyCache) {
-        QQmlPropertyData *p = data->propertyCache->method(index);
-        if (!p->hasArguments())
-            return QList<QByteArray>();
+    QQmlPropertyCache *c = 0;
+    QQmlPropertyData *signalData = signal(index, &c);
+    if (!signalData)
+        return QString();
+
+    typedef QQmlPropertyCacheMethodArguments A;
+
+    if (signalData->arguments) {
+        A *arguments = static_cast<A *>(signalData->arguments);
+        if (arguments->signalParameterStringForJS) {
+            if (count)
+                *count = arguments->signalParameterCountForJS;
+            if (arguments->parameterError) {
+                if (errorString)
+                    *errorString = *arguments->signalParameterStringForJS;
+                return QString();
+            }
+            return *arguments->signalParameterStringForJS;
+        }
     }
 
-    return object->metaObject()->method(index).parameterNames();
+    QList<QByteArray> parameterNameList = signalParameterNames(index);
+
+    if (!signalData->arguments) {
+        int argc = parameterNameList.count();
+        A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+        args->arguments[0] = argc;
+        args->argumentsValid = false;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
+        args->names = new QList<QByteArray>(parameterNameList);
+        signalData->arguments = args;
+        args->next = c->argumentsCache;
+        c->argumentsCache = args;
+    }
+
+    QQmlRewrite::RewriteSignalHandler rewriter;
+    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+    const QString &parameters = rewriter.createParameterString(parameterNameList,
+                                                               ep->v8engine()->illegalNames());
+
+    bool error = rewriter.hasParameterError();
+    A *arguments = static_cast<A *>(signalData->arguments);
+    arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters);
+    arguments->signalParameterCountForJS = rewriter.parameterCountForJS();
+    if (count)
+        *count = arguments->signalParameterCountForJS;
+    if (error) {
+        arguments->parameterError = true;
+        if (errorString)
+            *errorString = *arguments->signalParameterStringForJS;
+        return QString();
+    }
+    return *arguments->signalParameterStringForJS;
 }
 
 // Returns an array of the arguments for method \a index.  The first entry in the array
 // is the number of arguments.
-int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
+int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
                                                      QVarLengthArray<int, 9> &dummy,
                                                      QByteArray *unknownTypeError)
 {
@@ -986,7 +1145,7 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
 
         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
 
-        if (rv->arguments)  
+        if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid)
             return static_cast<A *>(rv->arguments)->arguments;
 
         const QMetaObject *metaObject = c->createMetaObject();
@@ -994,9 +1153,20 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
         QMetaMethod m = metaObject->method(index);
 
         int argc = m.parameterCount();
-        A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
-        args->arguments[0] = argc;
-        args->names = 0;
+        if (!rv->arguments) {
+            A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+            args->arguments[0] = argc;
+            args->argumentsValid = false;
+            args->signalParameterStringForJS = 0;
+            args->signalParameterCountForJS = 0;
+            args->parameterError = false;
+            args->names = 0;
+            rv->arguments = args;
+            args->next = c->argumentsCache;
+            c->argumentsCache = args;
+        }
+        A *args = static_cast<A *>(rv->arguments);
+
         QList<QByteArray> argTypeNames; // Only loaded if needed
 
         for (int ii = 0; ii < argc; ++ii) {
@@ -1014,15 +1184,11 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
             }
             if (type == QMetaType::UnknownType) {
                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
-                free(args);
                 return 0;
             }
             args->arguments[ii + 1] = type;
         }
-
-        rv->arguments = args;
-        args->next = c->argumentsCache;
-        c->argumentsCache = args;
+        args->argumentsValid = true;
         return static_cast<A *>(rv->arguments)->arguments;
 
     } else {
@@ -1056,6 +1222,77 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
     }
 }
 
+// Returns the return type of the method.
+int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
+                                        QByteArray *unknownTypeError)
+{
+    Q_ASSERT(object && data.coreIndex >= 0);
+
+    int type = data.propType;
+
+    const char *propTypeName = 0;
+
+    if (type == QMetaType::UnknownType) {
+        // Find the return type name from the method info
+        QMetaMethod m;
+
+        QQmlData *ddata = QQmlData::get(object, false);
+        if (ddata && ddata->propertyCache) {
+            QQmlPropertyCache *c = ddata->propertyCache;
+            Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+            while (data.coreIndex < c->methodIndexCacheStart)
+                c = c->_parent;
+
+            const QMetaObject *metaObject = c->createMetaObject();
+            Q_ASSERT(metaObject);
+            m = metaObject->method(data.coreIndex);
+        } else {
+            m = object->metaObject()->method(data.coreIndex);
+        }
+
+        type = m.returnType();
+        propTypeName = m.typeName();
+    }
+
+    QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+    if (flags & QMetaType::IsEnumeration) {
+        type = QVariant::Int;
+    } else if (type == QMetaType::UnknownType ||
+               (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+               type != qMetaTypeId<QJSValue>())) {
+        //the UserType clause is to catch registered QFlags
+        type = EnumType(object->metaObject(), propTypeName, type);
+    }
+
+    if (type == QMetaType::UnknownType) {
+        if (unknownTypeError) *unknownTypeError = propTypeName;
+    }
+
+    return type;
+}
+
+int QQmlPropertyCache::originalClone(int index)
+{
+    while (signal(index)->isCloned())
+        --index;
+    return index;
+}
+
+int QQmlPropertyCache::originalClone(QObject *object, int index)
+{
+    QQmlData *data = QQmlData::get(object, false);
+    if (data && data->propertyCache) {
+        QQmlPropertyCache *cache = data->propertyCache;
+        while (cache->signal(index)->isCloned())
+            --index;
+    } else {
+        while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
+            --index;
+    }
+    return index;
+}
+
 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
 {
     Q_ASSERT(metaObject);
@@ -1116,7 +1353,8 @@ inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
 
 template<typename T>
 QQmlPropertyData *
-qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
+                          QQmlContextData *context, QQmlPropertyData &local)
 {
     QQmlPropertyCache *cache = 0;
 
@@ -1137,7 +1375,7 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
     QQmlPropertyData *rv = 0;
 
     if (cache) {
-        rv = cache->property(name);
+        rv = cache->property(name, obj, context);
     } else {
         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
         if (local.isValid())
@@ -1148,17 +1386,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
 }
 
 QQmlPropertyData *
-QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
-                                    const QHashedV8String &name, QQmlPropertyData &local)
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
+                            QQmlContextData *context, QQmlPropertyData &local)
 {
-    return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
+    return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
 }
 
 QQmlPropertyData *
 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
-                                    const QString &name, QQmlPropertyData &local)
+                                    const QString &name, QQmlContextData *context, QQmlPropertyData &local)
 {
-    return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
+    return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
 }
 
 static inline const QMetaObjectPrivate *priv(const uint* data)
@@ -1199,9 +1437,8 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
             // Overrides can cause the entry to already exist
             if (!methods.contains(entry)) methods.append(entry);
 
-            QQmlPropertyData *olddata = data;
             data = This->overrideData(data);
-            if (data) Insert::in(This, properties, methods, iter, data);
+            if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
         } else {
             if (data->coreIndex < This->propertyIndexCacheStart)
                 return;
@@ -1210,7 +1447,6 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
             // Overrides can cause the entry to already exist
             if (!properties.contains(entry)) properties.append(entry);
 
-            QQmlPropertyData *olddata = data;
             data = This->overrideData(data);
             if (data) Insert::in(This, properties, methods, iter, data);
         }
@@ -1223,7 +1459,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
     QList<QPair<QString, QQmlPropertyData *> > methods;
 
     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
-        Insert::in(this, properties, methods, iter, iter.value());
+        Insert::in(this, properties, methods, iter, iter.value().second);
 
     Q_ASSERT(properties.count() == propertyIndexCache.count());
     Q_ASSERT(methods.count() == methodIndexCache.count());
@@ -1236,7 +1472,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
 
         int notifierId = -1;
         if (data->notifyIndex != -1)
-            notifierId = data->notifyIndex - methodIndexCacheStart;
+            notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
 
         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
                                                             QMetaType::typeName(data->propType),
@@ -1259,7 +1495,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
         QQmlPropertyCacheMethodArguments *arguments = 0;
         if (data->hasArguments()) {
             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
-
+            Q_ASSERT(arguments->argumentsValid);
             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
                 if (ii != 0) signature.append(",");
                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
@@ -1284,7 +1520,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
     }
 
     if (!_defaultPropertyName.isEmpty()) {
-        QQmlPropertyData *dp = property(_defaultPropertyName);
+        QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
             Q_ASSERT(!dp->isFunction());
             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
@@ -1292,6 +1528,23 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
     }
 }
 
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
+{
+    QQmlPropertyData *signalData = signal(index);
+    if (signalData && signalData->hasArguments()) {
+        QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments;
+        if (args && args->names)
+            return *args->names;
+        const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
+        return method.parameterNames();
+    }
+    return QList<QByteArray>();
+}
+
 // Returns true if \a from is assignable to a property of type \a to
 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
 {