From 0f6551c43f12512ecd57242bead784f67d2a3fab Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Mon, 1 Feb 2010 13:54:44 +0100
Subject: [PATCH] Introduced ASTObjectValue.

---
 src/libs/qmljs/qmljsbind.cpp        |  34 ++++++-
 src/libs/qmljs/qmljsinterpreter.cpp | 139 +++++++++++++++++++---------
 src/libs/qmljs/qmljsinterpreter.h   |   4 +
 3 files changed, 131 insertions(+), 46 deletions(-)

diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 94889f637fd..a5d61af7969 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -39,6 +39,36 @@ using namespace QmlJS::Interpreter;
 
 namespace {
 
+class ASTObjectValue: public ObjectValue
+{
+    UiQualifiedId *_typeName;
+    UiObjectInitializer *_initializer;
+
+public:
+    ASTObjectValue(UiQualifiedId *typeName, UiObjectInitializer *initializer, Interpreter::Engine *engine)
+        : ObjectValue(engine), _typeName(typeName), _initializer(initializer)
+    {
+    }
+
+    virtual void processMembers(MemberProcessor *processor) const
+    {
+        if (_initializer) {
+            for (UiObjectMemberList *it = _initializer->members; it; it = it->next) {
+                UiObjectMember *member = it->member;
+                if (UiPublicMember *def = cast<UiPublicMember *>(member)) {
+                    if (def->name && def->memberType) {
+                        const QString propName = def->name->asString();
+                        const QString propType = def->memberType->asString();
+
+                        processor->processProperty(propName, engine()->defaultValueForBuiltinType(propType));
+                    }
+                }
+            }
+        }
+        ObjectValue::processMembers(processor);
+    }
+};
+
 class ASTFunctionValue: public FunctionValue
 {
     FunctionDeclaration *_ast;
@@ -175,7 +205,7 @@ ObjectValue *Bind::bindObject(UiQualifiedId *qualifiedTypeNameId, UiObjectInitia
         // Script blocks all contribute to the same scope
         parentObjectValue = switchObjectValue(_functionEnvironment);
     } else { // normal component instance
-        ObjectValue *objectValue = _interp->newObject(/*prototype =*/0);
+        ASTObjectValue *objectValue = new ASTObjectValue(qualifiedTypeNameId, initializer, _interp);
         parentObjectValue = switchObjectValue(objectValue);
         if (parentObjectValue)
             objectValue->setProperty("parent", parentObjectValue);
@@ -257,12 +287,14 @@ bool Bind::visit(UiImport *ast)
 
 bool Bind::visit(UiPublicMember *ast)
 {
+#if 0
     if (_currentObjectValue && ast->name && ast->memberType) {
         const QString propName = ast->name->asString();
         const QString propType = ast->memberType->asString();
 
         _currentObjectValue->setProperty(propName, _interp->defaultValueForBuiltinType(propType));
     }
+#endif
 
     return false;
 }
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 4b101bc5cb1..9767de7c08c 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -43,8 +43,64 @@
 
 using namespace QmlJS::Interpreter;
 
+namespace {
+
+class LookupMember: public MemberProcessor
+{
+    QString _name;
+    const Value *_value;
+
+    bool process(const QString &name, const Value *value)
+    {
+        if (_value)
+            return false;
+
+        if (name == _name) {
+            _value = value;
+            return false;
+        }
+
+        return true;
+    }
+
+public:
+    LookupMember(const QString &name)
+        : _name(name), _value(0) {}
+
+    const Value *value() const { return _value; }
+
+    virtual bool processProperty(const QString &name, const Value *value)
+    {
+        return process(name, value);
+    }
+
+    virtual bool processEnumerator(const QString &name, const Value *value)
+    {
+        return process(name, value);
+    }
+
+    virtual bool processSignal(const QString &name, const Value *value)
+    {
+        return process(name, value);
+    }
+
+    virtual bool processSlot(const QString &name, const Value *value)
+    {
+        return process(name, value);
+    }
+
+    virtual bool processGeneratedSlot(const QString &name, const Value *value)
+    {
+        return process(name, value);
+    }
+};
+
+} // end of anonymous namespace
+
 #ifndef NO_DECLARATIVE_BACKEND
 
+namespace {
+
 class MetaFunction: public FunctionValue
 {
     QMetaMethod _method;
@@ -89,6 +145,8 @@ public:
     }
 };
 
+} // end of anonymous namespace
+
 QmlObjectValue::QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName,
                                int majorVersion, int minorVersion, Engine *engine)
     : ObjectValue(engine),
@@ -104,46 +162,29 @@ QmlObjectValue::~QmlObjectValue() {}
 
 const Value *QmlObjectValue::lookupMember(const QString &name) const
 {
-    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
-        QMetaProperty prop = _metaObject->property(index);
-
-        if (name == QString::fromUtf8(prop.name()))
-            return propertyValue(prop);
-    }
-
-    for (int index = 0; index < _metaObject->methodCount(); ++index) {
-        QMetaMethod method = _metaObject->method(index);
-
-        const QString signature = QString::fromUtf8(method.signature());
-
-        const int indexOfParen = signature.indexOf(QLatin1Char('('));
-        if (indexOfParen == -1)
-            continue; // skip it, invalid signature.
-
-        const QString methodName = signature.left(indexOfParen);
+    return ObjectValue::lookupMember(name);
+}
 
-        if (methodName != name) {
-            continue;
+const Value *QmlObjectValue::findOrCreateSignature(int index, const QMetaMethod &method, QString *methodName) const
+{
+    const QString signature = QString::fromUtf8(method.signature());
 
-        } else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
-            return new MetaFunction(method, engine());
+    const int indexOfParen = signature.indexOf(QLatin1Char('('));
+    if (indexOfParen == -1)
+        return engine()->undefinedValue(); // skip it, invalid signature.
 
-        } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
-            return new MetaFunction(method, engine());
-        }
+    *methodName = signature.left(indexOfParen);
+    const Value *value = _metaSignature.value(index);
+    if (! value) {
+        value = new MetaFunction(method, engine());
+        _metaSignature.insert(index, value);
     }
-
-    return ObjectValue::lookupMember(name);
+    return value;
 }
 
 void QmlObjectValue::processMembers(MemberProcessor *processor) const
 {
-    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
-        QMetaProperty prop = _metaObject->property(index);
-
-        processor->processProperty(prop.name(), propertyValue(prop));
-    }
-
+    // process the meta enums
     for (int index = _metaObject->enumeratorOffset(); index < _metaObject->propertyCount(); ++index) {
         QMetaEnum e = _metaObject->enumerator(index);
 
@@ -152,23 +193,25 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
         }
     }
 
-    for (int index = 0; index < _metaObject->methodCount(); ++index) {
-        QMetaMethod method = _metaObject->method(index);
-
-        const QString signature = QString::fromUtf8(method.signature());
+    // process the meta properties
+    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
+        QMetaProperty prop = _metaObject->property(index);
 
-        const int indexOfParen = signature.indexOf(QLatin1Char('('));
-        if (indexOfParen == -1)
-            continue; // skip it, invalid signature.
+        processor->processProperty(prop.name(), propertyValue(prop));
+    }
 
-        const QString methodName = signature.left(indexOfParen);
+    // process the meta methods
+    for (int index = 0; index < _metaObject->methodCount(); ++index) {
+        QMetaMethod method = _metaObject->method(index);
+        QString methodName;
+        const Value *signature = findOrCreateSignature(index, method, &methodName);
 
         if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
-            processor->processSlot(methodName, engine()->undefinedValue());
+            processor->processSlot(methodName, signature);
 
         } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
             // process the signal
-            processor->processSignal(methodName, engine()->undefinedValue());
+            processor->processSignal(methodName, signature);
 
             QString slotName;
             slotName += QLatin1String("on");
@@ -176,7 +219,7 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
             slotName += methodName.midRef(1);
 
             // process the generated slot
-            processor->processGeneratedSlot(slotName, engine()->undefinedValue());
+            processor->processGeneratedSlot(slotName, signature);
         }
     }
 
@@ -599,8 +642,8 @@ const Value *Environment::lookup(const QString &name) const
         return 0;
 }
 
-const Value *Environment::lookupMember(const QString &name) const {
-    Q_UNUSED(name);
+const Value *Environment::lookupMember(const QString &) const
+{
     return 0;
 }
 
@@ -806,6 +849,12 @@ const Value *ObjectValue::lookupMember(const QString &name) const
 {
     if (const Value *m = _members.value(name))
         return m;
+    else {
+        LookupMember slowLookup(name);
+        processMembers(&slowLookup);
+        if (slowLookup.value())
+            return slowLookup.value();
+    }
 
     if (_prototype) {
         if (const Value *m = _prototype->lookup(name))
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 54251a87ff3..ba4b7606560 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -273,11 +273,15 @@ public:
     int minorVersion() const
     { return _minorVersion; }
 
+protected:
+    const Value *findOrCreateSignature(int index, const QMetaMethod &method, QString *methodName) const;
+
 private:
     const QMetaObject *_metaObject;
     QString _qmlTypeName;
     int _majorVersion;
     int _minorVersion;
+    mutable QHash<int, const Value *> _metaSignature;
 };
 
 #endif // !NO_DECLARATIVE_BACKEND
-- 
GitLab