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>
This commit is contained in:
parent
2c2e7f2742
commit
e74a1d0b34
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import QtQuick 2.6
|
||||
import "simpleimportByName"
|
||||
|
||||
Item {
|
||||
Component.onCompleted: {
|
||||
console.warn(SimpleType)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import QtQuick 2.6
|
||||
import "simpleimportByName" as ImportName
|
||||
|
||||
Item {
|
||||
Component.onCompleted: {
|
||||
console.warn(ImportName.SimpleType)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.6
|
||||
|
||||
Item {
|
||||
Component.onCompleted: {
|
||||
console.warn(Item)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.6 as Quick
|
||||
|
||||
Quick.Item {
|
||||
Quick.Component.onCompleted: {
|
||||
console.warn(Quick.Item)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import QtQuick 2.6
|
||||
|
||||
MouseArea {
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
SimpleType 1.0 SimpleType.qml
|
|
@ -257,6 +257,9 @@ private slots:
|
|||
void defaultListProperty();
|
||||
void namespacedPropertyTypes();
|
||||
|
||||
void qmlTypeCanBeResolvedByName_data();
|
||||
void qmlTypeCanBeResolvedByName();
|
||||
|
||||
private:
|
||||
QQmlEngine engine;
|
||||
QStringList defaultImportPathList;
|
||||
|
@ -4250,6 +4253,32 @@ void tst_qqmllanguage::namespacedPropertyTypes()
|
|||
QVERIFY(!o.isNull());
|
||||
}
|
||||
|
||||
void tst_qqmllanguage::qmlTypeCanBeResolvedByName_data()
|
||||
{
|
||||
QTest::addColumn<QUrl>("componentUrl");
|
||||
|
||||
// Built-in C++ types
|
||||
QTest::newRow("C++ - Anonymous") << testFileUrl("quickTypeByName_anon.qml");
|
||||
QTest::newRow("C++ - Named") << testFileUrl("quickTypeByName_named.qml");
|
||||
|
||||
// Composite types with a qmldir
|
||||
QTest::newRow("QML - Anonymous - qmldir") << testFileUrl("compositeTypeByName_anon_qmldir.qml");
|
||||
QTest::newRow("QML - Named - qmldir") << testFileUrl("compositeTypeByName_named_qmldir.qml");
|
||||
}
|
||||
|
||||
void tst_qqmllanguage::qmlTypeCanBeResolvedByName()
|
||||
{
|
||||
QFETCH(QUrl, componentUrl);
|
||||
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine, componentUrl);
|
||||
VERIFY_ERRORS(0);
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "[object Object]"); // a bit crude, but it will do
|
||||
|
||||
QScopedPointer<QObject> o(component.create());
|
||||
QVERIFY(!o.isNull());
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmllanguage)
|
||||
|
||||
#include "tst_qqmllanguage.moc"
|
||||
|
|
Loading…
Reference in New Issue