From 822520c304e4c1984213b15e6cda5d71a35d5424 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 1 Jun 2010 15:10:20 +0200
Subject: [PATCH] QmlJS: Get at types defined in plugins by running qmldump on
 them.

Task-number: QTCREATORBUG-1021
Reviewed-by: Roberto Raggi
---
 src/libs/qmljs/qmljsinterpreter.cpp           | 98 ++++++++++++++-----
 src/libs/qmljs/qmljsinterpreter.h             | 35 ++++---
 src/libs/qmljs/qmljslink.cpp                  |  6 +-
 src/plugins/qmljseditor/qmljsmodelmanager.cpp |  5 +-
 src/tools/qml/qml.pro                         |  2 +
 src/tools/qml/qmldump/main.cpp                |  2 +-
 src/tools/qml/qmldump/qmldump.pro             |  4 +
 src/tools/tools.pro                           |  1 +
 8 files changed, 112 insertions(+), 41 deletions(-)
 create mode 100644 src/tools/qml/qml.pro

diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 3b50b9036d3..f585d8cc482 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -34,12 +34,14 @@
 #include "parser/qmljsast_p.h"
 
 #include <QtCore/QFile>
+#include <QtCore/QDir>
 #include <QtCore/QString>
 #include <QtCore/QStringList>
 #include <QtCore/QMetaObject>
 #include <QtCore/QMetaProperty>
 #include <QtCore/QXmlStreamReader>
 #include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
 #include <QtCore/QDebug>
 
 using namespace QmlJS::Interpreter;
@@ -334,6 +336,10 @@ public:
         , _objects(0)
     {}
 
+    QmlXmlReader(const QByteArray &data)
+        : _xml(data)
+    {}
+
     bool operator()(QMap<QString, FakeMetaObject *> *objects) {
         Q_ASSERT(objects);
         _objects = objects;
@@ -774,7 +780,7 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
     const QString typeName = prop.typeName();
 
     // ### Verify type resolving.
-    QmlObjectValue *objectValue = engine()->metaTypeSystem().staticTypeForImport(typeName);
+    QmlObjectValue *objectValue = engine()->cppQmlTypes().typeForImport(typeName);
     if (objectValue)
         return objectValue;
 
@@ -917,7 +923,10 @@ bool QmlObjectValue::hasChildInPackage() const
 {
     if (!packageName().isEmpty())
         return true;
-    foreach (const FakeMetaObject *other, MetaTypeSystem::_metaObjects) {
+    QHashIterator<QString, FakeMetaObject *> it(CppQmlTypesLoader::instance()->objects);
+    while (it.hasNext()) {
+        it.next();
+        const FakeMetaObject *other = it.value();
         if (other->packageName().isEmpty())
             continue;
         for (const FakeMetaObject *iter = other; iter; iter = iter->superClass()) {
@@ -1931,19 +1940,22 @@ const Value *Function::invoke(const Activation *activation) const
 // typing environment
 ////////////////////////////////////////////////////////////////////////////////
 
-QList<const FakeMetaObject *> MetaTypeSystem::_metaObjects;
-
-QStringList MetaTypeSystem::load(const QFileInfoList &xmlFiles)
+CppQmlTypesLoader *CppQmlTypesLoader::instance()
 {
-    QMap<QString, FakeMetaObject *> objects;
+    static CppQmlTypesLoader _instance;
+    return &_instance;
+}
 
+QStringList CppQmlTypesLoader::load(const QFileInfoList &xmlFiles)
+{
+    QMap<QString, FakeMetaObject *> newObjects;
     QStringList errorMsgs;
 
     foreach (const QFileInfo &xmlFile, xmlFiles) {
         QFile file(xmlFile.absoluteFilePath());
         if (file.open(QIODevice::ReadOnly)) {
             QmlXmlReader read(&file);
-            if (!read(&objects)) {
+            if (!read(&newObjects)) {
                 errorMsgs.append(read.errorMessage());
             }
             file.close();
@@ -1953,34 +1965,70 @@ QStringList MetaTypeSystem::load(const QFileInfoList &xmlFiles)
         }
     }
 
-    if (errorMsgs.isEmpty()) {
-        qDeleteAll(_metaObjects);
-        _metaObjects.clear();
+    if (errorMsgs.isEmpty())
+        addObjects(newObjects);
 
-        foreach (FakeMetaObject *obj, objects.values()) {
-            const QString superName = obj->superclassName();
-            if (! superName.isEmpty()) {
-                obj->setSuperclass(objects.value(superName, 0));
-            }
-            _metaObjects.append(obj);
-        }
+    return errorMsgs;
+}
+
+void CppQmlTypesLoader::loadPluginTypes(const QString &pluginPath)
+{
+    QProcess *process = new QProcess(this);
+    connect(process, SIGNAL(finished(int)), SLOT(processDone(int)));
+    QDir qmldumpExecutable(QCoreApplication::applicationDirPath());
+    process->start(qmldumpExecutable.filePath("qmldump"), QStringList(pluginPath));
+}
+
+void CppQmlTypesLoader::processDone(int exitCode)
+{
+    QMap<QString, FakeMetaObject *> newObjects;
+
+    QProcess *process = qobject_cast<QProcess *>(sender());
+    if (process && exitCode == 0) {
+        const QByteArray output = process->readAllStandardOutput();
+        QmlXmlReader read(output);
+        if (read(&newObjects))
+            addObjects(newObjects);
     }
+    process->deleteLater();
+}
 
-    return errorMsgs;
+void CppQmlTypesLoader::addObjects(QMap<QString, FakeMetaObject *> &newObjects)
+{
+    QMapIterator<QString, FakeMetaObject *> it(newObjects);
+    while (it.hasNext()) {
+        it.next();
+        FakeMetaObject *obj = it.value();
+        //if (objects.contains(it.key()))
+        //    qWarning() << "QmlJS::Interpreter::MetaTypeSystem: Found duplicate type" << it.key();
+
+        const QString superName = obj->superclassName();
+        if (! superName.isEmpty()) {
+            FakeMetaObject *superClass = objects.value(superName);
+            if (!superClass)
+                superClass = newObjects.value(superName);
+            if (superClass)
+                obj->setSuperclass(superClass);
+            //else
+            //    qWarning() << "QmlJS::Interpreter::MetaTypeSystem: Can't find superclass" << superName << "for" << it.key();
+        }
+
+        objects.insert(it.key(), obj);
+    }
 }
 
-void MetaTypeSystem::reload(Engine *interpreter)
+void CppQmlTypes::reload(Engine *interpreter)
 {
     QHash<const FakeMetaObject *, QmlObjectValue *> qmlObjects;
     _importedTypes.clear();
 
-    foreach (const FakeMetaObject *metaObject, _metaObjects) {
+    foreach (const FakeMetaObject *metaObject, CppQmlTypesLoader::instance()->objects) {
         QmlObjectValue *objectValue = new QmlObjectValue(metaObject, interpreter);
         qmlObjects.insert(metaObject, objectValue);
         _importedTypes[metaObject->packageName()].append(objectValue);
     }
 
-    foreach (const FakeMetaObject *metaObject, _metaObjects) {
+    foreach (const FakeMetaObject *metaObject, CppQmlTypesLoader::instance()->objects) {
         QmlObjectValue *objectValue = qmlObjects.value(metaObject);
         if (!objectValue)
             continue;
@@ -1988,7 +2036,7 @@ void MetaTypeSystem::reload(Engine *interpreter)
     }
 }
 
-QList<QmlObjectValue *> MetaTypeSystem::staticTypesForImport(const QString &packageName, int majorVersion, int minorVersion) const
+QList<QmlObjectValue *> CppQmlTypes::typesForImport(const QString &packageName, int majorVersion, int minorVersion) const
 {
     QMap<QString, QmlObjectValue *> objectValuesByName;
 
@@ -2014,7 +2062,7 @@ QList<QmlObjectValue *> MetaTypeSystem::staticTypesForImport(const QString &pack
     return objectValuesByName.values();
 }
 
-QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName) const
+QmlObjectValue *CppQmlTypes::typeForImport(const QString &qualifiedName) const
 {
     QString name = qualifiedName;
     QString packageName;
@@ -2045,7 +2093,7 @@ QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName
     return previousCandidate;
 }
 
-bool MetaTypeSystem::hasPackage(const QString &package) const
+bool CppQmlTypes::hasPackage(const QString &package) const
 {
     return _importedTypes.contains(package);
 }
@@ -2323,7 +2371,7 @@ Engine::Engine()
 {
     initializePrototypes();
 
-    _metaTypeSystem.reload(this);
+    _cppQmlTypes.reload(this);
 }
 
 Engine::~Engine()
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index e16f45a295c..55705801685 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -515,25 +515,38 @@ private:
 // typing environment
 ////////////////////////////////////////////////////////////////////////////////
 
-class QMLJS_EXPORT MetaTypeSystem
+class QMLJS_EXPORT CppQmlTypesLoader : public QObject
 {
-    static QList<const FakeMetaObject *> _metaObjects;
-
+    Q_OBJECT
 public:
+    static CppQmlTypesLoader *instance();
+
+    QHash<QString, FakeMetaObject *> objects;
+
     /** \return an empty list when successful, error messages otherwise. */
-    static QStringList load(const QFileInfoList &xmlFiles);
+    QStringList load(const QFileInfoList &xmlFiles);
 
+    void loadPluginTypes(const QString &pluginPath);
+
+private slots:
+    void processDone(int exitCode);
+
+private:
+    void addObjects(QMap<QString, FakeMetaObject *> &newObjects);
+};
+
+class QMLJS_EXPORT CppQmlTypes
+{
+public:
     void reload(Interpreter::Engine *interpreter);
 
-    QList<Interpreter::QmlObjectValue *> staticTypesForImport(const QString &prefix, int majorVersion, int minorVersion) const;
-    Interpreter::QmlObjectValue *staticTypeForImport(const QString &qualifiedName) const;
+    QList<Interpreter::QmlObjectValue *> typesForImport(const QString &prefix, int majorVersion, int minorVersion) const;
+    Interpreter::QmlObjectValue *typeForImport(const QString &qualifiedName) const;
 
     bool hasPackage(const QString &package) const;
 
 private:
     QHash<QString, QList<QmlObjectValue *> > _importedTypes;
-
-    friend class QmlObjectValue;
 };
 
 class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt()
@@ -683,8 +696,8 @@ public:
     QString typeId(const Value *value);
 
     // typing:
-    const MetaTypeSystem &metaTypeSystem() const
-    { return _metaTypeSystem; }
+    const CppQmlTypes &cppQmlTypes() const
+    { return _cppQmlTypes; }
 
     void registerValue(Value *value); // internal
 
@@ -732,7 +745,7 @@ private:
     ConvertToObject _convertToObject;
     TypeId _typeId;
 
-    MetaTypeSystem _metaTypeSystem;
+    CppQmlTypes _cppQmlTypes;
 };
 
 
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index ab714c54a26..b3304892f13 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -136,7 +136,7 @@ void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Pt
         return;
 
     // Add the implicitly available Script type
-    const ObjectValue *scriptValue = engine()->metaTypeSystem().staticTypeForImport("Script");
+    const ObjectValue *scriptValue = engine()->cppQmlTypes().typeForImport("Script");
     if (scriptValue)
         typeEnv->setProperty("Script", scriptValue);
 
@@ -270,8 +270,8 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A
     }
 
     // if the package is in the meta type system, use it
-    if (engine()->metaTypeSystem().hasPackage(packageName)) {
-        foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(packageName, majorVersion, minorVersion)) {
+    if (engine()->cppQmlTypes().hasPackage(packageName)) {
+        foreach (QmlObjectValue *object, engine()->cppQmlTypes().typesForImport(packageName, majorVersion, minorVersion)) {
             namespaceObject->setProperty(object->className(), object);
         }
         return;
diff --git a/src/plugins/qmljseditor/qmljsmodelmanager.cpp b/src/plugins/qmljseditor/qmljsmodelmanager.cpp
index 5151bb534ac..a418d023c93 100644
--- a/src/plugins/qmljseditor/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljseditor/qmljsmodelmanager.cpp
@@ -85,7 +85,7 @@ void ModelManager::loadQmlTypeDescriptions()
                                                              QDir::Files,
                                                              QDir::Name);
 
-    const QStringList errors = Interpreter::MetaTypeSystem::load(xmlFiles);
+    const QStringList errors = Interpreter::CppQmlTypesLoader::instance()->load(xmlFiles);
     foreach (const QString &error, errors)
         qWarning() << qPrintable(error);
 }
@@ -194,6 +194,9 @@ void ModelManager::onLibraryInfoUpdated(const QString &path, const LibraryInfo &
 {
     QMutexLocker locker(&m_mutex);
 
+    if (!_snapshot.libraryInfo(path).isValid())
+        QmlJS::Interpreter::CppQmlTypesLoader::instance()->loadPluginTypes(path);
+
     _snapshot.insertLibraryInfo(path, info);
 }
 
diff --git a/src/tools/qml/qml.pro b/src/tools/qml/qml.pro
new file mode 100644
index 00000000000..626612ba2a2
--- /dev/null
+++ b/src/tools/qml/qml.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += qmldump
diff --git a/src/tools/qml/qmldump/main.cpp b/src/tools/qml/qmldump/main.cpp
index 6bdcecf2704..65b7a9dd2ff 100644
--- a/src/tools/qml/qmldump/main.cpp
+++ b/src/tools/qml/qmldump/main.cpp
@@ -267,7 +267,7 @@ int main(int argc, char *argv[])
     importCode += "import Qt.labs.folderlistmodel 4.7;\n";
     importCode += "import org.webkit 1.0;\n";
     if (!pluginImportName.isEmpty())
-        importCode += QString("import %0 1.0;\n").arg(pluginImportName);
+        importCode += QString("import %0 1.0;\n").arg(pluginImportName).toAscii();
 
     {
         QByteArray code = importCode;
diff --git a/src/tools/qml/qmldump/qmldump.pro b/src/tools/qml/qmldump/qmldump.pro
index 1010d6c3d80..5bdb8ee15b3 100644
--- a/src/tools/qml/qmldump/qmldump.pro
+++ b/src/tools/qml/qmldump/qmldump.pro
@@ -12,3 +12,7 @@ CONFIG   -= app_bundle
 TEMPLATE = app
 
 SOURCES += main.cpp
+
+include(../../../../qtcreator.pri)
+DESTDIR = $$IDE_APP_PATH
+include(../../../rpath.pri)
diff --git a/src/tools/tools.pro b/src/tools/tools.pro
index e90b1d6e171..375a6bf8914 100644
--- a/src/tools/tools.pro
+++ b/src/tools/tools.pro
@@ -1,2 +1,3 @@
 TEMPLATE = subdirs
 win32:SUBDIRS = qtcdebugger
+SUBDIRS += qml
-- 
GitLab