aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmltc
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2021-12-16 12:41:11 +0100
committerAndrei Golubev <andrei.golubev@qt.io>2021-12-23 09:26:57 +0000
commitd5fa4a6bb7a1948cedbadceda6caa2ddfcf3db01 (patch)
tree3223b70c2061e5d0462e31cc1c5f1e1d64b53eba /tools/qmltc
parentb592f32f414c7eb1c14bbbe2ba7e9fa7f0178ea3 (diff)
qmltc: Fix explicit import of local QML types
qmltc passes re-import local QML types in order to get their URLs and modifiable versions of types. The existing logic seems to work only when we've already imported the types before. But re-import may, in fact, easily load *same* types from a *different* place. This is totally wrong and exceptionally evil (even within the passes). Re-write this logic by looking up the already-imported types from QQmlJSImportVisitor instead This, in particular, fixes a case: import MyOwnModule 1.0 MyOwnType { } // oops, does not include "myowntype.h" Change-Id: I35be7e41094c3bb9e210727a7a59bee33b548698 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@qt.io> (cherry picked from commit 0d40cde68ea89db46eac896a28ff65bd2c3ab40d)
Diffstat (limited to 'tools/qmltc')
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.cpp22
-rw-r--r--tools/qmltc/prototype/typeresolver.cpp77
-rw-r--r--tools/qmltc/prototype/typeresolver.h11
-rw-r--r--tools/qmltc/prototype/visitor.cpp22
-rw-r--r--tools/qmltc/prototype/visitor.h8
5 files changed, 25 insertions, 115 deletions
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; }
};
}