From dd1de1b82f9f8681aec14bc4266bb1d68d11c4fd Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 8 Feb 2011 11:01:37 +0100
Subject: [PATCH] qmldump: Make Creator able to read qmldump's new output.

Task-number: QTCREATORBUG-3048
---
 src/libs/languageutils/componentversion.cpp   |  25 +
 src/libs/languageutils/componentversion.h     |   2 +
 src/libs/languageutils/fakemetaobject.cpp     |  27 +-
 src/libs/languageutils/fakemetaobject.h       |  15 +-
 src/libs/qmljs/qmljs-lib.pri                  |   6 +-
 src/libs/qmljs/qmljsbind.cpp                  |   7 +-
 src/libs/qmljs/qmljsinterpreter.cpp           |   8 +-
 src/libs/qmljs/qmljsinterpreter.h             |   2 +-
 src/libs/qmljs/qmljstypedescriptionreader.cpp | 448 ++++++++++++++++++
 src/libs/qmljs/qmljstypedescriptionreader.h   |  53 +++
 src/plugins/qmljstools/qmljsmodelmanager.cpp  |   2 +-
 11 files changed, 577 insertions(+), 18 deletions(-)
 create mode 100644 src/libs/qmljs/qmljstypedescriptionreader.cpp
 create mode 100644 src/libs/qmljs/qmljstypedescriptionreader.h

diff --git a/src/libs/languageutils/componentversion.cpp b/src/libs/languageutils/componentversion.cpp
index ebab885ad67..94e6037030f 100644
--- a/src/libs/languageutils/componentversion.cpp
+++ b/src/libs/languageutils/componentversion.cpp
@@ -33,6 +33,8 @@
 
 #include "componentversion.h"
 
+#include <QtCore/QString>
+
 using namespace LanguageUtils;
 
 const int ComponentVersion::NoVersion = -1;
@@ -47,6 +49,23 @@ ComponentVersion::ComponentVersion(int major, int minor)
 {
 }
 
+ComponentVersion::ComponentVersion(const QString &versionString)
+    : _major(NoVersion), _minor(NoVersion)
+{
+    int dotIdx = versionString.indexOf(QLatin1Char('.'));
+    if (dotIdx == -1)
+        return;
+    bool ok = false;
+    int maybeMajor = versionString.left(dotIdx).toInt(&ok);
+    if (!ok)
+        return;
+    int maybeMinor = versionString.mid(dotIdx + 1).toInt(&ok);
+    if (!ok)
+        return;
+    _major = maybeMajor;
+    _minor = maybeMinor;
+}
+
 ComponentVersion::~ComponentVersion()
 {
 }
@@ -56,6 +75,12 @@ bool ComponentVersion::isValid() const
     return _major >= 0 && _minor >= 0;
 }
 
+QString ComponentVersion::toString() const
+{
+    return QString("%1.%2").arg(QString::number(_major),
+                                QString::number(_minor));
+}
+
 namespace LanguageUtils {
 
 bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
diff --git a/src/libs/languageutils/componentversion.h b/src/libs/languageutils/componentversion.h
index d19a9689375..21a7265e32c 100644
--- a/src/libs/languageutils/componentversion.h
+++ b/src/libs/languageutils/componentversion.h
@@ -48,6 +48,7 @@ public:
 
     ComponentVersion();
     ComponentVersion(int major, int minor);
+    explicit ComponentVersion(const QString &versionString);
     ~ComponentVersion();
 
     int majorVersion() const
@@ -56,6 +57,7 @@ public:
     { return _minor; }
 
     bool isValid() const;
+    QString toString() const;
 };
 
 bool LANGUAGEUTILS_EXPORT operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
diff --git a/src/libs/languageutils/fakemetaobject.cpp b/src/libs/languageutils/fakemetaobject.cpp
index 1e22ecb19aa..f9f51c7236a 100644
--- a/src/libs/languageutils/fakemetaobject.cpp
+++ b/src/libs/languageutils/fakemetaobject.cpp
@@ -35,6 +35,9 @@
 
 using namespace LanguageUtils;
 
+FakeMetaEnum::FakeMetaEnum()
+{}
+
 FakeMetaEnum::FakeMetaEnum(const QString &name)
     : m_name(name)
 {}
@@ -42,6 +45,9 @@ FakeMetaEnum::FakeMetaEnum(const QString &name)
 QString FakeMetaEnum::name() const
 { return m_name; }
 
+void FakeMetaEnum::setName(const QString &name)
+{ m_name = name; }
+
 void FakeMetaEnum::addKey(const QString &key, int value)
 { m_keys.append(key); m_values.append(value); }
 
@@ -61,9 +67,20 @@ FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
     , m_methodAccess(FakeMetaMethod::Public)
 {}
 
+FakeMetaMethod::FakeMetaMethod()
+    : m_methodTy(FakeMetaMethod::Method)
+    , m_methodAccess(FakeMetaMethod::Public)
+{}
+
 QString FakeMetaMethod::methodName() const
 { return m_name; }
 
+void FakeMetaMethod::setMethodName(const QString &name)
+{ m_name = name; }
+
+void FakeMetaMethod::setReturnType(const QString &type)
+{ m_returnType = type; }
+
 QStringList FakeMetaMethod::parameterNames() const
 { return m_paramNames; }
 
@@ -108,16 +125,20 @@ FakeMetaObject::FakeMetaObject()
 {
 }
 
+QString FakeMetaObject::className() const
+{ return m_className; }
+void FakeMetaObject::setClassName(const QString &name)
+{ m_className = name; }
+
 void FakeMetaObject::addExport(const QString &name, const QString &package, ComponentVersion version)
 {
     Export exp;
     exp.type = name;
     exp.package = package;
     exp.version = version;
-    exp.packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg(
+    exp.packageNameVersion = QString::fromLatin1("%1.%2 %3").arg(
                 package, name,
-                QString::number(version.majorVersion()),
-                QString::number(version.minorVersion()));
+                version.toString());
     m_exports.append(exp);
 }
 QList<FakeMetaObject::Export> FakeMetaObject::exports() const
diff --git a/src/libs/languageutils/fakemetaobject.h b/src/libs/languageutils/fakemetaobject.h
index 60f77aee207..4449a1e27e6 100644
--- a/src/libs/languageutils/fakemetaobject.h
+++ b/src/libs/languageutils/fakemetaobject.h
@@ -51,9 +51,11 @@ class LANGUAGEUTILS_EXPORT FakeMetaEnum {
     QList<int> m_values;
 
 public:
-    FakeMetaEnum(const QString &name);
+    FakeMetaEnum();
+    explicit FakeMetaEnum(const QString &name);
 
     QString name() const;
+    void setName(const QString &name);
 
     void addKey(const QString &key, int value);
     QString key(int index) const;
@@ -76,9 +78,14 @@ public:
     };
 
 public:
-    FakeMetaMethod(const QString &name, const QString &returnType = QString());
+    FakeMetaMethod();
+    explicit FakeMetaMethod(const QString &name, const QString &returnType = QString());
 
     QString methodName() const;
+    void setMethodName(const QString &name);
+
+    void setReturnType(const QString &type);
+
     QStringList parameterNames() const;
     QStringList parameterTypes() const;
     void addParameter(const QString &name, const QString &type);
@@ -131,6 +138,7 @@ public:
     };
 
 private:
+    QString m_className;
     QList<Export> m_exports;
     ConstPtr m_super;
     QString m_superName;
@@ -144,6 +152,9 @@ private:
 public:
     FakeMetaObject();
 
+    QString className() const;
+    void setClassName(const QString &name);
+
     void addExport(const QString &name, const QString &package, ComponentVersion version);
     QList<Export> exports() const;
 
diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri
index b4e4b5810aa..7bd069c63ac 100644
--- a/src/libs/qmljs/qmljs-lib.pri
+++ b/src/libs/qmljs/qmljs-lib.pri
@@ -27,7 +27,8 @@ HEADERS += \
     $$PWD/qmljspropertyreader.h \
     $$PWD/qmljsrewriter.h \
     $$PWD/qmljsicons.h \
-    $$PWD/qmljsdelta.h
+    $$PWD/qmljsdelta.h \
+    $$PWD/qmljstypedescriptionreader.h
 
 SOURCES += \
     $$PWD/qmljsbind.cpp \
@@ -45,7 +46,8 @@ SOURCES += \
     $$PWD/qmljspropertyreader.cpp \
     $$PWD/qmljsrewriter.cpp \
     $$PWD/qmljsicons.cpp \
-    $$PWD/qmljsdelta.cpp
+    $$PWD/qmljsdelta.cpp \
+    $$PWD/qmljstypedescriptionreader.cpp
 
 RESOURCES += \
     $$PWD/qmljs.qrc
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 0ed4ea5e8da..073d9b69337 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -254,11 +254,8 @@ bool Bind::visit(UiImport *ast)
 
     if (ast->versionToken.isValid()) {
         const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
-        const int dotIdx = versionString.indexOf(QLatin1Char('.'));
-        if (dotIdx != -1) {
-            version = ComponentVersion(versionString.left(dotIdx).toInt(),
-                                       versionString.mid(dotIdx + 1).toInt());
-        } else {
+        version = ComponentVersion(versionString);
+        if (!version.isValid()) {
             _diagnosticMessages->append(
                         errorMessage(ast->versionToken, tr("expected two numbers separated by a dot")));
         }
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 034b8f82189..2e540f37b70 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -1945,7 +1945,7 @@ const Value *Function::invoke(const Activation *activation) const
 
 QList<FakeMetaObject::ConstPtr> CppQmlTypesLoader::builtinObjects;
 
-QStringList CppQmlTypesLoader::load(const QFileInfoList &xmlFiles)
+QStringList CppQmlTypesLoader::loadXml(const QFileInfoList &xmlFiles)
 {
     QMap<QString, FakeMetaObject::Ptr> newObjects;
     QStringList errorMsgs;
@@ -2117,10 +2117,10 @@ bool CppQmlTypes::hasPackage(const QString &package) const
 
 QString CppQmlTypes::qualifiedName(const QString &package, const QString &type, ComponentVersion version)
 {
-    return QString("%1.%2 %3.%4").arg(
+    return QString("%1.%2 %3").arg(
                 package, type,
-                QString::number(version.majorVersion()),
-                QString::number(version.minorVersion()));
+                version.toString());
+
 }
 
 QmlObjectValue *CppQmlTypes::typeByQualifiedName(const QString &name) const
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index d80ecddd61b..2090dc71db0 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -585,7 +585,7 @@ class QMLJS_EXPORT CppQmlTypesLoader
 {
 public:
     /** \return an empty list when successful, error messages otherwise. */
-    static QStringList load(const QFileInfoList &xmlFiles);
+    static QStringList loadXml(const QFileInfoList &xmlFiles);
     static QList<LanguageUtils::FakeMetaObject::ConstPtr> builtinObjects;
 
     // parses the xml string and fills the newObjects map
diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp
new file mode 100644
index 00000000000..0c2b5f318a7
--- /dev/null
+++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp
@@ -0,0 +1,448 @@
+#include "qmljstypedescriptionreader.h"
+
+#include "parser/qmljsparser_p.h"
+#include "parser/qmljslexer_p.h"
+#include "parser/qmljsengine_p.h"
+#include "parser/qmljsnodepool_p.h"
+#include "parser/qmljsast_p.h"
+#include "parser/qmljsastvisitor_p.h"
+
+#include "qmljsbind.h"
+
+#include <QtCore/QIODevice>
+#include <QtCore/QBuffer>
+
+using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace LanguageUtils;
+
+TypeDescriptionReader::TypeDescriptionReader(const QString &data)
+    : _source(data)
+    , _objects(0)
+{
+}
+
+TypeDescriptionReader::~TypeDescriptionReader()
+{
+}
+
+bool TypeDescriptionReader::operator()(QMap<QString, FakeMetaObject::Ptr> *objects)
+{
+    QString fileName("typeDescription");
+    Engine engine;
+    NodePool pool(fileName, &engine);
+
+    Lexer lexer(&engine);
+    Parser parser(&engine);
+
+    lexer.setCode(_source, /*line = */ 1);
+
+    if (!parser.parse()) {
+        _errorMessage = QString("%1:%2: %3").arg(
+                    QString::number(parser.errorLineNumber()),
+                    QString::number(parser.errorColumnNumber()),
+                    parser.errorMessage());
+        return false;
+    }
+
+    _objects = objects;
+    readDocument(parser.ast());
+
+    return _errorMessage.isEmpty();
+}
+
+QString TypeDescriptionReader::errorMessage() const
+{
+    return _errorMessage;
+}
+
+void TypeDescriptionReader::readDocument(UiProgram *ast)
+{
+    if (!ast) {
+        addError(SourceLocation(), "Could not parse document");
+        return;
+    }
+
+    if (!ast->imports || ast->imports->next) {
+        addError(SourceLocation(), "Expected a single import");
+        return;
+    }
+
+    UiImport *import = ast->imports->import;
+    if (Bind::toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
+        addError(import->importToken, "Expected import of QtQuick.tooling");
+        return;
+    }
+
+    ComponentVersion version;
+    const QString versionString = _source.mid(import->versionToken.offset, import->versionToken.length);
+    const int dotIdx = versionString.indexOf(QLatin1Char('.'));
+    if (dotIdx != -1) {
+        version = ComponentVersion(versionString.left(dotIdx).toInt(),
+                                   versionString.mid(dotIdx + 1).toInt());
+    }
+    if (version != ComponentVersion(1, 0)) {
+        addError(import->versionToken, "Expected version 1.0");
+        return;
+    }
+
+    if (!ast->members || !ast->members->member || ast->members->next) {
+        addError(SourceLocation(), "Expected document to contain a single object definition");
+        return;
+    }
+
+    UiObjectDefinition *module = dynamic_cast<UiObjectDefinition *>(ast->members->member);
+    if (!module) {
+        addError(SourceLocation(), "Expected document to contain a single object definition");
+        return;
+    }
+
+    if (Bind::toString(module->qualifiedTypeNameId) != "Module") {
+        addError(SourceLocation(), "Expected document to contain a Module {} member");
+        return;
+    }
+
+    readModule(module);
+}
+
+void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
+{
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
+        if (!component || Bind::toString(component->qualifiedTypeNameId) != "Component") {
+            addError(member->firstSourceLocation(), "Expected only 'Component' object definitions");
+            return;
+        }
+
+        readComponent(component);
+    }
+}
+
+void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
+{
+    _errorMessage += QString("%1:%2: %3\n").arg(
+                QString::number(loc.startLine),
+                QString::number(loc.startColumn),
+                message);
+}
+
+void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
+{
+    FakeMetaObject::Ptr fmo(new FakeMetaObject);
+
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
+        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
+        if (component) {
+            QString name = Bind::toString(component->qualifiedTypeNameId);
+            if (name == "Property") {
+                readProperty(component, fmo);
+            } else if (name == "Method" || name == "Signal") {
+                readSignalOrMethod(component, name == "Method", fmo);
+            } else if (name == "Enum") {
+                readEnum(component, fmo);
+            } else {
+                addError(component->firstSourceLocation(), "Expected only Property, Method, Signal and Enum object definitions");
+                return;
+            }
+        } else if (script) {
+            QString name = Bind::toString(script->qualifiedId);
+            if (name == "name") {
+                fmo->setClassName(readStringBinding(script));
+            } else if (name == "prototype") {
+                fmo->setSuperclassName(readStringBinding(script));
+            } else if (name == "defaultProperty") {
+                fmo->setDefaultPropertyName(readStringBinding(script));
+            } else if (name == "exports") {
+                readExports(script, fmo);
+            } else {
+                addError(script->firstSourceLocation(), "Expected only name, prototype, defaultProperty and exports script bindings");
+                return;
+            }
+        } else {
+            addError(member->firstSourceLocation(), "Expected only script bindings and object definitions");
+            return;
+        }
+    }
+
+    if (fmo->className().isEmpty()) {
+        addError(ast->firstSourceLocation(), "Component definition is missing a name binding");
+        return;
+    }
+
+    _objects->insert(fmo->className(), fmo);
+}
+
+void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
+{
+    FakeMetaMethod fmm;
+    // ### confusion between Method and Slot. Method should be removed.
+    if (isMethod)
+        fmm.setMethodType(FakeMetaMethod::Slot);
+    else
+        fmm.setMethodType(FakeMetaMethod::Signal);
+
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
+        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
+        if (component) {
+            QString name = Bind::toString(component->qualifiedTypeNameId);
+            if (name == "Parameter") {
+                readParameter(component, &fmm);
+            } else {
+                addError(component->firstSourceLocation(), "Expected only Parameter object definitions");
+                return;
+            }
+        } else if (script) {
+            QString name = Bind::toString(script->qualifiedId);
+            if (name == "name") {
+                fmm.setMethodName(readStringBinding(script));
+            } else if (name == "type") {
+                fmm.setReturnType(readStringBinding(script));
+            } else {
+                addError(script->firstSourceLocation(), "Expected only name and type script bindings");
+                return;
+            }
+
+        } else {
+            addError(member->firstSourceLocation(), "Expected only script bindings and object definitions");
+            return;
+        }
+    }
+
+    if (fmm.methodName().isEmpty()) {
+        addError(ast->firstSourceLocation(), "Method or Signal is missing a name script binding");
+        return;
+    }
+
+    fmo->addMethod(fmm);
+}
+
+void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+{
+    QString name;
+    QString type;
+    bool isPointer = false;
+    bool isReadonly = false;
+    bool isList = false;
+
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
+        if (!script) {
+            addError(member->firstSourceLocation(), "Expected script binding");
+            return;
+        }
+
+        QString id = Bind::toString(script->qualifiedId);
+        if (id == "name") {
+            name = readStringBinding(script);
+        } else if (id == "type") {
+            type = readStringBinding(script);
+        } else if (id == "isPointer") {
+            isPointer = readBoolBinding(script);
+        } else if (id == "isReadonly") {
+            isReadonly = readBoolBinding(script);
+        } else if (id == "isList") {
+            isList = readBoolBinding(script);
+        } else {
+            addError(script->firstSourceLocation(), "Expected only type, name, isPointer, isReadonly and isList script bindings");
+            return;
+        }
+    }
+
+    if (name.isEmpty() || type.isEmpty()) {
+        addError(ast->firstSourceLocation(), "Property object is missing a name or type script binding");
+        return;
+    }
+
+    fmo->addProperty(FakeMetaProperty(name, type, isList, !isReadonly, isPointer));
+}
+
+void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+{
+    FakeMetaEnum fme;
+
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
+        if (!script) {
+            addError(member->firstSourceLocation(), "Expected script binding");
+            return;
+        }
+
+        QString name = Bind::toString(script->qualifiedId);
+        if (name == "name") {
+            fme.setName(readStringBinding(script));
+        } else if (name == "values") {
+            readEnumValues(script, &fme);
+        } else {
+            addError(script->firstSourceLocation(), "Expected only name and values script bindings");
+            return;
+        }
+    }
+
+    fmo->addEnum(fme);
+}
+
+void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMethod *fmm)
+{
+    QString name;
+    QString type;
+
+    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+        UiObjectMember *member = it->member;
+        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
+        if (!script) {
+            addError(member->firstSourceLocation(), "Expected script binding");
+            return;
+        }
+
+        QString id = Bind::toString(script->qualifiedId);
+        if (id == "name") {
+            id = readStringBinding(script);
+        } else if (id == "type") {
+            type = readStringBinding(script);
+        } else if (id == "isPointer") {
+            // ### unhandled
+        } else if (id == "isReadonly") {
+            // ### unhandled
+        } else if (id == "isList") {
+            // ### unhandled
+        } else {
+            addError(script->firstSourceLocation(), "Expected only name and type script bindings");
+            return;
+        }
+    }
+
+    fmm->addParameter(name, type);
+}
+
+QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
+{
+    if (!ast || !ast->statement) {
+        addError(ast->colonToken, "Expected string after colon");
+        return QString();
+    }
+
+    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
+    if (!expStmt) {
+        addError(ast->statement->firstSourceLocation(), "Expected string after colon");
+        return QString();
+    }
+
+    StringLiteral *stringLit = dynamic_cast<StringLiteral *>(expStmt->expression);
+    if (!stringLit) {
+        addError(expStmt->firstSourceLocation(), "Expected string after colon");
+        return QString();
+    }
+
+    return stringLit->value->asString();
+}
+
+bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
+{
+    if (!ast || !ast->statement) {
+        addError(ast->colonToken, "Expected boolean after colon");
+        return false;
+    }
+
+    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
+    if (!expStmt) {
+        addError(ast->statement->firstSourceLocation(), "Expected boolean after colon");
+        return false;
+    }
+
+    TrueLiteral *trueLit = dynamic_cast<TrueLiteral *>(expStmt->expression);
+    FalseLiteral *falseLit = dynamic_cast<FalseLiteral *>(expStmt->expression);
+    if (!trueLit && !falseLit) {
+        addError(expStmt->firstSourceLocation(), "Expected true or false after colon");
+        return false;
+    }
+
+    return trueLit;
+}
+
+void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+{
+    if (!ast || !ast->statement) {
+        addError(ast->colonToken, "Expected array of strings after colon");
+        return;
+    }
+
+    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
+    if (!expStmt) {
+        addError(ast->statement->firstSourceLocation(), "Expected array of strings after colon");
+        return;
+    }
+
+    ArrayLiteral *arrayLit = dynamic_cast<ArrayLiteral *>(expStmt->expression);
+    if (!arrayLit) {
+        addError(expStmt->firstSourceLocation(), "Expected array of strings after colon");
+        return;
+    }
+
+    for (ElementList *it = arrayLit->elements; it; it = it->next) {
+        StringLiteral *stringLit = dynamic_cast<StringLiteral *>(it->expression);
+        if (!stringLit) {
+            addError(arrayLit->firstSourceLocation(), "Expected array literal with only string literal members");
+            return;
+        }
+        QString exp = stringLit->value->asString();
+        int slashIdx = exp.indexOf(QLatin1Char('/'));
+        int spaceIdx = exp.indexOf(QLatin1Char(' '));
+        ComponentVersion version(exp.mid(spaceIdx + 1));
+
+        if (spaceIdx == -1 || !version.isValid()) {
+            addError(stringLit->firstSourceLocation(), "Expected string literal to contain 'Package/Name major.minor' or 'Name major.minor'");
+            continue;
+        }
+        QString package;
+        if (slashIdx != -1)
+            package = exp.left(slashIdx);
+        QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
+
+        // ### relocatable exports where package is empty?
+        fmo->addExport(name, package, version);
+    }
+}
+
+void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
+{
+    if (!ast || !ast->statement) {
+        addError(ast->colonToken, "Expected object literal after colon");
+        return;
+    }
+
+    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
+    if (!expStmt) {
+        addError(ast->statement->firstSourceLocation(), "Expected object literal after colon");
+        return;
+    }
+
+    ObjectLiteral *objectLit = dynamic_cast<ObjectLiteral *>(expStmt->expression);
+    if (!objectLit) {
+        addError(expStmt->firstSourceLocation(), "Expected object literal after colon");
+        return;
+    }
+
+    for (PropertyNameAndValueList *it = objectLit->properties; it; it = it->next) {
+        StringLiteralPropertyName *propName = dynamic_cast<StringLiteralPropertyName *>(it->name);
+        NumericLiteral *value = dynamic_cast<NumericLiteral *>(it->value);
+        UnaryMinusExpression *minus = dynamic_cast<UnaryMinusExpression *>(it->value);
+        if (minus)
+            value = dynamic_cast<NumericLiteral *>(minus->expression);
+        if (!propName || !value) {
+            addError(objectLit->firstSourceLocation(), "Expected object literal to contain only 'string: number' elements");
+            continue;
+        }
+
+        double v = value->value;
+        if (minus)
+            v = -v;
+        fme->addKey(propName->id->asString(), v);
+    }
+}
diff --git a/src/libs/qmljs/qmljstypedescriptionreader.h b/src/libs/qmljs/qmljstypedescriptionreader.h
new file mode 100644
index 00000000000..1b7d38c9a58
--- /dev/null
+++ b/src/libs/qmljs/qmljstypedescriptionreader.h
@@ -0,0 +1,53 @@
+#ifndef QMLJSTYPEDESCRIPTIONREADER_H
+#define QMLJSTYPEDESCRIPTIONREADER_H
+
+#include <languageutils/fakemetaobject.h>
+
+#include <QtCore/QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QBuffer;
+QT_END_NAMESPACE
+
+namespace QmlJS {
+
+namespace AST {
+class UiProgram;
+class UiObjectDefinition;
+class UiScriptBinding;
+class SourceLocation;
+}
+
+class TypeDescriptionReader
+{
+public:
+    explicit TypeDescriptionReader(const QString &data);
+    ~TypeDescriptionReader();
+
+    bool operator()(QMap<QString, LanguageUtils::FakeMetaObject::Ptr> *objects);
+    QString errorMessage() const;
+
+private:
+    void readDocument(AST::UiProgram *ast);
+    void readModule(AST::UiObjectDefinition *ast);
+    void readComponent(AST::UiObjectDefinition *ast);
+    void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo);
+    void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+    void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+    void readParameter(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaMethod *fmm);
+
+    QString readStringBinding(AST::UiScriptBinding *ast);
+    bool readBoolBinding(AST::UiScriptBinding *ast);
+    void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+    void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme);
+    void addError(const AST::SourceLocation &loc, const QString &message);
+
+    QString _source;
+    QString _errorMessage;
+    QMap<QString, LanguageUtils::FakeMetaObject::Ptr> *_objects;
+};
+
+} // namespace QmlJS
+
+#endif // QMLJSTYPEDESCRIPTIONREADER_H
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp
index f8a0ba251ae..187007f0437 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp
@@ -117,7 +117,7 @@ void ModelManager::loadQmlTypeDescriptions(const QString &resourcePath)
                                                              QDir::Files,
                                                              QDir::Name);
 
-    const QStringList errors = Interpreter::CppQmlTypesLoader::load(xmlFiles);
+    const QStringList errors = Interpreter::CppQmlTypesLoader::loadXml(xmlFiles);
     foreach (const QString &error, errors)
         qWarning() << qPrintable(error);
 
-- 
GitLab