QmlJS: Rework FakeMetaObjects to no longer contain pointers.

Having a duplicate prototype chain - once in FakeMetaObjects and once
in QmlObjectValues was unnecessary. Now FMOs don't contain references
which may allow other simplifications.
This commit is contained in:
Christian Kamm
2011-02-10 14:53:57 +01:00
parent 13f9135827
commit 187ae1e94a
9 changed files with 116 additions and 140 deletions

View File

@@ -660,9 +660,9 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
// ### Verify type resolving.
QmlObjectValue *objectValue = engine()->cppQmlTypes().typeByCppName(typeName);
if (objectValue) {
QString fqn = objectValue->fullyQualifiedNameInPackage(packageName());
if (!fqn.isEmpty())
objectValue = engine()->cppQmlTypes().typeByQualifiedName(fqn);
FakeMetaObject::Export exp = objectValue->metaObject()->exportInPackage(packageName());
if (exp.isValid())
objectValue = engine()->cppQmlTypes().typeByQualifiedName(exp.packageNameVersion);
return objectValue;
}
@@ -713,25 +713,20 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
return value;
}
const QmlObjectValue *QmlObjectValue::prototype() const
{
Q_ASSERT(!_prototype || dynamic_cast<const QmlObjectValue *>(_prototype));
return static_cast<const QmlObjectValue *>(_prototype);
}
FakeMetaObject::ConstPtr QmlObjectValue::metaObject() const
{
return _metaObject;
}
QString QmlObjectValue::packageName() const
{ return _packageName; }
QString QmlObjectValue::nameInPackage(const QString &packageName) const
{
foreach (const FakeMetaObject::Export &exp, _metaObject->exports())
if (exp.package == packageName)
return exp.type;
return QString();
}
QString QmlObjectValue::fullyQualifiedNameInPackage(const QString &packageName) const
{
foreach (const FakeMetaObject::Export &exp, _metaObject->exports())
if (exp.package == packageName)
return exp.packageNameVersion;
return QString();
}
ComponentVersion QmlObjectValue::version() const
{ return _componentVersion; }
@@ -740,7 +735,8 @@ QString QmlObjectValue::defaultPropertyName() const
QString QmlObjectValue::propertyType(const QString &propertyName) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
int propIdx = iter->propertyIndex(propertyName);
if (propIdx != -1) {
return iter->property(propIdx).typeName();
@@ -751,7 +747,8 @@ QString QmlObjectValue::propertyType(const QString &propertyName) const
bool QmlObjectValue::isListProperty(const QString &propertyName) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
int propIdx = iter->propertyIndex(propertyName);
if (propIdx != -1) {
return iter->property(propIdx).isList();
@@ -767,7 +764,8 @@ bool QmlObjectValue::isEnum(const QString &typeName) const
bool QmlObjectValue::isWritable(const QString &propertyName) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
int propIdx = iter->propertyIndex(propertyName);
if (propIdx != -1) {
return iter->property(propIdx).isWritable();
@@ -778,7 +776,8 @@ bool QmlObjectValue::isWritable(const QString &propertyName) const
bool QmlObjectValue::isPointer(const QString &propertyName) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
int propIdx = iter->propertyIndex(propertyName);
if (propIdx != -1) {
return iter->property(propIdx).isPointer();
@@ -797,7 +796,8 @@ bool QmlObjectValue::hasLocalProperty(const QString &typeName) const
bool QmlObjectValue::hasProperty(const QString &propertyName) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
int propIdx = iter->propertyIndex(propertyName);
if (propIdx != -1) {
return true;
@@ -841,7 +841,8 @@ bool QmlObjectValue::hasChildInPackage() const
// if it has only the default no-package export, it is not really exported
if (other->exports().size() <= 1)
continue;
for (FakeMetaObject::ConstPtr iter = other; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
if (iter == _metaObject) // this object is a parent of other
return true;
}
@@ -851,7 +852,8 @@ bool QmlObjectValue::hasChildInPackage() const
bool QmlObjectValue::isDerivedFrom(FakeMetaObject::ConstPtr base) const
{
for (FakeMetaObject::ConstPtr iter = _metaObject; iter; iter = iter->superClass()) {
for (const QmlObjectValue *it = this; it; it = it->prototype()) {
FakeMetaObject::ConstPtr iter = it->_metaObject;
if (iter == base)
return true;
}
@@ -1956,7 +1958,7 @@ QHash<QString, FakeMetaObject::ConstPtr> CppQmlTypesLoader::builtinObjects;
QStringList CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles)
{
QHash<QString, FakeMetaObject::Ptr> newObjects;
QHash<QString, FakeMetaObject::ConstPtr> newObjects;
QStringList errorMsgs;
foreach (const QFileInfo &qmlTypeFile, qmlTypeFiles) {
@@ -1977,21 +1979,13 @@ QStringList CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles)
}
if (errorMsgs.isEmpty()) {
setSuperClasses(&newObjects);
// we need to go from QHash<K, T::Ptr> to QHash<K, T::ConstPtr>
// and there seems to be no better way
QHashIterator<QString, FakeMetaObject::Ptr> it(newObjects);
while (it.hasNext()) {
it.next();
builtinObjects.insert(it.key(), it.value());
}
builtinObjects.unite(newObjects);
}
return errorMsgs;
}
QString CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, QHash<QString, FakeMetaObject::Ptr> *newObjects)
QString CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, QHash<QString, FakeMetaObject::ConstPtr> *newObjects)
{
QmlJS::TypeDescriptionReader reader(QString::fromUtf8(xml));
if (!reader(newObjects)) {
@@ -1999,30 +1993,9 @@ QString CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, QHash
return QLatin1String("unknown error");
return reader.errorMessage();
}
setSuperClasses(newObjects);
return QString();
}
void CppQmlTypesLoader::setSuperClasses(QHash<QString, FakeMetaObject::Ptr> *newObjects)
{
QHashIterator<QString, FakeMetaObject::Ptr> it(*newObjects);
while (it.hasNext()) {
it.next();
FakeMetaObject::Ptr obj = it.value();
const QString superName = obj->superclassName();
if (! superName.isEmpty()) {
FakeMetaObject::ConstPtr superClass = newObjects->value(superName);
if (!superClass)
superClass = builtinObjects.value(superName);
if (superClass)
obj->setSuperclass(superClass);
else
qWarning() << "QmlJS::Interpreter::MetaTypeSystem: Can't find superclass" << superName << "for" << it.key();
}
}
}
const QLatin1String CppQmlTypes::defaultPackage("<default>");
const QLatin1String CppQmlTypes::cppPackage("<cpp>");
@@ -2030,16 +2003,18 @@ template <typename T>
void CppQmlTypes::load(Engine *engine, const T &objects)
{
// load
QList<FakeMetaObject::ConstPtr> newObjects;
QList<QmlObjectValue *> newObjects;
foreach (FakeMetaObject::ConstPtr metaObject, objects) {
foreach (const FakeMetaObject::Export &exp, metaObject->exports())
makeObject(engine, metaObject, exp, &newObjects);
foreach (const FakeMetaObject::Export &exp, metaObject->exports()) {
QmlObjectValue *newObject = makeObject(engine, metaObject, exp);
if (newObject)
newObjects += newObject;
}
}
// set prototypes
foreach (FakeMetaObject::ConstPtr metaObject, newObjects) {
foreach (const FakeMetaObject::Export &exp, metaObject->exports())
setPrototypes(engine, metaObject, exp);
foreach (QmlObjectValue *object, newObjects) {
setPrototypes(object);
}
}
// explicitly instantiate load for list and hash
@@ -2098,71 +2073,72 @@ QmlObjectValue *CppQmlTypes::typeByQualifiedName(const QString &package, const Q
return typeByQualifiedName(qualifiedName(package, type, version));
}
void CppQmlTypes::makeObject(Engine *engine,
FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp,
QList<LanguageUtils::FakeMetaObject::ConstPtr> *newObjects)
QmlObjectValue *CppQmlTypes::makeObject(
Engine *engine,
FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp)
{
// make sure we're not loading duplicate objects
if (_typesByFullyQualifiedName.contains(exp.packageNameVersion))
return;
return 0;
newObjects->append(metaObject);
QmlObjectValue *objectValue = new QmlObjectValue(
metaObject, exp.type, exp.package, exp.version, engine);
_typesByPackage[exp.package].append(objectValue);
_typesByFullyQualifiedName[exp.packageNameVersion] = objectValue;
return objectValue;
}
void CppQmlTypes::setPrototypes(Engine *engine,
FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp)
void CppQmlTypes::setPrototypes(QmlObjectValue *object)
{
QmlObjectValue *objectValue = _typesByFullyQualifiedName.value(exp.packageNameVersion);
if (!objectValue || !metaObject->superClass())
if (!object || object->metaObject()->superclassName().isEmpty())
return;
const QString targetPackage = object->packageName();
// set prototypes for whole chain, creating new QmlObjectValues if necessary
// for instance, if an type isn't exported in the package of the super type
// Example: QObject (Qt, QtQuick) -> Positioner (not exported) -> Column (Qt, QtQuick)
// needs to create Positioner (Qt) and Positioner (QtQuick)
bool created = true;
QmlObjectValue *v = objectValue;
FakeMetaObject::ConstPtr fmo = metaObject;
while (created && fmo->superClass()) {
QmlObjectValue *superValue = getOrCreate(exp.package, fmo->superclassName(),
fmo->superClass(), engine, &created);
QmlObjectValue *v = object;
FakeMetaObject::ConstPtr fmo = v->metaObject();
while (!v->prototype() && !fmo->superclassName().isEmpty()) {
QmlObjectValue *superValue = getOrCreate(targetPackage, fmo->superclassName());
if (!superValue)
return;
v->setPrototype(superValue);
v = superValue;
fmo = fmo->superClass();
fmo = v->metaObject();
}
}
QmlObjectValue *CppQmlTypes::getOrCreate(const QString &package, const QString &cppName,
FakeMetaObject::ConstPtr metaObject, Engine *engine, bool *created)
QmlObjectValue *CppQmlTypes::getOrCreate(const QString &package, const QString &cppName)
{
QString typeName = cppName;
ComponentVersion version;
foreach (const FakeMetaObject::Export &exp, metaObject->exports()) {
if (exp.package == package) {
typeName = exp.type;
version = exp.version;
break;
// first get the cpp object value
QmlObjectValue *cppObject = typeByCppName(cppName);
if (!cppObject) {
qWarning() << "QML type system: could not find '" << cppName << "'";
return 0;
}
FakeMetaObject::ConstPtr metaObject = cppObject->metaObject();
FakeMetaObject::Export exp = metaObject->exportInPackage(package);
QmlObjectValue *object = 0;
if (exp.isValid()) {
object = typeByQualifiedName(exp.packageNameVersion);
if (!object)
object = makeObject(cppObject->engine(), metaObject, exp);
} else {
const QString qname = qualifiedName(package, cppName, ComponentVersion());
object = typeByQualifiedName(qname);
if (!object) {
object = new QmlObjectValue(
metaObject, cppName, package, ComponentVersion(), cppObject->engine());
_typesByFullyQualifiedName[qname] = object;
}
}
const QString qName = qualifiedName(package, typeName, version);
QmlObjectValue *value = typeByQualifiedName(qName);
if (!value) {
*created = true;
value = new QmlObjectValue(
metaObject, typeName, package, ComponentVersion(), engine);
_typesByFullyQualifiedName[qName] = value;
} else {
*created = false;
}
return value;
return object;
}
ConvertToNumber::ConvertToNumber(Engine *engine)