diff --git a/share/qtcreator/qml/qmldump/main.cpp b/share/qtcreator/qml/qmldump/main.cpp
index 1a7a3c439f5dcbb626b3a6c2b1192e2d23230124..6f9abfea05dbd6deb2fa712ad67a8e957a3daa20 100644
--- a/share/qtcreator/qml/qmldump/main.cpp
+++ b/share/qtcreator/qml/qmldump/main.cpp
@@ -4,11 +4,8 @@
 #include <QtDeclarative/QDeclarativeView>
 
 #include <QtGui/QApplication>
-#include <QtGui/QPushButton>
 
 #include <QtCore/QSet>
-#include <QtCore/QXmlStreamWriter>
-#include <QtCore/QXmlStreamReader>
 #include <QtCore/QMetaObject>
 #include <QtCore/QMetaProperty>
 #include <QtCore/QDebug>
@@ -17,256 +14,335 @@
 
 #include <iostream>
 
+#include "qmlstreamwriter.h"
+
 #ifdef QT_SIMULATOR
 #include <QtGui/private/qsimulatorconnection_p.h>
 #endif
+
 #ifdef Q_OS_UNIX
 #include <signal.h>
 #endif
 
-static QHash<QByteArray, QList<const QDeclarativeType *> > qmlTypesByCppName;
-static QHash<QByteArray, QByteArray> cppToId;
-QString currentProperty;
-
-QByteArray convertToId(const QByteArray &cppName)
-{
-    QByteArray idName = cppToId.value(cppName, cppName);
-    idName.replace("::", ".");
-    idName.replace("/", ".");
-    return idName;
-}
-
-void erasure(QByteArray *typeName, bool *isList, bool *isPointer)
-{
-    static QByteArray declListPrefix = "QDeclarativeListProperty<";
-
-    if (typeName->endsWith('*')) {
-        *isPointer = true;
-        typeName->truncate(typeName->length() - 1);
-        erasure(typeName, isList, isPointer);
-    } else if (typeName->startsWith(declListPrefix)) {
-        *isList = true;
-        typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
-        *typeName = typeName->mid(declListPrefix.size());
-        erasure(typeName, isList, isPointer);
-    }
-
-    *typeName = convertToId(*typeName);
-}
-
-void processMetaObject(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
+void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
 {
     if (! meta || metas->contains(meta))
         return;
 
-    // dynamic meta objects break things badly
+    // dynamic meta objects break things badly, so just ignore them
     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
     if (!(mop->flags & DynamicMetaObject))
         metas->insert(meta);
 
-    processMetaObject(meta->superClass(), metas);
+    collectReachableMetaObjects(meta->superClass(), metas);
 }
 
-void processObject(QObject *object, QSet<const QMetaObject *> *metas)
+QString currentProperty;
+
+void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
 {
     if (! object)
         return;
 
     const QMetaObject *meta = object->metaObject();
     qDebug() << "Processing object" << meta->className();
-    processMetaObject(meta, metas);
+    collectReachableMetaObjects(meta, metas);
 
     for (int index = 0; index < meta->propertyCount(); ++index) {
         QMetaProperty prop = meta->property(index);
         if (QDeclarativeMetaType::isQObject(prop.userType())) {
             qDebug() << "  Processing property" << prop.name();
             currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
+
+            // if the property was not initialized during construction,
+            // accessing a member of oo is going to cause a segmentation fault
             QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
             if (oo && !metas->contains(oo->metaObject()))
-                processObject(oo, metas);
+                collectReachableMetaObjects(oo, metas);
             currentProperty.clear();
         }
     }
 }
 
-void processDeclarativeType(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
+void collectReachableMetaObjects(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
 {
-    processMetaObject(ty->metaObject(), metas);
+    collectReachableMetaObjects(ty->metaObject(), metas);
 }
 
-void writeType(QXmlStreamAttributes *attrs, QByteArray typeName, bool isWritable = false)
+/* We want to add the MetaObject for 'Qt' to the list, this is a
+   simple way to access it.
+*/
+class FriendlyQObject: public QObject
 {
-    bool isList = false, isPointer = false;
-    erasure(&typeName, &isList, &isPointer);
-    attrs->append(QXmlStreamAttribute("type", typeName));
-    if (isList)
-        attrs->append(QXmlStreamAttribute("isList", "true"));
-    if (isWritable)
-        attrs->append(QXmlStreamAttribute("isWritable", "true"));
-    if (isPointer)
-        attrs->append(QXmlStreamAttribute("isPointer", "true"));
-}
+public:
+    static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
+};
 
-void dump(const QMetaProperty &prop, QXmlStreamWriter *xml)
-{
-    xml->writeStartElement("property");
+/* When we dump a QMetaObject, we want to list all the types it is exported as.
+   To do this, we need to find the QDeclarativeTypes associated with this
+   QMetaObject.
+*/
+static QHash<QByteArray, QSet<const QDeclarativeType *> > qmlTypesByCppName;
 
-    QXmlStreamAttributes attributes;
-    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(prop.name())));
+static QHash<QByteArray, QByteArray> cppToId;
 
-    writeType(&attributes, prop.typeName(), prop.isWritable());
+/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
+   maps it to how it should appear in the description file.
 
-    xml->writeAttributes(attributes);
-    xml->writeEndElement();
+   These names need to be unique globally, so we don't change the C++ symbol's
+   name much. It is mostly used to for explicit translations such as
+   QString->string and translations for extended QML objects.
+*/
+QByteArray convertToId(const QByteArray &cppName)
+{
+    return cppToId.value(cppName, cppName);
 }
 
-void dump(const QMetaMethod &meth, QXmlStreamWriter *xml)
+QSet<const QMetaObject *> collectReachableMetaObjects(const QString &importCode, QDeclarativeEngine *engine)
 {
-    if (meth.methodType() == QMetaMethod::Signal) {
-        if (meth.access() != QMetaMethod::Protected)
-            return; // nothing to do.
-    } else if (meth.access() != QMetaMethod::Public) {
-        return; // nothing to do.
+    QSet<const QMetaObject *> metas;
+    metas.insert(FriendlyQObject::qtMeta());
+
+    QHash<QByteArray, QSet<QByteArray> > extensions;
+    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+        qmlTypesByCppName[ty->metaObject()->className()].insert(ty);
+        if (ty->isExtendedType()) {
+            extensions[ty->typeName()].insert(ty->metaObject()->className());
+        }
+        collectReachableMetaObjects(ty, &metas);
     }
 
-    QByteArray name = meth.signature();
-    int lparenIndex = name.indexOf('(');
-    if (lparenIndex == -1) {
-        return; // invalid signature
+    // Adjust ids of extended objects.
+    // The chain ends up being:
+    // __extended__.originalname - the base object
+    // __extension_0_.originalname - first extension
+    // ..
+    // __extension_n-2_.originalname - second to last extension
+    // originalname - last extension
+    // ### does this actually work for multiple extensions? it seems like the prototypes might be wrong
+    foreach (const QByteArray &extendedCpp, extensions.keys()) {
+        cppToId.remove(extendedCpp);
+        const QByteArray extendedId = convertToId(extendedCpp);
+        cppToId.insert(extendedCpp, "__extended__." + extendedId);
+        QSet<QByteArray> extensionCppNames = extensions.value(extendedCpp);
+        int c = 0;
+        foreach (const QByteArray &extensionCppName, extensionCppNames) {
+            if (c != extensionCppNames.size() - 1) {
+                QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(c), QString(extendedId)).toAscii();
+                cppToId.insert(extensionCppName, adjustedName);
+            } else {
+                cppToId.insert(extensionCppName, extendedId);
+            }
+            ++c;
+        }
     }
 
-    name = name.left(lparenIndex);
+    // find even more QMetaObjects by instantiating QML types and running
+    // over the instances
+    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+        if (ty->isExtendedType())
+            continue;
 
+        QByteArray tyName = ty->qmlTypeName();
+        tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
 
-    QString elementName = QLatin1String("method");
+        QByteArray code = importCode.toUtf8();
+        code += tyName;
+        code += " {}\n";
 
-    QXmlStreamAttributes attributes;
-    if (meth.methodType() == QMetaMethod::Signal)
-        elementName = QLatin1String("signal");
+        QDeclarativeComponent c(engine);
+        c.setData(code, QUrl("typeinstance"));
 
-    xml->writeStartElement(elementName);
+        QObject *object = c.create();
+        if (object)
+            collectReachableMetaObjects(object, &metas);
+        else
+            qDebug() << "Could not create" << tyName << ":" << c.errorString();
+    }
 
-    attributes.append(QXmlStreamAttribute("name", name));
+    return metas;
+}
 
-    const QString typeName = convertToId(meth.typeName());
-    if (! typeName.isEmpty())
-        attributes.append(QXmlStreamAttribute("type", typeName));
 
-    xml->writeAttributes(attributes);
+class Dumper
+{
+    QmlStreamWriter *qml;
+    QString relocatableModuleUri;
 
-    for (int i = 0; i < meth.parameterTypes().size(); ++i) {
-        QByteArray argName = meth.parameterNames().at(i);
+public:
+    Dumper(QmlStreamWriter *qml) : qml(qml) {}
 
-        xml->writeStartElement("param");
+    void setRelocatableModuleUri(const QString &uri)
+    {
+        relocatableModuleUri = uri;
+    }
 
-        QXmlStreamAttributes attrs;
+    void dump(const QMetaObject *meta)
+    {
+        qml->writeStartObject("Component");
 
-        if (! argName.isEmpty())
-            attrs.append(QXmlStreamAttribute("name", argName));
+        QByteArray id = convertToId(meta->className());
+        qml->writeScriptBinding(QLatin1String("name"), enquote(id));
 
-        writeType(&attrs, meth.parameterTypes().at(i));
-        xml->writeAttributes(attrs);
+        for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
+            QMetaClassInfo classInfo = meta->classInfo(index);
+            if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
+                qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
+                break;
+            }
+        }
 
-        xml->writeEndElement();
-    }
+        if (meta->superClass())
+            qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass()->className())));
+
+        QSet<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(meta->className());
+        if (!qmlTypes.isEmpty()) {
+            QStringList exports;
+
+            foreach (const QDeclarativeType *qmlTy, qmlTypes) {
+                QString qmlTyName = qmlTy->qmlTypeName();
+                if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) {
+                    qmlTyName.remove(0, relocatableModuleUri.size() + 1);
+                }
+                exports += enquote(QString("%1 %2.%3").arg(
+                                       qmlTyName,
+                                       QString::number(qmlTy->majorVersion()),
+                                       QString::number(qmlTy->minorVersion())));
+            }
 
-    xml->writeEndElement();
-}
+            // ensure exports are sorted and don't change order when the plugin is dumped again
+            exports.removeDuplicates();
+            qSort(exports);
 
-void dump(const QMetaEnum &e, QXmlStreamWriter *xml)
-{
-    xml->writeStartElement("enum");
+            qml->writeArrayBinding(QLatin1String("exports"), exports);
+        }
 
-    QXmlStreamAttributes attributes;
-    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.name()))); // ### FIXME
-    xml->writeAttributes(attributes);
+        for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
+            dump(meta->enumerator(index));
 
-    for (int index = 0; index < e.keyCount(); ++index) {
-        xml->writeStartElement("enumerator");
+        for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
+            dump(meta->property(index));
 
-        QXmlStreamAttributes attributes;
-        attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.key(index))));
-        attributes.append(QXmlStreamAttribute("value", QString::number(e.value(index))));
-        xml->writeAttributes(attributes);
+        for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
+            dump(meta->method(index));
 
-        xml->writeEndElement();
+        qml->writeEndObject();
     }
 
-    xml->writeEndElement();
-}
+    void writeEasingCurve()
+    {
+        qml->writeStartObject("Component");
+        qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve")));
+        qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QDeclarativeEasingValueType")));
+        qml->writeEndObject();
+    }
 
-class FriendlyQObject: public QObject
-{
-public:
-    static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
-};
+private:
+    static QString enquote(const QString &string)
+    {
+        return QString("\"%1\"").arg(string);
+    }
 
-void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
-{
-    QByteArray id = convertToId(meta->className());
+    /* Removes pointer and list annotations from a type name, returning
+       what was removed in isList and isPointer
+    */
+    static void removePointerAndList(QByteArray *typeName, bool *isList, bool *isPointer)
+    {
+        static QByteArray declListPrefix = "QDeclarativeListProperty<";
+
+        if (typeName->endsWith('*')) {
+            *isPointer = true;
+            typeName->truncate(typeName->length() - 1);
+            removePointerAndList(typeName, isList, isPointer);
+        } else if (typeName->startsWith(declListPrefix)) {
+            *isList = true;
+            typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
+            *typeName = typeName->mid(declListPrefix.size());
+            removePointerAndList(typeName, isList, isPointer);
+        }
 
-    xml->writeStartElement("type");
+        *typeName = convertToId(*typeName);
+    }
 
-    QXmlStreamAttributes attributes;
-    attributes.append(QXmlStreamAttribute("name", id));
+    void writeTypeProperties(QByteArray typeName, bool isWritable)
+    {
+        bool isList = false, isPointer = false;
+        removePointerAndList(&typeName, &isList, &isPointer);
+
+        qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
+        if (isList)
+            qml->writeScriptBinding(QLatin1String("isList"), QLatin1String("true"));
+        if (!isWritable)
+            qml->writeScriptBinding(QLatin1String("isReadonly"), QLatin1String("true"));
+        if (isPointer)
+            qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
+    }
 
-    for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
-        QMetaClassInfo classInfo = meta->classInfo(index);
-        if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
-            attributes.append(QXmlStreamAttribute("defaultProperty", QLatin1String(classInfo.value())));
-            break;
-        }
+    void dump(const QMetaProperty &prop)
+    {
+        qml->writeStartObject("Property");
+
+        qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
+        writeTypeProperties(prop.typeName(), prop.isWritable());
+
+        qml->writeEndObject();
     }
 
-    if (meta->superClass())
-        attributes.append(QXmlStreamAttribute("extends", convertToId(meta->superClass()->className())));
-
-    xml->writeAttributes(attributes);
-
-    QList<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(meta->className());
-    if (!qmlTypes.isEmpty()) {
-        xml->writeStartElement("exports");
-        foreach (const QDeclarativeType *qmlTy, qmlTypes) {
-            QXmlStreamAttributes moduleAttributes;
-            const QString qmlTyName = qmlTy->qmlTypeName();
-            int slashIdx = qmlTyName.lastIndexOf(QLatin1Char('/'));
-            if (slashIdx == -1)
-                continue;
-            const QString moduleName = qmlTyName.left(slashIdx);
-            const QString typeName = qmlTyName.mid(slashIdx + 1);
-            moduleAttributes.append(QXmlStreamAttribute("module", moduleName));
-            moduleAttributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
-            moduleAttributes.append(QXmlStreamAttribute("type", typeName));
-            xml->writeEmptyElement("export");
-            xml->writeAttributes(moduleAttributes);
+    void dump(const QMetaMethod &meth)
+    {
+        if (meth.methodType() == QMetaMethod::Signal) {
+            if (meth.access() != QMetaMethod::Protected)
+                return; // nothing to do.
+        } else if (meth.access() != QMetaMethod::Public) {
+            return; // nothing to do.
         }
-        xml->writeEndElement();
-    }
 
-    for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
-        dump(meta->enumerator(index), xml);
+        QByteArray name = meth.signature();
+        int lparenIndex = name.indexOf('(');
+        if (lparenIndex == -1) {
+            return; // invalid signature
+        }
+        name = name.left(lparenIndex);
+
+        if (meth.methodType() == QMetaMethod::Signal)
+            qml->writeStartObject(QLatin1String("Signal"));
+        else
+            qml->writeStartObject(QLatin1String("Method"));
 
-    for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
-        dump(meta->property(index), xml);
+        qml->writeScriptBinding(QLatin1String("name"), enquote(name));
 
-    for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
-        dump(meta->method(index), xml);
+        const QString typeName = convertToId(meth.typeName());
+        if (! typeName.isEmpty())
+            qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
 
-    xml->writeEndElement();
-}
+        for (int i = 0; i < meth.parameterTypes().size(); ++i) {
+            QByteArray argName = meth.parameterNames().at(i);
 
-void writeEasingCurve(QXmlStreamWriter *xml)
-{
-    xml->writeStartElement("type");
+            qml->writeStartObject(QLatin1String("Parameter"));
+            if (! argName.isEmpty())
+                qml->writeScriptBinding(QLatin1String("name"), enquote(argName));
+            writeTypeProperties(meth.parameterTypes().at(i), true);
+            qml->writeEndObject();
+        }
+
+        qml->writeEndObject();
+    }
+
+    void dump(const QMetaEnum &e)
     {
-        QXmlStreamAttributes attributes;
-        attributes.append(QXmlStreamAttribute("name", "QEasingCurve"));
-        attributes.append(QXmlStreamAttribute("extends", "QDeclarativeEasingValueType"));
-        xml->writeAttributes(attributes);
+        qml->writeStartObject(QLatin1String("Enum"));
+        qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name())));
+
+        QList<QPair<QString, QString> > namesValues;
+        for (int index = 0; index < e.keyCount(); ++index) {
+            namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index))));
+        }
+
+        qml->writeScriptObjectLiteralBinding(QLatin1String("values"), namesValues);
+        qml->writeEndObject();
     }
+};
 
-    xml->writeEndElement();
-}
 
 enum ExitCode {
     EXIT_INVALIDARGUMENTS = 1,
@@ -298,21 +374,29 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef QT_SIMULATOR
+    // Running this application would bring up the Qt Simulator (since it links QtGui), avoid that!
     QtSimulatorPrivate::SimulatorConnection::createStubInstance();
 #endif
     QApplication app(argc, argv);
-
-    if (argc != 1 && argc != 3) {
-        qWarning() << "Usage: qmldump [plugin/import/path plugin.uri]";
-        qWarning() << "Example: ./qmldump /home/user/dev/qt-install/imports Qt.labs.particles";
+    const QStringList args = app.arguments();
+    const QString appName = QFileInfo(app.applicationFilePath()).baseName();
+    if (args.size() != 3 && args.size() != 4 && !(args.size() == 2 && args.at(1) == QLatin1String("--builtins"))) {
+        qWarning() << qPrintable(QString(
+                                     "Usage: %1 module.uri version [module/import/path]\n"
+                                     "       %1 --builtins\n"
+                                     "Example: %1 Qt.labs.particles 4.7 /home/user/dev/qt-install/imports").arg(
+                                     appName));
         return EXIT_INVALIDARGUMENTS;
     }
 
-    QString pluginImportName;
+    QString pluginImportUri;
+    QString pluginImportVersion;
     QString pluginImportPath;
-    if (argc == 3) {
-        pluginImportPath = QString(argv[1]);
-        pluginImportName = QString(argv[2]);
+    if (args.size() > 2) {
+        pluginImportUri = args[1];
+        pluginImportVersion = args[2];
+        if (args.size() >= 4)
+            pluginImportPath = args[3];
     }
 
     QDeclarativeView view;
@@ -320,135 +404,92 @@ int main(int argc, char *argv[])
     if (!pluginImportPath.isEmpty())
         engine->addImportPath(pluginImportPath);
 
-    bool hasQtQuickModule = false;
-    {
-        QByteArray code = "import QtQuick 1.0; Item {}";
-        QDeclarativeComponent c(engine);
-        c.setData(code, QUrl("qtquickcheck"));
-        c.create();
-        if (c.errors().isEmpty()) {
-            hasQtQuickModule = true;
-        }
-    }
-
-    QByteArray importCode;
-    importCode += "import Qt 4.7;\n";
-    if (hasQtQuickModule) {
-        importCode += "import QtQuick 1.0;\n";
-    }
-    if (pluginImportName.isEmpty()) {
-        importCode += "import Qt.labs.particles 4.7;\n";
-        importCode += "import Qt.labs.gestures 4.7;\n";
-        importCode += "import Qt.labs.folderlistmodel 4.7;\n";
-        importCode += "import QtWebKit 1.0;\n";
-    } else {
-        importCode += QString("import %0 1.0;\n").arg(pluginImportName).toAscii();
-    }
-
-    {
-        QByteArray code = importCode;
-        code += "Item {}";
-        QDeclarativeComponent c(engine);
-
-        c.setData(code, QUrl("typelist"));
-        c.create();
-        if (!c.errors().isEmpty()) {
-            foreach (const QDeclarativeError &error, c.errors())
-                qWarning() << error.toString();
-            return EXIT_IMPORTERROR;
-        }
-    }
-
-    cppToId.insert("QString", "string");
-    cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
+    // find all QMetaObjects reachable from the builtin module
+    QByteArray importCode("import QtQuick 1.0\n");
+    QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(importCode, engine);
 
+    // this will hold the meta objects we want to dump information of
     QSet<const QMetaObject *> metas;
 
-    metas.insert(FriendlyQObject::qtMeta());
-
-    QHash<QByteArray, QSet<QByteArray> > extensions;
-    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
-        qmlTypesByCppName[ty->metaObject()->className()].append(ty);
-        if (ty->isExtendedType()) {
-            extensions[ty->typeName()].insert(ty->metaObject()->className());
-        } else {
-            cppToId.insert(ty->metaObject()->className(), ty->metaObject()->className());
+    if (pluginImportUri.isEmpty()) {
+        metas = defaultReachable;
+    } else {
+        // find all QMetaObjects reachable when the specified module is imported
+        importCode += QString("import %0 %1\n").arg(pluginImportUri, pluginImportVersion).toAscii();
+
+        // create a component with these imports to make sure the imports are valid
+        // and to populate the declarative meta type system
+        {
+            QByteArray code = importCode;
+            code += "QtObject {}";
+            QDeclarativeComponent c(engine);
+
+            c.setData(code, QUrl("typelist"));
+            c.create();
+            if (!c.errors().isEmpty()) {
+                foreach (const QDeclarativeError &error, c.errors())
+                    qWarning() << error.toString();
+                return EXIT_IMPORTERROR;
+            }
         }
-        processDeclarativeType(ty, &metas);
-    }
 
-    // Adjust ids of extended objects.
-    // The chain ends up being:
-    // __extended__.originalname - the base object
-    // __extension_0_.originalname - first extension
-    // ..
-    // __extension_n-2_.originalname - second to last extension
-    // originalname - last extension
-    foreach (const QByteArray &extendedCpp, extensions.keys()) {
-        const QByteArray extendedId = cppToId.value(extendedCpp);
-        cppToId.insert(extendedCpp, "__extended__." + extendedId);
-        QSet<QByteArray> extensionCppNames = extensions.value(extendedCpp);
-        int c = 0;
-        foreach (const QByteArray &extensionCppName, extensionCppNames) {
-            if (c != extensionCppNames.size() - 1) {
-                QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(c), QString(extendedId)).toAscii();
-                cppToId.insert(extensionCppName, adjustedName);
-            } else {
-                cppToId.insert(extensionCppName, extendedId);
-            }
-            ++c;
+        QSet<const QMetaObject *> candidates = collectReachableMetaObjects(importCode, engine);
+        candidates.subtract(defaultReachable);
+
+        // Also eliminate meta objects with the same classname.
+        // This is required because extended objects seem not to share
+        // a single meta object instance.
+        QSet<QByteArray> defaultReachableNames;
+        foreach (const QMetaObject *mo, defaultReachable)
+            defaultReachableNames.insert(QByteArray(mo->className()));
+        foreach (const QMetaObject *mo, candidates) {
+            if (!defaultReachableNames.contains(mo->className()))
+                metas.insert(mo);
         }
     }
 
-    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
-        if (ty->isExtendedType())
-            continue;
-
-        QByteArray tyName = ty->qmlTypeName();
-        tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
-
-        QByteArray code = importCode;
-        code += tyName;
-        code += " {}\n";
-
-        QDeclarativeComponent c(engine);
-        c.setData(code, QUrl("typeinstance"));
-
-        QObject *object = c.create();
-        if (object)
-            processObject(object, &metas);
-        else
-            qDebug() << "Could not create" << tyName << ":" << c.errorString();
-    }
+    // setup static rewrites of type names
+    cppToId.insert("QString", "string");
+    cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
 
+    // start dumping data
     QByteArray bytes;
-    QXmlStreamWriter xml(&bytes);
-    xml.setAutoFormatting(true);
+    QmlStreamWriter qml(&bytes);
 
-    xml.writeStartDocument("1.0");
-    xml.writeStartElement("module");
+    qml.writeStartDocument();
+    qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 0);
+    qml.write("\n"
+              "// This file describes the plugin-supplied types contained in the library.\n"
+              "// It is used for QML tooling purposes only.\n"
+              "\n");
+    qml.writeStartObject("Module");
 
+    // put the metaobjects into a map so they are always dumped in the same order
     QMap<QString, const QMetaObject *> nameToMeta;
-    foreach (const QMetaObject *meta, metas) {
+    foreach (const QMetaObject *meta, metas)
         nameToMeta.insert(convertToId(meta->className()), meta);
-    }
+
+    Dumper dumper(&qml);
+    dumper.setRelocatableModuleUri(pluginImportUri);
     foreach (const QMetaObject *meta, nameToMeta) {
-        dump(meta, &xml);
+        dumper.dump(meta);
     }
 
-    // define QEasingCurve as an extension of QDeclarativeEasingValueType
-    writeEasingCurve(&xml);
+    // define QEasingCurve as an extension of QDeclarativeEasingValueType, this way
+    // properties using the QEasingCurve type get useful type information.
+    if (pluginImportUri.isEmpty())
+        dumper.writeEasingCurve();
 
-    xml.writeEndElement();
-    xml.writeEndDocument();
+    qml.writeEndObject();
+    qml.writeEndDocument();
 
     std::cout << bytes.constData();
 
+    // workaround to avoid crashes on exit
     QTimer timer;
     timer.setSingleShot(true);
     timer.setInterval(0);
     QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
-
     timer.start();
 
     return app.exec();
diff --git a/share/qtcreator/qml/qmldump/qmldump.pro b/share/qtcreator/qml/qmldump/qmldump.pro
index ea1fb42c0fef522d8590e9e3623eff7e427d6135..51eb7e054b5771c0595d87ab27ea9ca5a594422d 100644
--- a/share/qtcreator/qml/qmldump/qmldump.pro
+++ b/share/qtcreator/qml/qmldump/qmldump.pro
@@ -10,7 +10,11 @@ CONFIG += console
 
 TEMPLATE = app
 
-SOURCES += main.cpp
+SOURCES += main.cpp \
+    qmlstreamwriter.cpp
 
 OTHER_FILES += Info.plist
 macx:QMAKE_INFO_PLIST = Info.plist
+
+HEADERS += \
+    qmlstreamwriter.h
diff --git a/share/qtcreator/qml/qmldump/qmlstreamwriter.cpp b/share/qtcreator/qml/qmldump/qmlstreamwriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e33a92a569e14a7316e2a1c887de1c49d757f026
--- /dev/null
+++ b/share/qtcreator/qml/qmldump/qmlstreamwriter.cpp
@@ -0,0 +1,142 @@
+#include "qmlstreamwriter.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QStringList>
+
+QmlStreamWriter::QmlStreamWriter(QByteArray *array)
+    : m_indentDepth(0)
+    , m_pendingLineLength(0)
+    , m_maybeOneline(false)
+    , m_stream(new QBuffer(array))
+{
+    m_stream->open(QIODevice::WriteOnly);
+}
+
+void QmlStreamWriter::writeStartDocument()
+{
+}
+
+void QmlStreamWriter::writeEndDocument()
+{
+}
+
+void QmlStreamWriter::writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as)
+{
+    m_stream->write(QString("import %1 %2.%3").arg(uri, QString::number(majorVersion), QString::number(minorVersion)).toUtf8());
+    if (!as.isEmpty())
+        m_stream->write(QString(" as %1").arg(as).toUtf8());
+    m_stream->write("\n");
+}
+
+void QmlStreamWriter::writeStartObject(const QString &component)
+{
+    flushPotentialLinesWithNewlines();
+    writeIndent();
+    m_stream->write(QString("%1 {").arg(component).toUtf8());
+    ++m_indentDepth;
+    m_maybeOneline = true;
+}
+
+void QmlStreamWriter::writeEndObject()
+{
+    if (m_maybeOneline && !m_pendingLines.isEmpty()) {
+        --m_indentDepth;
+        for (int i = 0; i < m_pendingLines.size(); ++i) {
+            m_stream->write(" ");
+            m_stream->write(m_pendingLines.at(i).trimmed());
+            if (i != m_pendingLines.size() - 1)
+                m_stream->write(";");
+        }
+        m_stream->write(" }\n");
+        m_pendingLines.clear();
+        m_pendingLineLength = 0;
+        m_maybeOneline = false;
+    } else {
+        if (m_maybeOneline)
+            flushPotentialLinesWithNewlines();
+        --m_indentDepth;
+        writeIndent();
+        m_stream->write("}\n");
+    }
+}
+
+void QmlStreamWriter::writeScriptBinding(const QString &name, const QString &rhs)
+{
+    writePotentialLine(QString("%1: %2").arg(name, rhs).toUtf8());
+}
+
+void QmlStreamWriter::writeArrayBinding(const QString &name, const QStringList &elements)
+{
+    flushPotentialLinesWithNewlines();
+    writeIndent();
+    m_stream->write(QString("%1: [\n").arg(name).toUtf8());
+    ++m_indentDepth;
+    for (int i = 0; i < elements.size(); ++i) {
+        writeIndent();
+        m_stream->write(elements.at(i).toUtf8());
+        if (i != elements.size() - 1) {
+            m_stream->write(",\n");
+        } else {
+            m_stream->write("\n");
+        }
+    }
+    --m_indentDepth;
+    writeIndent();
+    m_stream->write("]\n");
+}
+
+void QmlStreamWriter::write(const QString &data)
+{
+    flushPotentialLinesWithNewlines();
+    m_stream->write(data.toUtf8());
+}
+
+void QmlStreamWriter::writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue)
+{
+    flushPotentialLinesWithNewlines();
+    writeIndent();
+    m_stream->write(QString("%1: {\n").arg(name).toUtf8());
+    ++m_indentDepth;
+    for (int i = 0; i < keyValue.size(); ++i) {
+        const QString key = keyValue.at(i).first;
+        const QString value = keyValue.at(i).second;
+        writeIndent();
+        m_stream->write(QString("%1: %2").arg(key, value).toUtf8());
+        if (i != keyValue.size() - 1) {
+            m_stream->write(",\n");
+        } else {
+            m_stream->write("\n");
+        }
+    }
+    --m_indentDepth;
+    writeIndent();
+    m_stream->write("}\n");
+}
+
+void QmlStreamWriter::writeIndent()
+{
+    m_stream->write(QByteArray(m_indentDepth * 4, ' '));
+}
+
+void QmlStreamWriter::writePotentialLine(const QByteArray &line)
+{
+    m_pendingLines.append(line);
+    m_pendingLineLength += line.size();
+    if (m_pendingLineLength >= 80) {
+        flushPotentialLinesWithNewlines();
+    }
+}
+
+void QmlStreamWriter::flushPotentialLinesWithNewlines()
+{
+    if (m_maybeOneline)
+        m_stream->write("\n");
+    foreach (const QByteArray &line, m_pendingLines) {
+        writeIndent();
+        m_stream->write(line);
+        m_stream->write("\n");
+    }
+    m_pendingLines.clear();
+    m_pendingLineLength = 0;
+    m_maybeOneline = false;
+}
diff --git a/share/qtcreator/qml/qmldump/qmlstreamwriter.h b/share/qtcreator/qml/qmldump/qmlstreamwriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..74a6d501a3b07bf96588c95a6765eaa98eb84e47
--- /dev/null
+++ b/share/qtcreator/qml/qmldump/qmlstreamwriter.h
@@ -0,0 +1,38 @@
+#ifndef QMLSTREAMWRITER_H
+#define QMLSTREAMWRITER_H
+
+#include <QtCore/QIODevice>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QPair>
+
+class QmlStreamWriter
+{
+public:
+    QmlStreamWriter(QByteArray *array);
+
+    void writeStartDocument();
+    void writeEndDocument();
+    void writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as = QString());
+    //void writeFilesystemImport(const QString &file, const QString &as = QString());
+    void writeStartObject(const QString &component);
+    void writeEndObject();
+    void writeScriptBinding(const QString &name, const QString &rhs);
+    void writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue);
+    void writeArrayBinding(const QString &name, const QStringList &elements);
+    void write(const QString &data);
+
+private:
+    void writeIndent();
+    void writePotentialLine(const QByteArray &line);
+    void flushPotentialLinesWithNewlines();
+
+    int m_indentDepth;
+    QList<QByteArray> m_pendingLines;
+    int m_pendingLineLength;
+    bool m_maybeOneline;
+    QScopedPointer<QIODevice> m_stream;
+};
+
+#endif // QMLSTREAMWRITER_H