Qml-C++: Find C++ qmlRegisterType calls and populate QML code model.

Reviewed-by: Erik Verbruggen
This commit is contained in:
Christian Kamm
2010-12-03 10:13:15 +01:00
parent 16542241c9
commit 0194da7300
12 changed files with 359 additions and 2 deletions

View File

@@ -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