diff options
author | Robin Burchell <robin.burchell@crimson.no> | 2017-01-25 20:52:00 +0100 |
---|---|---|
committer | Robin Burchell <robin.burchell@crimson.no> | 2017-01-27 11:57:57 +0000 |
commit | e74a1d0b342f2c95dc3a543c8c9ec07fd52d8fe0 (patch) | |
tree | 082dbca3cdb0745e842ec33f03d422362e5e2e22 /src | |
parent | 2c2e7f27426cb4381f2dcaa36affe55719619753 (diff) |
Enable resolution of composite types in QQmlTypeNameCache
We didn't have resolution of composite types previously, which is a
prerequisite to do more exciting things with QML types in JavaScript
(such as instanceof).
By deferring the resolution to QQmlImports, we can avoid the need to
fill the cache with types that may not be needed, while still finding
types which are requested.
In the future, we could consider removing the "special" handling for composite
singletons as they should be found through QQmlImports now. If we do
that, we may still want to cache the QUrl for the types, to avoid using
QQmlImports too often directly, as it is a little slow itself.
This change doesn't regress tst_compilation.
Task-number: QTBUG-24799
Change-Id: I9ba2e4829ca49008fd180fb488c586475cf90674
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypenamecache.cpp | 57 | ||||
-rw-r--r-- | src/qml/qml/qqmltypenamecache_p.h | 8 |
4 files changed, 71 insertions, 8 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index e69789d5f4..257c280e50 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -400,9 +400,8 @@ QUrl QQmlImports::baseUrl() const document's imports into the \a cache for resolution elsewhere (e.g. in JS, or when loading additional types). - \note A current limitation of the implementation here is that only C++ types - are added to the type cache. This is due to file imports not having a - registered module. + \note This is for C++ types only. Composite types are handled separately, + as they do not have a QQmlTypeModule. */ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const { @@ -420,11 +419,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const const QQmlImportNamespace &set = *ns; + // positioning is important; we must create the namespace even if there is no module. + QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix]; + typeimport.m_qualifier = set.prefix; + for (int ii = set.imports.count() - 1; ii >= 0; --ii) { const QQmlImportInstance *import = set.imports.at(ii); QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion); if (module) { - QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix]; typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion)); } } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index a0781ee08b..8dea866c9a 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2602,7 +2602,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache ) const { - typeNameCache->adopt(new QQmlTypeNameCache); + typeNameCache->adopt(new QQmlTypeNameCache(m_importCache)); for (const QString &ns: m_namespaces) (*typeNameCache)->add(ns); @@ -2946,7 +2946,7 @@ void QQmlScriptBlob::done() } } - m_scriptData->typeNameCache = new QQmlTypeNameCache(); + m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache); QSet<QString> ns; diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index c2098bc9a1..b5b14d1ae8 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -43,7 +43,8 @@ QT_BEGIN_NAMESPACE -QQmlTypeNameCache::QQmlTypeNameCache() +QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache) + : m_imports(importCache) { } @@ -70,6 +71,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, { Import import; import.scriptIndex = importedScriptIndex; + import.m_qualifier = name; if (nameSpace.length() != 0) { Import *i = m_namedImports.value(nameSpace); @@ -94,6 +96,18 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) if (!result.isValid()) result = query(m_anonymousCompositeSingletons, name); + if (!result.isValid()) { + // Look up anonymous types from the imports of this document + QQmlImportNamespace *typeNamespace = 0; + QList<QQmlError> errors; + QQmlType *t = 0; + bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors); + if (typeFound) { + return Result(t); + } + + } + return result; } @@ -109,6 +123,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, if (!result.isValid()) result = query(i->compositeSingletons, name); + if (!result.isValid()) { + // Look up types from the imports of this document + // ### it would be nice if QQmlImports allowed us to resolve a namespace + // first, and then types on it. + QString qualifiedTypeName = i->m_qualifier + "." + name.toString(); + QQmlImportNamespace *typeNamespace = 0; + QList<QQmlError> errors; + QQmlType *t = 0; + bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); + if (typeFound) { + return Result(t); + } + } + return result; } @@ -122,6 +150,19 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons if (!result.isValid()) result = query(m_anonymousCompositeSingletons, name); + if (!result.isValid()) { + // Look up anonymous types from the imports of this document + QString typeName = name->toQStringNoThrow(); + QQmlImportNamespace *typeNamespace = 0; + QList<QQmlError> errors; + QQmlType *t = 0; + bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors); + if (typeFound) { + return Result(t); + } + + } + return result; } @@ -143,6 +184,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons if (!r.isValid()) r = query(i->compositeSingletons, name); + if (!r.isValid()) { + // Look up types from the imports of this document + // ### it would be nice if QQmlImports allowed us to resolve a namespace + // first, and then types on it. + QString qualifiedTypeName = i->m_qualifier + "." + name->toQStringNoThrow(); + QQmlImportNamespace *typeNamespace = 0; + QList<QQmlError> errors; + QQmlType *t = 0; + bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); + if (typeFound) { + return Result(t); + } + } + return r; } diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 8a387bed5f..7cdcbe91b6 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -56,6 +56,7 @@ #include "qqmlmetatype_p.h" #include <private/qhashedstring_p.h> +#include <private/qqmlimport_p.h> #include <QtCore/qvector.h> @@ -66,7 +67,7 @@ class QQmlEngine; class QQmlTypeNameCache : public QQmlRefCount { public: - QQmlTypeNameCache(); + QQmlTypeNameCache(const QQmlImports &imports); virtual ~QQmlTypeNameCache(); inline bool isEmpty() const; @@ -105,6 +106,9 @@ private: // Or, imported compositeSingletons QStringHash<QUrl> compositeSingletons; + + // The qualifier of this import + QString m_qualifier; }; template<typename Key> @@ -112,6 +116,7 @@ private: { Import *i = imports.value(key); if (i) { + Q_ASSERT(!i->m_qualifier.isEmpty()); if (i->scriptIndex != -1) { return Result(i->scriptIndex); } else { @@ -151,6 +156,7 @@ private: QMap<const Import *, QStringHash<Import> > m_namespacedImports; QVector<QQmlTypeModuleVersion> m_anonymousImports; QStringHash<QUrl> m_anonymousCompositeSingletons; + QQmlImports m_imports; }; QQmlTypeNameCache::Result::Result() |