diff options
-rw-r--r-- | src/qmlcompiler/qqmljsimporter_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/data/localImport_explicit.qml | 23 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/tst_qmltc.cpp | 21 | ||||
-rw-r--r-- | tests/auto/qml/qmltc/tst_qmltc.h | 1 | ||||
-rw-r--r-- | tools/qmltc/prototype/qml2cppdefaultpasses.cpp | 22 | ||||
-rw-r--r-- | tools/qmltc/prototype/typeresolver.cpp | 77 | ||||
-rw-r--r-- | tools/qmltc/prototype/typeresolver.h | 11 | ||||
-rw-r--r-- | tools/qmltc/prototype/visitor.cpp | 22 | ||||
-rw-r--r-- | tools/qmltc/prototype/visitor.h | 8 |
10 files changed, 70 insertions, 119 deletions
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h index 4cc22f4cfe..953f8d720e 100644 --- a/src/qmlcompiler/qqmljsimporter_p.h +++ b/src/qmlcompiler/qqmljsimporter_p.h @@ -65,6 +65,9 @@ public: QQmlJSScope::Ptr importFile(const QString &file); ImportedTypes importDirectory(const QString &directory, const QString &prefix = QString()); + // ### qmltc needs this. once re-written, we no longer need to expose this + QHash<QString, QQmlJSScope::Ptr> importedFiles() const { return m_importedFiles; } + ImportedTypes importModule(const QString &module, const QString &prefix = QString(), QTypeRevision version = QTypeRevision(), QStringList *staticModuleList = nullptr); diff --git a/tests/auto/qml/qmltc/CMakeLists.txt b/tests/auto/qml/qmltc/CMakeLists.txt index 90731f2e02..fc1d88e56a 100644 --- a/tests/auto/qml/qmltc/CMakeLists.txt +++ b/tests/auto/qml/qmltc/CMakeLists.txt @@ -41,6 +41,7 @@ set(qml_sources data/groupedProperty.qml data/groupedProperty_qquicktext.qml data/localImport.qml + data/localImport_explicit.qml data/newPropertyBoundToOld.qml data/oldPropertyBoundToNew.qml data/nonLocalQmlPropertyBoundToAny.qml diff --git a/tests/auto/qml/qmltc/data/localImport_explicit.qml b/tests/auto/qml/qmltc/data/localImport_explicit.qml new file mode 100644 index 0000000000..a5455cb5a9 --- /dev/null +++ b/tests/auto/qml/qmltc/data/localImport_explicit.qml @@ -0,0 +1,23 @@ +import QtQuick +import QmltcTests 1.0 + +LocallyImported { + property string derivedMessage: "derived" + message: "derived.message" + + baseObject: Text { + text: "derived.baseObject" + } + + Text { + text: "derived.child[0]" + } + + Rectangle { + property string text: "derived.child[1]" + } + + HelloWorld { + property string text: "derived.child[2]" + } +} diff --git a/tests/auto/qml/qmltc/tst_qmltc.cpp b/tests/auto/qml/qmltc/tst_qmltc.cpp index d16b1157c1..e93fd3bf24 100644 --- a/tests/auto/qml/qmltc/tst_qmltc.cpp +++ b/tests/auto/qml/qmltc/tst_qmltc.cpp @@ -57,6 +57,7 @@ #include "groupedproperty.h" #include "groupedproperty_qquicktext.h" #include "localimport.h" +#include "localimport_explicit.h" #include "newpropertyboundtoold.h" #include "oldpropertyboundtonew.h" #include "nonlocalqmlpropertyboundtoany.h" @@ -1169,11 +1170,9 @@ void tst_qmltc::groupedProperty_qquicktext() QCOMPARE(childAnchors->bottomMargin(), qreal(11)); } -void tst_qmltc::localImport() +template<typename T> +void localImport_impl(T &created) { - QQmlEngine e; - PREPEND_NAMESPACE(localImport) created(&e); - QCOMPARE(created.baseMessage(), QStringLiteral(u"base")); QCOMPARE(created.count(), 1); QCOMPARE(created.derivedMessage(), QStringLiteral(u"derived")); @@ -1201,6 +1200,20 @@ void tst_qmltc::localImport() QCOMPARE(children.at(2)->property("hello").toString(), QStringLiteral("Hello, World")); } +void tst_qmltc::localImport() +{ + QQmlEngine e; + PREPEND_NAMESPACE(localImport) created(&e); + localImport_impl(created); +} + +void tst_qmltc::explicitLocalImport() +{ + QQmlEngine e; + PREPEND_NAMESPACE(localImport_explicit) created(&e); + localImport_impl(created); +} + void tst_qmltc::newPropertyBoundToOld() { QQmlEngine e; diff --git a/tests/auto/qml/qmltc/tst_qmltc.h b/tests/auto/qml/qmltc/tst_qmltc.h index d6c4d3aec3..78a66cf8e5 100644 --- a/tests/auto/qml/qmltc/tst_qmltc.h +++ b/tests/auto/qml/qmltc/tst_qmltc.h @@ -72,6 +72,7 @@ private slots: void groupedProperty(); void groupedProperty_qquicktext(); void localImport(); + void explicitLocalImport(); void newPropertyBoundToOld(); void oldPropertyBoundToNew(); void nonLocalQmlPropertyBoundToAny(); diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp index 22767eee45..b4be78de7e 100644 --- a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp +++ b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp @@ -539,8 +539,7 @@ static void setupQmlCppType(const Qml2CppContext &context, const QQmlJSScope::Pt return; } - // TODO: in reality, the file path could be something else instead of - // "<qml_file_name>_qmltc.h", but this is not supported right now + // TODO: this does not cover QT_QMLTC_FILE_BASENAME renaming filePath = QFileInfo(filePath).baseName().toLower() + u".h"_qs; type->setFileName(filePath); // this file name will be discovered during findCppIncludes @@ -566,17 +565,26 @@ static void setupQmlCppType(const Qml2CppContext &context, const QQmlJSScope::Pt QSet<QString> setupQmlCppTypes(const Qml2CppContext &context, QList<Qml2CppObject> &objects) { + // TODO: in general, the whole logic here is incomplete. it will suffice as + // long as we only import QML types from our own module and C++ types from + // any module. importing QML types (that are presumably compiled) from + // external modules is not supported, so we can get away with it + QSet<QString> qmlBaseTypes; - QHash<QString, std::pair<QString, QQmlJSScope::Ptr>> qmlTypes = - context.typeResolver->gatherCompiledQmlTypes(); for (const auto &object : objects) { // 1. set up object itself setupQmlCppType(context, object.type, context.documentUrl); // 2. set up the base type if it is also QML originated - auto [url, potentialQmlType] = qmlTypes.value(object.type->baseTypeName()); - if (potentialQmlType) { // it is an actual QML type - setupQmlCppType(context, potentialQmlType, url); + if (auto base = object.type->baseType(); base->isComposite()) { + auto pair = context.typeResolver->importedType(base); + if (pair.first.isEmpty()) { + context.recordError(object.type->sourceLocation(), + u"QML base type has unknown origin. Do you miss an import?"_qs); + continue; + } + + setupQmlCppType(context, pair.second, pair.first); qmlBaseTypes.insert(object.type->baseTypeName()); } } diff --git a/tools/qmltc/prototype/typeresolver.cpp b/tools/qmltc/prototype/typeresolver.cpp index 5bfff44928..377787830e 100644 --- a/tools/qmltc/prototype/typeresolver.cpp +++ b/tools/qmltc/prototype/typeresolver.cpp @@ -39,44 +39,6 @@ Q_LOGGING_CATEGORY(lcTypeResolver2, "qml.compiler.typeresolver", QtInfoMsg); -static QString prefixedName(const QString &prefix, const QString &name) -{ - Q_ASSERT(!prefix.endsWith(u'.')); - return prefix.isEmpty() ? name : (prefix + QLatin1Char('.') + name); -} - -// TODO: this method is a (almost identical) copy-paste of QQmlJSImporter::importDirectory(). -static void customImportDirectory(QHash<QString, std::pair<QString, QQmlJSScope::Ptr>> &qmlTypes, - QQmlJSImporter *importer, const QString &directory, - const QString &prefix = QString()) -{ - if (directory.startsWith(u':')) { - if (QQmlJSResourceFileMapper *mapper = importer->resourceFileMapper()) { - const auto resources = mapper->filter( - QQmlJSResourceFileMapper::resourceQmlDirectoryFilter(directory.mid(1))); - for (const auto &entry : resources) { - const QString name = QFileInfo(entry.resourcePath).baseName(); - if (name.front().isUpper()) { - qmlTypes.insert( - prefixedName(prefix, name), - std::make_pair(entry.filePath, importer->importFile(entry.filePath))); - } - } - } - return; - } - - QDirIterator it { directory, QStringList() << QLatin1String("*.qml"), QDir::NoFilter }; - while (it.hasNext()) { - it.next(); - if (!it.fileName().front().isUpper()) - continue; // Non-uppercase names cannot be imported anyway. - - qmlTypes.insert(prefixedName(prefix, QFileInfo(it.filePath()).baseName()), - std::make_pair(it.filePath(), importer->importFile(it.filePath()))); - } -} - namespace Qmltc { TypeResolver::TypeResolver(QQmlJSImporter *importer) @@ -103,10 +65,6 @@ void TypeResolver::init(Visitor &visitor, QQmlJS::AST::Node *program) for (const auto &childScope : childScopes) objects.enqueue(childScope); } - - m_implicitImportDir = visitor.getImplicitImportDirectory(); - m_importedDirs = visitor.getImportedDirectories(); - m_importedFiles = visitor.getImportedQmlFiles(); } QQmlJSScope::Ptr TypeResolver::scopeForLocation(const QV4::CompiledData::Location &location) const @@ -116,33 +74,14 @@ QQmlJSScope::Ptr TypeResolver::scopeForLocation(const QV4::CompiledData::Locatio return m_objectsByLocationNonConst.value(location); } -QHash<QString, std::pair<QString, QQmlJSScope::Ptr>> TypeResolver::gatherCompiledQmlTypes() const +QPair<QString, QQmlJSScope::Ptr> TypeResolver::importedType(const QQmlJSScope::ConstPtr &type) const { - QHash<QString, std::pair<QString, QQmlJSScope::Ptr>> qmlTypes; - // implicit directory first - customImportDirectory(qmlTypes, m_importer, m_implicitImportDir); - // followed by subdirectories and absolute directories - for (const QString &dir : m_importedDirs) { - QString dirPath = dir; - const QFileInfo dirInfo(dir); - if (dirInfo.isRelative()) { - dirPath = QDir(m_implicitImportDir).filePath(dirPath); - } - customImportDirectory(qmlTypes, m_importer, dirPath); - } - // followed by individual files - for (const QString &file : m_importedFiles) { - QString filePath = file; - const QFileInfo fileInfo(file); - if (fileInfo.isRelative()) { - filePath = QDir(m_implicitImportDir).filePath(filePath); - } - // TODO: file importing is untested - const QString baseName = QFileInfo(filePath).baseName(); - if (baseName.front().isUpper()) - qmlTypes.insert(baseName, std::make_pair(filePath, m_importer->importFile(filePath))); - } - return qmlTypes; + const auto files = m_importer->importedFiles(); + auto it = std::find_if(files.cbegin(), files.cend(), [&](const QQmlJSScope::Ptr &importedType) { + return importedType.data() == type.data(); + }); + if (it == files.cend()) + return {}; + return { it.key(), it.value() }; } - } diff --git a/tools/qmltc/prototype/typeresolver.h b/tools/qmltc/prototype/typeresolver.h index dc747fd042..ff5fd19ef5 100644 --- a/tools/qmltc/prototype/typeresolver.h +++ b/tools/qmltc/prototype/typeresolver.h @@ -74,21 +74,14 @@ public: QQmlJSScope::Ptr scopeForLocation(const QV4::CompiledData::Location &location) const; - // returns a mapping from "QML name" (typically QML file name without - // extension) to {file path, QML scope/type pointer} pair. the mapping - // contains only native, non-C++ originated, QML types that would be - // compiled into C++. - QHash<QString, std::pair<QString, QQmlJSScope::Ptr>> gatherCompiledQmlTypes() const; + // returns an import pair {url, modifiable type} for a given \a type + QPair<QString, QQmlJSScope::Ptr> importedType(const QQmlJSScope::ConstPtr &type) const; private: QQmlJSImporter *m_importer = nullptr; QHash<QV4::CompiledData::Location, QQmlJSScope::Ptr> m_objectsByLocationNonConst; - QString m_implicitImportDir; // implicit QML import directory QQmlJSScope::Ptr m_root; - - QList<QString> m_importedDirs; - QList<QString> m_importedFiles; }; } diff --git a/tools/qmltc/prototype/visitor.cpp b/tools/qmltc/prototype/visitor.cpp index 07e5e41214..307cb992ea 100644 --- a/tools/qmltc/prototype/visitor.cpp +++ b/tools/qmltc/prototype/visitor.cpp @@ -38,28 +38,6 @@ Visitor::Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger, { } -bool Visitor::visit(QQmlJS::AST::UiImport *import) -{ - if (!QQmlJSImportVisitor::visit(import)) - return false; - - auto filename = import->fileName.toString(); - if (filename.isEmpty()) - return true; - - const QFileInfo file(filename); - const QString absolute = - file.isRelative() ? QDir(m_implicitImportDirectory).filePath(filename) : filename; - - QFileInfo path(absolute); - if (path.isDir()) { - m_importedDirectories.append(filename); - } else if (path.isFile() && absolute.endsWith(u".qml"_qs)) { - m_importedFiles.append(filename); - } - return true; -} - bool Visitor::visit(QQmlJS::AST::UiInlineComponent *component) { if (!QQmlJSImportVisitor::visit(component)) diff --git a/tools/qmltc/prototype/visitor.h b/tools/qmltc/prototype/visitor.h index 2df72b25ae..730021b66c 100644 --- a/tools/qmltc/prototype/visitor.h +++ b/tools/qmltc/prototype/visitor.h @@ -44,19 +44,11 @@ namespace Qmltc { class Visitor : public QQmlJSImportVisitor { - QStringList m_importedDirectories; - QStringList m_importedFiles; - public: Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger, const QString &implicitImportDirectory, const QStringList &qmltypesFiles = QStringList()); - bool visit(QQmlJS::AST::UiImport *import) override; bool visit(QQmlJS::AST::UiInlineComponent *) override; - - QString getImplicitImportDirectory() const { return m_implicitImportDirectory; } - QStringList getImportedDirectories() const { return m_importedDirectories; } - QStringList getImportedQmlFiles() const { return m_importedFiles; } }; } |