Commit 283a3d32 authored by Christian Kamm's avatar Christian Kamm

Qml/C++: Fix performance problem with type extraction.

By moving the offending code into a background thread.

Reviewed-by: Erik Verbruggen
parent c7070526
......@@ -147,7 +147,7 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro) = 0;
virtual QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects() const = 0;
virtual QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects(const CPlusPlus::Document::Ptr &doc) const = 0;
Q_SIGNALS:
void documentUpdated(CPlusPlus::Document::Ptr doc);
......
......@@ -1944,7 +1944,6 @@ const Value *Function::invoke(const Activation *activation) const
////////////////////////////////////////////////////////////////////////////////
QList<FakeMetaObject::ConstPtr> CppQmlTypesLoader::builtinObjects;
QList<FakeMetaObject::ConstPtr> CppQmlTypesLoader::cppObjects;
QStringList CppQmlTypesLoader::load(const QFileInfoList &xmlFiles)
{
......@@ -2438,7 +2437,6 @@ Engine::Engine()
initializePrototypes();
_cppQmlTypes.load(this, CppQmlTypesLoader::builtinObjects);
_cppQmlTypes.load(this, CppQmlTypesLoader::cppObjects);
// the 'Qt' object is dumped even though it is not exported
// it contains useful information, in particular on enums - add the
......
......@@ -587,7 +587,6 @@ public:
/** \return an empty list when successful, error messages otherwise. */
static QStringList load(const QFileInfoList &xmlFiles);
static QList<LanguageUtils::FakeMetaObject::ConstPtr> builtinObjects;
static QList<LanguageUtils::FakeMetaObject::ConstPtr> cppObjects;
// parses the xml string and fills the newObjects map
static QString parseQmlTypeXml(const QByteArray &xml,
......
......@@ -120,6 +120,14 @@ Link::Link(Context *context, const Document::Ptr &doc, const Snapshot &snapshot,
d->snapshot = snapshot;
d->importPaths = importPaths;
// populate engine with types from C++
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
if (modelManager) {
foreach (const QList<FakeMetaObject::ConstPtr> &cppTypes, modelManager->cppQmlTypes()) {
engine()->cppQmlTypes().load(engine(), cppTypes);
}
}
linkImports();
}
......
......@@ -110,6 +110,8 @@ public:
Table _elements;
};
typedef QHash<QString, QList<LanguageUtils::FakeMetaObject::ConstPtr> > CppQmlTypeHash;
public:
ModelManagerInterface(QObject *parent = 0);
virtual ~ModelManagerInterface();
......@@ -132,6 +134,8 @@ public:
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri) = 0;
virtual CppQmlTypeHash cppQmlTypes() const = 0;
signals:
void documentUpdated(QmlJS::Document::Ptr doc);
void documentChangedOnDisk(QmlJS::Document::Ptr doc);
......
......@@ -291,8 +291,7 @@ public:
void operator()()
{
_doc->check(_mode);
// temporarily disabled because it's too expensive
//_doc->findExposedQmlTypes();
_doc->findExposedQmlTypes();
_doc->releaseSource();
_doc->releaseTranslationUnit();
......@@ -1548,32 +1547,34 @@ static void populate(LanguageUtils::FakeMetaObject::Ptr fmo, Class *klass,
}
}
QList<LanguageUtils::FakeMetaObject::ConstPtr> CppModelManager::exportedQmlObjects() const
QList<LanguageUtils::FakeMetaObject::ConstPtr> CppModelManager::exportedQmlObjects(const Document::Ptr &doc) const
{
using namespace LanguageUtils;
QList<FakeMetaObject::ConstPtr> exportedObjects;
QHash<Class *, FakeMetaObject::Ptr> classes;
const QList<CPlusPlus::Document::ExportedQmlType> exported = doc->exportedQmlTypes();
if (exported.isEmpty())
return exportedObjects;
TypeOfExpression typeOf;
const Snapshot currentSnapshot = snapshot();
foreach (Document::Ptr doc, currentSnapshot) {
TypeOfExpression typeOf;
typeOf.init(doc, currentSnapshot);
foreach (const Document::ExportedQmlType &exportedType, doc->exportedQmlTypes()) {
FakeMetaObject::Ptr fmo(new FakeMetaObject);
fmo->addExport(exportedType.typeName, exportedType.packageName,
ComponentVersion(exportedType.majorVersion, exportedType.minorVersion));
exportedObjects += fmo;
Class *klass = lookupClass(exportedType.typeExpression, exportedType.scope, typeOf);
if (!klass)
continue;
typeOf.init(doc, currentSnapshot);
foreach (const Document::ExportedQmlType &exportedType, exported) {
FakeMetaObject::Ptr fmo(new FakeMetaObject);
fmo->addExport(exportedType.typeName, exportedType.packageName,
ComponentVersion(exportedType.majorVersion, exportedType.minorVersion));
exportedObjects += fmo;
Class *klass = lookupClass(exportedType.typeExpression, exportedType.scope, typeOf);
if (!klass)
continue;
// add the no-package export, so the cpp name can be used in properties
Overview overview;
fmo->addExport(overview(klass->name()), QString(), ComponentVersion());
// add the no-package export, so the cpp name can be used in properties
Overview overview;
fmo->addExport(overview(klass->name()), QString(), ComponentVersion());
populate(fmo, klass, &classes, typeOf);
}
populate(fmo, klass, &classes, typeOf);
}
return exportedObjects;
......
......@@ -131,7 +131,7 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro);
virtual QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects() const;
virtual QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects(const CPlusPlus::Document::Ptr &doc) const;
void setHeaderSuffixes(const QStringList &suffixes)
{ m_headerSuffixes = suffixes; }
......
......@@ -40,6 +40,9 @@
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/mimedatabase.h>
#include <cplusplus/ModelManagerInterface.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/Overview.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/parser/qmldirparser_p.h>
......@@ -77,7 +80,7 @@ ModelManager::ModelManager(QObject *parent):
m_updateCppQmlTypesTimer = new QTimer(this);
m_updateCppQmlTypesTimer->setInterval(1000);
m_updateCppQmlTypesTimer->setSingleShot(true);
connect(m_updateCppQmlTypesTimer, SIGNAL(timeout()), SLOT(updateCppQmlTypes()));
connect(m_updateCppQmlTypesTimer, SIGNAL(timeout()), SLOT(startCppQmlTypeUpdate()));
qRegisterMetaType<QmlJS::Document::Ptr>("QmlJS::Document::Ptr");
qRegisterMetaType<QmlJS::LibraryInfo>("QmlJS::LibraryInfo");
......@@ -94,7 +97,7 @@ void ModelManager::delayedInitialization()
CPlusPlus::CppModelManagerInterface::instance();
if (cppModelManager) {
connect(cppModelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
m_updateCppQmlTypesTimer, SLOT(start()));
this, SLOT(queueCppQmlTypeUpdate(CPlusPlus::Document::Ptr)));
}
}
......@@ -555,12 +558,46 @@ void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &im
m_pluginDumper->loadPluginTypes(libraryPath, importPath, importUri);
}
void ModelManager::updateCppQmlTypes()
void ModelManager::queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc)
{
m_queuedCppDocuments.insert(doc->fileName());
m_updateCppQmlTypesTimer->start();
}
void ModelManager::startCppQmlTypeUpdate()
{
CPlusPlus::CppModelManagerInterface *cppModelManager =
CPlusPlus::CppModelManagerInterface::instance();
if (!cppModelManager)
return;
Interpreter::CppQmlTypesLoader::cppObjects = cppModelManager->exportedQmlObjects();
QtConcurrent::run(&ModelManager::updateCppQmlTypes,
this, cppModelManager, m_queuedCppDocuments);
m_queuedCppDocuments.clear();
}
void ModelManager::updateCppQmlTypes(ModelManager *qmlModelManager, CPlusPlus::CppModelManagerInterface *cppModelManager, QSet<QString> files)
{
CppQmlTypeHash newCppTypes = qmlModelManager->cppQmlTypes();
CPlusPlus::Snapshot snapshot = cppModelManager->snapshot();
foreach (const QString &fileName, files) {
CPlusPlus::Document::Ptr doc = snapshot.document(fileName);
QList<LanguageUtils::FakeMetaObject::ConstPtr> exported;
if (doc)
exported = cppModelManager->exportedQmlObjects(doc);
if (!exported.isEmpty())
newCppTypes[fileName] = exported;
else
newCppTypes.remove(fileName);
}
QMutexLocker locker(&qmlModelManager->m_cppTypesMutex);
qmlModelManager->m_cppTypes = newCppTypes;
}
ModelManagerInterface::CppQmlTypeHash ModelManager::cppQmlTypes() const
{
QMutexLocker locker(&m_cppTypesMutex);
return m_cppTypes;
}
......@@ -38,6 +38,8 @@
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/ModelManagerInterface.h>
#include <QFuture>
#include <QFutureSynchronizer>
......@@ -85,6 +87,8 @@ public:
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri);
virtual CppQmlTypeHash cppQmlTypes() const;
Q_SIGNALS:
void projectPathChanged(const QString &projectPath);
......@@ -104,10 +108,12 @@ protected:
void updateImportPaths();
private slots:
void updateCppQmlTypes();
void queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc);
void startCppQmlTypeUpdate();
private:
static bool matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType);
static void updateCppQmlTypes(ModelManager *qmlModelManager, CPlusPlus::CppModelManagerInterface *cppModelManager, QSet<QString> files);
mutable QMutex m_mutex;
Core::ICore *m_core;
......@@ -116,7 +122,11 @@ private:
QStringList m_defaultImportPaths;
QFutureSynchronizer<void> m_synchronizer;
QTimer *m_updateCppQmlTypesTimer;
QSet<QString> m_queuedCppDocuments;
CppQmlTypeHash m_cppTypes;
mutable QMutex m_cppTypesMutex;
// project integration
QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment