From 6e939f63b4e7b8ed678f4d551ada35dfb2e76e11 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 5 Dec 2012 11:36:37 -0800 Subject: Delay loading implicit import As a performance improvement to avoid accessing the filesystem unnecessarily, only import "." implicitly if types cannot be found in the existing imports. This is not a behavior change for type resolution, because "." already has the lowest precedence for type resolution. Change-Id: I5ac2a9fac85559eb96cba93c29d17068fe8171da Manual cherry-pick of qtquick1/dc96bfd00152e25f007511f64bff7c413f657886 Reviewed-by: Christopher Adams --- src/declarative/qml/qdeclarativeimport.cpp | 28 +++++++-- src/declarative/qml/qdeclarativescriptparser_p.h | 2 +- src/declarative/qml/qdeclarativetypeloader.cpp | 72 +++++++++++++--------- .../qdeclarativelanguage/data/LocalLast2.qml | 2 + .../qdeclarativelanguage/data/localOrderTest.qml | 7 +++ .../tst_qdeclarativelanguage.cpp | 23 +++++++ 6 files changed, 98 insertions(+), 36 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/LocalLast2.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/localOrderTest.qml diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index c7a0d78..0518bcb 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -452,6 +452,13 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp set.insert(prefix,(s=new QDeclarativeImportedNamespace)); } + bool appendInstead = false; + if (importType == QDeclarativeScriptParser::Import::Implicit) { + //Treat same as a File import, but lower precedence + appendInstead = true; + importType = QDeclarativeScriptParser::Import::File; + } + QString url = uri; bool versionFound = false; if (importType == QDeclarativeScriptParser::Import::Library) { @@ -599,12 +606,21 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp } } - s->uris.prepend(uri); - s->urls.prepend(url); - s->majversions.prepend(vmaj); - s->minversions.prepend(vmin); - s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library); - s->qmlDirComponents.prepend(qmldircomponents); + if (appendInstead) { + s->uris.append(uri); + s->urls.append(url); + s->majversions.append(vmaj); + s->minversions.append(vmin); + s->isLibrary.append(importType == QDeclarativeScriptParser::Import::Library); + s->qmlDirComponents.append(qmldircomponents); + } else { + s->uris.prepend(uri); + s->urls.prepend(url); + s->majversions.prepend(vmaj); + s->minversions.prepend(vmin); + s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library); + s->qmlDirComponents.prepend(qmldircomponents); + } return true; } diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h index 671326a..0d02aba 100644 --- a/src/declarative/qml/qdeclarativescriptparser_p.h +++ b/src/declarative/qml/qdeclarativescriptparser_p.h @@ -75,7 +75,7 @@ public: public: Import() : type(Library) {} - enum Type { Library, File, Script }; + enum Type { Library, File, Script, Implicit }; //Implicit is only used internally Type type; QString uri; diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 5cce995..50c3639 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -1055,19 +1055,6 @@ void QDeclarativeTypeData::resolveTypes() QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine()); QDeclarativeImportDatabase *importDatabase = &ep->importDatabase; - // For local urls, add an implicit import "." as first (most overridden) lookup. - // This will also trigger the loading of the qmldir and the import of any native - // types from available plugins. - if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) { - m_imports.addImport(importDatabase, QLatin1String("."), - QString(), -1, -1, QDeclarativeScriptParser::Import::File, - qmldir->dirComponents(), 0); - } else { - m_imports.addImport(importDatabase, QLatin1String("."), - QString(), -1, -1, QDeclarativeScriptParser::Import::File, - QDeclarativeDirComponents(), 0); - } - foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) { QDeclarativeDirComponents qmldircomponentsnetwork; if (import.type == QDeclarativeScriptParser::Import::Script) @@ -1107,6 +1094,7 @@ void QDeclarativeTypeData::resolveTypes() } } + bool implicitImportLoaded = false; foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) { QByteArray typeName = parserRef->name.toUtf8(); @@ -1123,23 +1111,49 @@ void QDeclarativeTypeData::resolveTypes() // Known to not be a type: // - known to be a namespace (Namespace {}) // - type with unknown namespace (UnknownNamespace.SomeType {}) - QDeclarativeError error; - error.setUrl(m_imports.baseUrl()); - QString userTypeName = parserRef->name; - userTypeName.replace(QLatin1Char('/'),QLatin1Char('.')); - if (typeNamespace) - error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName)); - else - error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString)); - - if (!parserRef->refObjects.isEmpty()) { - QDeclarativeParser::Object *obj = parserRef->refObjects.first(); - error.setLine(obj->location.start.line); - error.setColumn(obj->location.start.column); + bool typeFound = false; + + if (!typeNamespace && !implicitImportLoaded) { + implicitImportLoaded = true; + // For local urls, add an implicit import "." as most overridden lookup. + // This will also trigger the loading of the qmldir and the import of any native + // types from available plugins. + // This is only done if the type is not otherwise found, side effects of plugin loading may be avoided + // ### This should be an acceptable variation because A) It's only side effects (and img providers) B) You shouldn't be doing that in "." anyways! + if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) { + m_imports.addImport(importDatabase, QLatin1String("."), + QString(), -1, -1, QDeclarativeScriptParser::Import::Implicit, + qmldir->dirComponents(), 0); + } else { + m_imports.addImport(importDatabase, QLatin1String("."), + QString(), -1, -1, QDeclarativeScriptParser::Import::Implicit, + QDeclarativeDirComponents(), 0); + } + if (m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion, + &typeNamespace, &errorString) || typeNamespace) { + typeFound = true; + } + } + + if (!typeFound) { + QDeclarativeError error; + error.setUrl(m_imports.baseUrl()); + QString userTypeName = parserRef->name; + userTypeName.replace(QLatin1Char('/'),QLatin1Char('.')); + if (typeNamespace) + error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName)); + else + error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString)); + + if (!parserRef->refObjects.isEmpty()) { + QDeclarativeParser::Object *obj = parserRef->refObjects.first(); + error.setLine(obj->location.start.line); + error.setColumn(obj->location.start.column); + } + + setError(error); + return; } - - setError(error); - return; } if (ref.type) { diff --git a/tests/auto/declarative/qdeclarativelanguage/data/LocalLast2.qml b/tests/auto/declarative/qdeclarativelanguage/data/LocalLast2.qml new file mode 100644 index 0000000..4bf7eb2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/LocalLast2.qml @@ -0,0 +1,2 @@ +import QtQuick 1.0 +MouseArea {} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/localOrderTest.qml b/tests/auto/declarative/qdeclarativelanguage/data/localOrderTest.qml new file mode 100644 index 0000000..d5db212 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/localOrderTest.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 +import org.qtproject.installedtest 1.0 + +LocalLast2 { + property QtObject item: LocalLast {} +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 40ff989..6068dfd 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -136,6 +136,7 @@ private slots: void reservedWords(); void inlineAssignmentsOverrideBindings(); void nestedComponentRoots(); + void implicitImportsLast(); void basicRemote_data(); void basicRemote(); @@ -1820,6 +1821,11 @@ void tst_qdeclarativelanguage::importsOrder_data() "LocalLast {}" << (!qmlCheckTypes()?"QDeclarativeRectangle":"")// i.e. from org.qtproject.installedtest, not data/LocalLast.qml << (!qmlCheckTypes()?"":"LocalLast is ambiguous. Found in lib/org/qtproject/installedtest and in local directory"); + QTest::newRow("local last 3") << + "import org.qtproject.installedtest 1.0\n" + "LocalLast {LocalLast2{}}" + << (!qmlCheckTypes()?"QDeclarativeRectangle":"")// i.e. from org.qtproject.installedtest, not data/LocalLast.qml + << (!qmlCheckTypes()?"":"LocalLast is ambiguous. Found in lib/org/qtproject/installedtest and in local directory"); } void tst_qdeclarativelanguage::importsOrder() @@ -2024,6 +2030,23 @@ void tst_qdeclarativelanguage::aliasPropertyChangeSignals() } } +// Tests that the implicit import has lowest precedence, in the case where +// there are conflicting types and types only found in the local import. +// Tests that just check one (or the root) type are in ::importsOrder +void tst_qdeclarativelanguage::implicitImportsLast() +{ + if (qmlCheckTypes()) + QSKIP("This test is about maintaining the same choice when type is ambiguous.", SkipAll); + QDeclarativeComponent component(&engine, TEST_FILE("localOrderTest.qml")); + VERIFY_ERRORS(0); + QObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QDeclarativeMouseArea"))); + QObject* object2 = object->property("item").value(); + QVERIFY(object2 != 0); + QCOMPARE(QString(object2->metaObject()->className()), QLatin1String("QDeclarativeRectangle")); +} + QTEST_MAIN(tst_qdeclarativelanguage) #include "tst_qdeclarativelanguage.moc" -- cgit v0.12