Commit 187ae1e9 authored by Christian Kamm's avatar Christian Kamm
Browse files

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.
parent 13f91358
......@@ -121,7 +121,6 @@ bool FakeMetaProperty::isPointer() const
FakeMetaObject::FakeMetaObject()
: m_super(0)
{
}
......@@ -143,17 +142,20 @@ void FakeMetaObject::addExport(const QString &name, const QString &package, Comp
}
QList<FakeMetaObject::Export> FakeMetaObject::exports() const
{ return m_exports; }
FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
{
foreach (const Export &exp, m_exports) {
if (exp.package == package)
return exp;
}
return Export();
}
void FakeMetaObject::setSuperclassName(const QString &superclass)
{ m_superName = superclass; }
QString FakeMetaObject::superclassName() const
{ return m_superName; }
void FakeMetaObject::setSuperclass(ConstPtr superClass)
{ m_super = superClass; }
FakeMetaObject::ConstPtr FakeMetaObject::superClass() const
{ return m_super; }
void FakeMetaObject::addEnum(const FakeMetaEnum &fakeEnum)
{ m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
int FakeMetaObject::enumeratorCount() const
......
......@@ -135,12 +135,13 @@ public:
QString type;
ComponentVersion version;
QString packageNameVersion;
bool isValid() const;
};
private:
QString m_className;
QList<Export> m_exports;
ConstPtr m_super;
QString m_superName;
QList<FakeMetaEnum> m_enums;
QHash<QString, int> m_enumNameToIndex;
......@@ -158,11 +159,10 @@ public:
void addExport(const QString &name, const QString &package, ComponentVersion version);
QList<Export> exports() const;
Export exportInPackage(const QString &package) const;
void setSuperclassName(const QString &superclass);
QString superclassName() const;
void setSuperclass(ConstPtr superClass);
ConstPtr superClass() const;
void addEnum(const FakeMetaEnum &fakeEnum);
int enumeratorCount() const;
......
......@@ -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;
}
QString QmlObjectValue::packageName() const
{ return _packageName; }
QString QmlObjectValue::nameInPackage(const QString &packageName) const
const QmlObjectValue *QmlObjectValue::prototype() const
{
foreach (const FakeMetaObject::Export &exp, _metaObject->exports())
if (exp.package == packageName)
return exp.type;
return QString();
Q_ASSERT(!_prototype || dynamic_cast<const QmlObjectValue *>(_prototype));
return static_cast<const QmlObjectValue *>(_prototype);
}
QString QmlObjectValue::fullyQualifiedNameInPackage(const QString &packageName) const
FakeMetaObject::ConstPtr QmlObjectValue::metaObject() const
{
foreach (const FakeMetaObject::Export &exp, _metaObject->exports())
if (exp.package == packageName)
return exp.packageNameVersion;
return QString();
return _metaObject;
}
QString QmlObjectValue::packageName() const
{ return _packageName; }
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;
}
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;
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 {
*created = false;
const QString qname = qualifiedName(package, cppName, ComponentVersion());
object = typeByQualifiedName(qname);
if (!object) {
object = new QmlObjectValue(
metaObject, cppName, package, ComponentVersion(), cppObject->engine());
_typesByFullyQualifiedName[qname] = object;
}
}
return value;
return object;
}
ConvertToNumber::ConvertToNumber(Engine *engine)
......
......@@ -420,9 +420,11 @@ private:
private:
Engine *_engine;
const Value *_prototype;
QHash<QString, const Value *> _members;
QString _className;
protected:
const Value *_prototype;
};
class QMLJS_EXPORT PrototypeIterator
......@@ -443,6 +445,8 @@ private:
const Context *m_context;
};
// A ObjectValue based on a FakeMetaObject.
// May only have other QmlObjectValues as ancestors.
class QMLJS_EXPORT QmlObjectValue: public ObjectValue
{
public:
......@@ -454,10 +458,14 @@ public:
virtual void processMembers(MemberProcessor *processor) const;
const Value *propertyValue(const LanguageUtils::FakeMetaProperty &prop) const;
using ObjectValue::prototype;
const QmlObjectValue *prototype() const;
LanguageUtils::FakeMetaObject::ConstPtr metaObject() const;
QString packageName() const;
QString nameInPackage(const QString &packageName) const;
QString fullyQualifiedNameInPackage(const QString &packageName) const;
LanguageUtils::ComponentVersion version() const;
QString defaultPropertyName() const;
QString propertyType(const QString &propertyName) const;
bool isListProperty(const QString &name) const;
......@@ -591,9 +599,7 @@ public:
// parses the xml string and fills the newObjects map
static QString parseQmlTypeDescriptions(const QByteArray &xml,
QHash<QString, LanguageUtils::FakeMetaObject::Ptr> *newObjects);
private:
static void setSuperClasses(QHash<QString, LanguageUtils::FakeMetaObject::Ptr> *newObjects);
QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *newObjects);
};
class QMLJS_EXPORT CppQmlTypes
......@@ -621,16 +627,11 @@ public:
LanguageUtils::ComponentVersion version) const;
private:
void makeObject(Engine *engine,
LanguageUtils::FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp,
QList<LanguageUtils::FakeMetaObject::ConstPtr> *newObjects);
void setPrototypes(Engine *engine,
LanguageUtils::FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp);
QmlObjectValue *getOrCreate(const QString &package, const QString &cppName,
LanguageUtils::FakeMetaObject::ConstPtr metaObject,
Engine *engine, bool *created);
QmlObjectValue *makeObject(Engine *engine,
LanguageUtils::FakeMetaObject::ConstPtr metaObject,
const LanguageUtils::FakeMetaObject::Export &exp);
void setPrototypes(QmlObjectValue *object);
QmlObjectValue *getOrCreate(const QString &package, const QString &cppName);
QHash<QString, QList<QmlObjectValue *> > _typesByPackage;
......
......@@ -27,7 +27,7 @@ TypeDescriptionReader::~TypeDescriptionReader()
{
}
bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::Ptr> *objects)
bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::ConstPtr> *objects)
{
QString fileName("typeDescription");
Engine engine;
......
......@@ -30,7 +30,7 @@ public:
explicit TypeDescriptionReader(const QString &data);
~TypeDescriptionReader();
bool operator()(QHash<QString, LanguageUtils::FakeMetaObject::Ptr> *objects);
bool operator()(QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects);
QString errorMessage() const;
private:
......@@ -50,7 +50,7 @@ private:
QString _source;
QString _errorMessage;
QHash<QString, LanguageUtils::FakeMetaObject::Ptr> *_objects;
QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects;
};
} // namespace QmlJS
......
......@@ -1551,7 +1551,6 @@ static void populate(LanguageUtils::FakeMetaObject::Ptr fmo, Class *klass,
baseFmo = FakeMetaObject::Ptr(new FakeMetaObject);
populate(baseFmo, baseClass, classes, typeOf);
}
fmo->setSuperclass(baseFmo);
}
}
......
......@@ -52,6 +52,7 @@
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/parser/qmljsast_p.h>
#include <languageutils/fakemetaobject.h>
#include <private/qdeclarativemetatype_p.h>
#include <private/qdeclarativestringconverters_p.h>
......@@ -658,7 +659,9 @@ bool NodeMetaInfoPrivate::cleverCheckType(const QString &otherType) const
if (packageName() == package)
return QString(package + "/" + typeName) == qualfiedTypeName();
const QString convertedName = getQmlObjectValue()->nameInPackage(package);
const LanguageUtils::FakeMetaObject::Export exp =
getQmlObjectValue()->metaObject()->exportInPackage(package);
const QString convertedName = exp.type;
return QString(package + "/" + typeName) == QString(package + "/" + convertedName);
}
......
......@@ -139,16 +139,11 @@ static QString qmldumpFailedMessage(const QString &error)
static QList<FakeMetaObject::ConstPtr> parseHelper(const QByteArray &qmlTypeDescriptions, QString *error)
{
QList<FakeMetaObject::ConstPtr> ret;
QHash<QString, FakeMetaObject::Ptr> newObjects;
QHash<QString, FakeMetaObject::ConstPtr> newObjects;
*error = Interpreter::CppQmlTypesLoader::parseQmlTypeDescriptions(qmlTypeDescriptions, &newObjects);
if (error->isEmpty()) {
// convert from QList<T *> to QList<const T *>
QHashIterator<QString, FakeMetaObject::Ptr> it(newObjects);
while (it.hasNext()) {
it.next();
ret.append(it.value());
}
ret = newObjects.values();
}
return ret;
}
......
Supports Markdown
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