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