diff options
author | Christian Kamm <christian.d.kamm@nokia.com> | 2010-12-03 10:13:15 +0100 |
---|---|---|
committer | Christian Kamm <christian.d.kamm@nokia.com> | 2011-01-04 15:58:22 +0100 |
commit | 0194da7300d3fd76594e337c785566c4498e12f4 (patch) | |
tree | a27481b214c038f7fc5f140b233d767e5ab1363c /src/plugins | |
parent | 16542241c91d6a4296bfbd18077de4eff1f43c8b (diff) | |
download | qt-creator-0194da7300d3fd76594e337c785566c4498e12f4.tar.gz |
Qml-C++: Find C++ qmlRegisterType calls and populate QML code model.
Reviewed-by: Erik Verbruggen
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/cpptools/cppmodelmanager.cpp | 162 | ||||
-rw-r--r-- | src/plugins/cpptools/cppmodelmanager.h | 2 | ||||
-rw-r--r-- | src/plugins/qmljstools/qmljsmodelmanager.cpp | 30 | ||||
-rw-r--r-- | src/plugins/qmljstools/qmljsmodelmanager.h | 8 | ||||
-rw-r--r-- | src/plugins/qmljstools/qmljstools_dependencies.pri | 1 | ||||
-rw-r--r-- | src/plugins/qmljstools/qmljstoolsplugin.cpp | 1 |
6 files changed, 203 insertions, 1 deletions
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index efe8175dcb..19d3530346 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -77,6 +77,7 @@ #include <Token.h> #include <Parser.h> #include <Control.h> +#include <CoreTypes.h> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> @@ -290,6 +291,8 @@ public: void operator()() { _doc->check(_mode); + _doc->findExposedQmlTypes(); + _doc->releaseSource(); _doc->releaseTranslationUnit(); if (_mode == Document::FastCheck) @@ -589,7 +592,6 @@ void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned doc->setSource(preprocessedCode); doc->tokenize(); - doc->releaseSource(); snapshot.insert(doc); m_todo.remove(fileName); @@ -601,6 +603,7 @@ void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned (void) switchDocument(previousDoc); #else + doc->releaseSource(); Document::CheckMode mode = Document::FastCheck; mode = Document::FullCheck; doc->parse(); @@ -1418,5 +1421,162 @@ void CppModelManager::GC() protectSnapshot.unlock(); } +static FullySpecifiedType stripPointerAndReference(const FullySpecifiedType &type) +{ + Type *t = type.type(); + while (t) { + if (PointerType *ptr = t->asPointerType()) + t = ptr->elementType().type(); + else if (ReferenceType *ref = t->asReferenceType()) + t = ref->elementType().type(); + else + break; + } + return FullySpecifiedType(t); +} + +static QString toQmlType(const FullySpecifiedType &type) +{ + Overview overview; + QString result = overview(stripPointerAndReference(type)); + if (result == QLatin1String("QString")) + result = QLatin1String("string"); + return result; +} + +static Class *lookupClass(const QString &expression, Scope *scope, TypeOfExpression &typeOf) +{ + QList<LookupItem> results = typeOf(expression, scope); + Class *klass = 0; + foreach (const LookupItem &item, results) { + if (item.declaration()) { + klass = item.declaration()->asClass(); + if (klass) + return klass; + } + } + return 0; +} + +static void populate(LanguageUtils::FakeMetaObject *fmo, Class *klass, + QHash<Class *, LanguageUtils::FakeMetaObject *> *classes, + TypeOfExpression &typeOf) +{ + using namespace LanguageUtils; + + Overview namePrinter; + + classes->insert(klass, fmo); + + for (unsigned i = 0; i < klass->memberCount(); ++i) { + Symbol *member = klass->memberAt(i); + if (!member->name()) + continue; + if (Function *func = member->type()->asFunctionType()) { + if (!func->isSlot() && !func->isInvokable() && !func->isSignal()) + continue; + FakeMetaMethod method(namePrinter(func->name()), toQmlType(func->returnType())); + if (func->isSignal()) + method.setMethodType(FakeMetaMethod::Signal); + else + method.setMethodType(FakeMetaMethod::Slot); + for (unsigned a = 0; a < func->argumentCount(); ++a) { + Symbol *arg = func->argumentAt(a); + QString name(CppModelManager::tr("unnamed")); + if (arg->name()) + name = namePrinter(arg->name()); + method.addParameter(name, toQmlType(arg->type())); + } + fmo->addMethod(method); + } + if (QtPropertyDeclaration *propDecl = member->asQtPropertyDeclaration()) { + const FullySpecifiedType &type = propDecl->type(); + const bool isList = false; // ### fixme + const bool isWritable = propDecl->flags() & QtPropertyDeclaration::WriteFunction; + const bool isPointer = type.type() && type.type()->isPointerType(); + FakeMetaProperty property( + namePrinter(propDecl->name()), + toQmlType(type), + isList, isWritable, isPointer); + fmo->addProperty(property); + } + if (QtEnum *qtEnum = member->asQtEnum()) { + // find the matching enum + Enum *e = 0; + QList<LookupItem> result = typeOf(namePrinter(qtEnum->name()), klass); + foreach (const LookupItem &item, result) { + if (item.declaration()) { + e = item.declaration()->asEnum(); + if (e) + break; + } + } + if (!e) + continue; + + FakeMetaEnum metaEnum(namePrinter(e->name())); + for (unsigned j = 0; j < e->memberCount(); ++j) { + Symbol *enumMember = e->memberAt(j); + if (!enumMember->name()) + continue; + metaEnum.addKey(namePrinter(enumMember->name()), 0); + } + fmo->addEnum(metaEnum); + } + } + + // only single inheritance is supported + if (klass->baseClassCount() > 0) { + BaseClass *base = klass->baseClassAt(0); + if (!base->name()) + return; + + const QString baseClassName = namePrinter(base->name()); + fmo->setSuperclassName(baseClassName); + + Class *baseClass = lookupClass(baseClassName, klass, typeOf); + if (!baseClass) + return; + + FakeMetaObject *baseFmo = classes->value(baseClass); + if (!baseFmo) { + baseFmo = new FakeMetaObject; + populate(baseFmo, baseClass, classes, typeOf); + } + fmo->setSuperclass(baseFmo); + } +} + +QList<LanguageUtils::FakeMetaObject *> CppModelManager::exportedQmlObjects() const +{ + using namespace LanguageUtils; + QList<FakeMetaObject *> exportedObjects; + QHash<Class *, FakeMetaObject *> classes; + + const Snapshot currentSnapshot = snapshot(); + foreach (Document::Ptr doc, currentSnapshot) { + TypeOfExpression typeOf; + typeOf.init(doc, currentSnapshot); + foreach (const Document::ExportedQmlType &exportedType, doc->exportedQmlTypes()) { + FakeMetaObject *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()); + + populate(fmo, klass, &classes, typeOf); + } + } + + return exportedObjects; +} + #endif diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 865421a16e..bd0bef0962 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -131,6 +131,8 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o); + virtual QList<LanguageUtils::FakeMetaObject *> exportedQmlObjects() const; + void setHeaderSuffixes(const QStringList &suffixes) { m_headerSuffixes = suffixes; } diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 69f43c5579..0477f9ed01 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -39,6 +39,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/mimedatabase.h> +#include <cplusplus/ModelManagerInterface.h> #include <qmljs/qmljsinterpreter.h> #include <qmljs/qmljsbind.h> #include <qmljs/parser/qmldirparser_p.h> @@ -56,6 +57,7 @@ #include <qtconcurrent/runextensions.h> #include <QTextStream> #include <QCoreApplication> +#include <QTimer> #include <QDebug> @@ -72,6 +74,11 @@ ModelManager::ModelManager(QObject *parent): { m_synchronizer.setCancelOnWait(true); + m_updateCppQmlTypesTimer = new QTimer(this); + m_updateCppQmlTypesTimer->setInterval(1000); + m_updateCppQmlTypesTimer->setSingleShot(true); + connect(m_updateCppQmlTypesTimer, SIGNAL(timeout()), SLOT(updateCppQmlTypes())); + qRegisterMetaType<QmlJS::Document::Ptr>("QmlJS::Document::Ptr"); qRegisterMetaType<QmlJS::LibraryInfo>("QmlJS::LibraryInfo"); @@ -81,6 +88,16 @@ ModelManager::ModelManager(QObject *parent): updateImportPaths(); } +void ModelManager::delayedInitialization() +{ + CPlusPlus::CppModelManagerInterface *cppModelManager = + CPlusPlus::CppModelManagerInterface::instance(); + if (cppModelManager) { + connect(cppModelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)), + m_updateCppQmlTypesTimer, SLOT(start())); + } +} + void ModelManager::loadQmlTypeDescriptions() { if (Core::ICore::instance()) { @@ -537,3 +554,16 @@ void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &im { m_pluginDumper->loadPluginTypes(libraryPath, importPath, importUri); } + +void ModelManager::updateCppQmlTypes() +{ + CPlusPlus::CppModelManagerInterface *cppModelManager = + CPlusPlus::CppModelManagerInterface::instance(); + if (!cppModelManager) + return; + + QList<const LanguageUtils::FakeMetaObject *> constFMOs; + foreach (LanguageUtils::FakeMetaObject *fmo, cppModelManager->exportedQmlObjects()) + constFMOs.append(fmo); + Interpreter::CppQmlTypesLoader::cppObjects = constFMOs; +} diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h index a80f18cdca..1a0b4c2833 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.h +++ b/src/plugins/qmljstools/qmljsmodelmanager.h @@ -44,6 +44,8 @@ #include <QMutex> #include <QProcess> +QT_FORWARD_DECLARE_CLASS(QTimer) + namespace Core { class ICore; class MimeType; @@ -61,6 +63,8 @@ class QMLJSTOOLS_EXPORT ModelManager: public QmlJS::ModelManagerInterface public: ModelManager(QObject *parent = 0); + void delayedInitialization(); + virtual WorkingCopy workingCopy() const; virtual QmlJS::Snapshot snapshot() const; @@ -99,6 +103,9 @@ protected: void updateImportPaths(); +private slots: + void updateCppQmlTypes(); + private: static bool matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType); @@ -109,6 +116,7 @@ private: QStringList m_defaultImportPaths; QFutureSynchronizer<void> m_synchronizer; + QTimer *m_updateCppQmlTypesTimer; // project integration QMap<ProjectExplorer::Project *, ProjectInfo> m_projects; diff --git a/src/plugins/qmljstools/qmljstools_dependencies.pri b/src/plugins/qmljstools/qmljstools_dependencies.pri index d63c784082..c94524e75c 100644 --- a/src/plugins/qmljstools/qmljstools_dependencies.pri +++ b/src/plugins/qmljstools/qmljstools_dependencies.pri @@ -1,4 +1,5 @@ include($$IDE_SOURCE_TREE/src/libs/languageutils/languageutils.pri) +include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri) include($$IDE_SOURCE_TREE/src/libs/qmljs/qmljs.pri) include($$IDE_SOURCE_TREE/src/plugins/projectexplorer/projectexplorer.pri) include($$IDE_SOURCE_TREE/src/plugins/texteditor/texteditor.pri) diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index c1f0e91e6b..3a456eed75 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -89,6 +89,7 @@ bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error) void QmlJSToolsPlugin::extensionsInitialized() { + m_modelManager->delayedInitialization(); } ExtensionSystem::IPlugin::ShutdownFlag QmlJSToolsPlugin::aboutToShutdown() |