[new compiler] Implement proper type resolution
Collect all references to unknown types after parsing, re-use the existing code in QQmlTypeLoader to resolve them and finally use the resolved references map in the QQmlObjectCreator instead of the type name cache directly. Change-Id: I8b83af4f8852e79c33985457081c024358bb9622 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
parent
8c2201e2e5
commit
4b5a7b15fc
|
@ -109,6 +109,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
|
|||
qSwap(_imports, output->imports);
|
||||
qSwap(_objects, output->objects);
|
||||
qSwap(_functions, output->functions);
|
||||
qSwap(_typeReferences, output->typeReferences);
|
||||
this->pool = output->jsParserEngine.pool();
|
||||
this->jsGenerator = &output->jsGenerator;
|
||||
|
||||
|
@ -128,9 +129,13 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
|
|||
AST::UiObjectDefinition *rootObject = AST::cast<AST::UiObjectDefinition*>(program->members->member);
|
||||
Q_ASSERT(rootObject);
|
||||
output->indexOfRootObject = defineQMLObject(rootObject);
|
||||
|
||||
collectTypeReferences();
|
||||
|
||||
qSwap(_imports, output->imports);
|
||||
qSwap(_objects, output->objects);
|
||||
qSwap(_functions, output->functions);
|
||||
qSwap(_typeReferences, output->typeReferences);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -440,6 +445,8 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
|
|||
}
|
||||
|
||||
param->nameIndex = registerString(p->name.toString());
|
||||
param->location.line = p->identifierToken.startLine;
|
||||
param->location.column = p->identifierToken.startColumn;
|
||||
signal->parameters->append(param);
|
||||
p = p->next;
|
||||
}
|
||||
|
@ -710,6 +717,22 @@ void QQmlCodeGenerator::recordError(const AST::SourceLocation &location, const Q
|
|||
errors << error;
|
||||
}
|
||||
|
||||
void QQmlCodeGenerator::collectTypeReferences()
|
||||
{
|
||||
foreach (QmlObject *obj, _objects) {
|
||||
_typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
|
||||
|
||||
for (QmlProperty *prop = obj->properties->first; prop; prop = prop->next) {
|
||||
if (prop->type >= QV4::CompiledData::Property::Custom)
|
||||
_typeReferences.add(prop->customTypeNameIndex, prop->location);
|
||||
}
|
||||
|
||||
for (Signal *sig = obj->qmlSignals->first; sig; sig = sig->next)
|
||||
for (SignalParameter *param = sig->parameters->first; param; param = param->next)
|
||||
_typeReferences.add(param->customTypeNameIndex, param->location);
|
||||
}
|
||||
}
|
||||
|
||||
QQmlScript::LocationSpan QQmlCodeGenerator::location(AST::SourceLocation start, AST::SourceLocation end)
|
||||
{
|
||||
QQmlScript::LocationSpan rv;
|
||||
|
|
|
@ -163,6 +163,8 @@ struct ParsedQML
|
|||
QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression
|
||||
QV4::Compiler::JSUnitGenerator jsGenerator;
|
||||
|
||||
QV4::CompiledData::TypeReferenceMap typeReferences;
|
||||
|
||||
QString stringAt(int index) const { return jsGenerator.strings.value(index); }
|
||||
};
|
||||
|
||||
|
@ -220,6 +222,8 @@ public:
|
|||
|
||||
void recordError(const AST::SourceLocation &location, const QString &description);
|
||||
|
||||
void collectTypeReferences();
|
||||
|
||||
static QQmlScript::LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
|
||||
|
||||
int registerString(const QString &str) const { return jsGenerator->registerString(str); }
|
||||
|
@ -231,6 +235,8 @@ public:
|
|||
QList<QmlObject*> _objects;
|
||||
QList<AST::Node*> _functions;
|
||||
|
||||
QV4::CompiledData::TypeReferenceMap _typeReferences;
|
||||
|
||||
QmlObject *_object;
|
||||
QSet<QString> _propertyNames;
|
||||
QSet<QString> _signalNames;
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <QtCore/qstring.h>
|
||||
#include <QVector>
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include <private/qv4value_def_p.h>
|
||||
#include <private/qv4executableallocator_p.h>
|
||||
|
||||
|
@ -73,6 +74,16 @@ struct Location
|
|||
int column;
|
||||
};
|
||||
|
||||
// map from name index to location of first use
|
||||
struct TypeReferenceMap : QHash<int, Location>
|
||||
{
|
||||
void add(int nameIndex, const Location &loc) {
|
||||
if (contains(nameIndex))
|
||||
return;
|
||||
insert(nameIndex, loc);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegExp
|
||||
{
|
||||
enum Flags {
|
||||
|
@ -263,6 +274,7 @@ struct Parameter
|
|||
quint32 type;
|
||||
quint32 customTypeNameIndex;
|
||||
quint32 reserved;
|
||||
Location location;
|
||||
};
|
||||
|
||||
struct Signal
|
||||
|
|
|
@ -116,6 +116,14 @@ QQmlCompiledData::~QQmlCompiledData()
|
|||
types.at(ii).typePropertyCache->release();
|
||||
}
|
||||
|
||||
for (QHash<int, TypeReference>::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end();
|
||||
resolvedType != end; ++resolvedType) {
|
||||
if (resolvedType->component)
|
||||
resolvedType->component->release();
|
||||
if (resolvedType->typePropertyCache)
|
||||
resolvedType->typePropertyCache->release();
|
||||
}
|
||||
|
||||
for (int ii = 0; ii < propertyCaches.count(); ++ii)
|
||||
propertyCaches.at(ii)->release();
|
||||
|
||||
|
|
|
@ -110,7 +110,12 @@ public:
|
|||
QQmlPropertyCache *propertyCache() const;
|
||||
QQmlPropertyCache *createPropertyCache(QQmlEngine *);
|
||||
};
|
||||
// --- old compiler:
|
||||
QList<TypeReference> types;
|
||||
// --- new compiler:
|
||||
// map from name index
|
||||
QHash<int, TypeReference> resolvedTypes;
|
||||
// ---
|
||||
|
||||
struct V8Program {
|
||||
V8Program(const QByteArray &p, QQmlCompiledData *c)
|
||||
|
|
|
@ -900,7 +900,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
|
|||
if (cc->compilationUnit && !cc->compilationUnit->engine)
|
||||
cc->compilationUnit->linkToEngine(v4);
|
||||
|
||||
state.creator = new QmlObjectCreator(context, cc->qmlUnit, cc->compilationUnit, cc->importCache,
|
||||
state.creator = new QmlObjectCreator(context, cc->qmlUnit, cc->compilationUnit, cc->resolvedTypes,
|
||||
cc->propertyCaches, cc->datas);
|
||||
rv = state.creator->create();
|
||||
if (!rv)
|
||||
|
|
|
@ -60,21 +60,22 @@ QT_USE_NAMESPACE
|
|||
|
||||
static QAtomicInt classIndexCounter(0);
|
||||
|
||||
QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, QQmlTypeNameCache *typeNameCache, const QQmlImports *imports)
|
||||
QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, const QQmlImports *imports,
|
||||
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes)
|
||||
: enginePrivate(enginePrivate)
|
||||
, unit(unit)
|
||||
, url(url)
|
||||
, typeNameCache(typeNameCache)
|
||||
, imports(imports)
|
||||
, resolvedTypes(resolvedTypes)
|
||||
{
|
||||
}
|
||||
|
||||
bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData)
|
||||
{
|
||||
QQmlTypeNameCache::Result res = typeNameCache->query(stringAt(obj->inheritedTypeNameIndex));
|
||||
Q_ASSERT(res.isValid()); // types resolved earlier in resolveTypes()
|
||||
QQmlType *baseType = resolvedTypes->value(obj->inheritedTypeNameIndex).type;
|
||||
Q_ASSERT(baseType);
|
||||
|
||||
QQmlPropertyCache *baseTypeCache = enginePrivate->cache(res.type->metaObject());
|
||||
QQmlPropertyCache *baseTypeCache = enginePrivate->cache(baseType->metaObject());
|
||||
if (obj->nProperties == 0 && obj->nSignals == 0 && obj->nFunctions == 0) {
|
||||
*resultCache = baseTypeCache;
|
||||
vmeMetaObjectData->clear();
|
||||
|
@ -441,14 +442,15 @@ static void removeBindingOnProperty(QObject *o, int index)
|
|||
}
|
||||
|
||||
QmlObjectCreator::QmlObjectCreator(QQmlContextData *contextData, const QV4::CompiledData::QmlUnit *qmlUnit,
|
||||
const QV4::CompiledData::CompilationUnit *jsUnit, QQmlTypeNameCache *typeNameCache,
|
||||
const QV4::CompiledData::CompilationUnit *jsUnit,
|
||||
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
|
||||
const QList<QQmlPropertyCache*> &propertyCaches,
|
||||
const QList<QByteArray> &vmeMetaObjectData)
|
||||
: engine(contextData->engine)
|
||||
, unit(qmlUnit)
|
||||
, jsUnit(jsUnit)
|
||||
, context(contextData)
|
||||
, typeNameCache(typeNameCache)
|
||||
, resolvedTypes(resolvedTypes)
|
||||
, propertyCaches(propertyCaches)
|
||||
, vmeMetaObjectData(vmeMetaObjectData)
|
||||
, _qobject(0)
|
||||
|
@ -546,11 +548,10 @@ QObject *QmlObjectCreator::create(int index, QObject *parent)
|
|||
{
|
||||
const QV4::CompiledData::Object *obj = unit->objectAt(index);
|
||||
|
||||
QQmlTypeNameCache::Result res = typeNameCache->query(stringAt(obj->inheritedTypeNameIndex));
|
||||
if (!res.isValid())
|
||||
return 0;
|
||||
QQmlType *type = resolvedTypes.value(obj->inheritedTypeNameIndex).type;
|
||||
Q_ASSERT(type);
|
||||
|
||||
QObject *result = res.type->create();
|
||||
QObject *result = type->create();
|
||||
// ### use no-event variant
|
||||
if (parent)
|
||||
result->setParent(parent);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <private/qqmlimport_p.h>
|
||||
#include <private/qqmltypenamecache_p.h>
|
||||
#include <private/qv4compileddata_p.h>
|
||||
#include <private/qqmlcompiler_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -54,7 +55,8 @@ class QQmlPropertyCacheCreator
|
|||
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator)
|
||||
public:
|
||||
QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit,
|
||||
const QUrl &url, QQmlTypeNameCache *typeNameCache, const QQmlImports *imports);
|
||||
const QUrl &url, const QQmlImports *imports,
|
||||
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes);
|
||||
|
||||
QList<QQmlError> errors;
|
||||
|
||||
|
@ -67,8 +69,8 @@ protected:
|
|||
QQmlEnginePrivate *enginePrivate;
|
||||
const QV4::CompiledData::QmlUnit *unit;
|
||||
QUrl url;
|
||||
QQmlTypeNameCache *typeNameCache;
|
||||
const QQmlImports *imports;
|
||||
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
|
||||
};
|
||||
|
||||
class QmlObjectCreator
|
||||
|
@ -76,7 +78,7 @@ class QmlObjectCreator
|
|||
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
|
||||
public:
|
||||
QmlObjectCreator(QQmlContextData *contextData, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::CompilationUnit *jsUnit,
|
||||
QQmlTypeNameCache *typeNameCache, const QList<QQmlPropertyCache *> &propertyCaches, const QList<QByteArray> &vmeMetaObjectData);
|
||||
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes, const QList<QQmlPropertyCache *> &propertyCaches, const QList<QByteArray> &vmeMetaObjectData);
|
||||
|
||||
QObject *create(QObject *parent = 0)
|
||||
{ return create(unit->indexOfRootObject, parent); }
|
||||
|
@ -102,7 +104,7 @@ private:
|
|||
const QV4::CompiledData::QmlUnit *unit;
|
||||
const QV4::CompiledData::CompilationUnit *jsUnit;
|
||||
QQmlContextData *context;
|
||||
QQmlTypeNameCache *typeNameCache;
|
||||
const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
|
||||
const QList<QQmlPropertyCache *> propertyCaches;
|
||||
const QList<QByteArray> vmeMetaObjectData;
|
||||
|
||||
|
|
|
@ -2167,6 +2167,13 @@ void QQmlTypeData::compile()
|
|||
m_imports.populateCache(m_compiledData->importCache);
|
||||
m_compiledData->importCache->addref();
|
||||
|
||||
for (QHash<int, TypeReference>::ConstIterator resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
|
||||
resolvedType != end; ++resolvedType) {
|
||||
QQmlCompiledData::TypeReference ref;
|
||||
ref.type = resolvedType->type;
|
||||
m_compiledData->resolvedTypes.insert(resolvedType.key(), ref);
|
||||
}
|
||||
|
||||
JSCodeGen jsCodeGen;
|
||||
jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), parsedQML.data());
|
||||
|
||||
|
@ -2196,8 +2203,8 @@ void QQmlTypeData::compile()
|
|||
m_compiledData->propertyCaches.reserve(qmlUnit->nObjects);
|
||||
|
||||
QQmlPropertyCacheCreator propertyCacheBuilder(QQmlEnginePrivate::get(m_typeLoader->engine()),
|
||||
qmlUnit, m_compiledData->url, m_compiledData->importCache,
|
||||
&m_imports);
|
||||
qmlUnit, m_compiledData->url,
|
||||
&m_imports, &m_compiledData->resolvedTypes);
|
||||
|
||||
for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
|
||||
|
@ -2255,10 +2262,10 @@ void QQmlTypeData::resolveTypes()
|
|||
m_scripts << ref;
|
||||
}
|
||||
|
||||
// --- old compiler:
|
||||
foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
|
||||
TypeReference ref;
|
||||
|
||||
QString url;
|
||||
int majorVersion = -1;
|
||||
int minorVersion = -1;
|
||||
QQmlImportNamespace *typeNamespace = 0;
|
||||
|
@ -2318,6 +2325,80 @@ void QQmlTypeData::resolveTypes()
|
|||
|
||||
m_types << ref;
|
||||
}
|
||||
|
||||
// --- new compiler:
|
||||
QV4::CompiledData::TypeReferenceMap typeReferences;
|
||||
QStringList names;
|
||||
if (parsedQML) {
|
||||
typeReferences = parsedQML->typeReferences;
|
||||
names = parsedQML->jsGenerator.strings;
|
||||
} else {
|
||||
// ### collect from available QV4::CompiledData::QmlUnit
|
||||
}
|
||||
for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = typeReferences.constBegin(), end = typeReferences.constEnd();
|
||||
unresolvedRef != end; ++unresolvedRef) {
|
||||
|
||||
TypeReference ref; // resolved reference
|
||||
|
||||
int majorVersion = -1;
|
||||
int minorVersion = -1;
|
||||
QQmlImportNamespace *typeNamespace = 0;
|
||||
QList<QQmlError> errors;
|
||||
|
||||
const QString name = names.at(unresolvedRef.key());
|
||||
bool typeFound = m_imports.resolveType(name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
|
||||
// Lazy loading of implicit import
|
||||
if (loadImplicitImport()) {
|
||||
// Try again to find the type
|
||||
errors.clear();
|
||||
typeFound = m_imports.resolveType(name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
} else {
|
||||
return; //loadImplicitImport() hit an error, and called setError already
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeFound || typeNamespace) {
|
||||
// Known to not be a type:
|
||||
// - known to be a namespace (Namespace {})
|
||||
// - type with unknown namespace (UnknownNamespace.SomeType {})
|
||||
QQmlError error;
|
||||
if (typeNamespace) {
|
||||
error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(name));
|
||||
} else {
|
||||
if (errors.size()) {
|
||||
error = errors.takeFirst();
|
||||
} else {
|
||||
// this should not be possible!
|
||||
// Description should come from error provided by addImport() function.
|
||||
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
|
||||
}
|
||||
error.setUrl(m_imports.baseUrl());
|
||||
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description()));
|
||||
}
|
||||
|
||||
error.setLine(unresolvedRef->line);
|
||||
error.setColumn(unresolvedRef->column);
|
||||
|
||||
errors.prepend(error);
|
||||
setError(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref.type->isComposite()) {
|
||||
ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
|
||||
addDependency(ref.typeData);
|
||||
}
|
||||
ref.majorVersion = majorVersion;
|
||||
ref.minorVersion = minorVersion;
|
||||
|
||||
ref.location.line = unresolvedRef->line;
|
||||
ref.location.column = unresolvedRef->column;
|
||||
|
||||
m_resolvedTypes.insert(unresolvedRef.key(), ref);
|
||||
}
|
||||
}
|
||||
|
||||
void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
|
||||
|
|
|
@ -457,7 +457,12 @@ private:
|
|||
|
||||
QSet<QString> m_namespaces;
|
||||
|
||||
// --- old compiler
|
||||
QList<TypeReference> m_types;
|
||||
// --- new compiler
|
||||
// map from name index to resolved type
|
||||
QHash<int, TypeReference> m_resolvedTypes;
|
||||
// ---
|
||||
bool m_typesResolved:1;
|
||||
bool m_useNewCompiler:1;
|
||||
|
||||
|
|
Loading…
Reference in New Issue