aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2022-05-19 10:35:20 +0200
committerSami Shalayel <sami.shalayel@qt.io>2022-05-23 12:50:02 +0200
commit69cd8c2779d18e82d9872c9f55c45caa029365b0 (patch)
tree02a0ff180d6e7b010f07f0b00cc2cdf9b5aa05cc
parent6e2d70f2b8a0a02d01ca9dba759bd3d5eec32235 (diff)
qmlcompiler: Add qualified name to QQmlJSScope
Added moduleName and qualifiedName to QQmlJSScope. Those properties are written in the scopes after they were loaded by readQmlDir. Fixes: QTBUG-103299 Change-Id: I3b2c68c43c3bf0ac6cf801b0e54cf4b412b4d4e5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp23
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h1
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp33
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h16
-rw-r--r--tests/auto/qml/qqmljsscope/data/qualifiedName.qml41
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp60
6 files changed, 173 insertions, 1 deletions
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index 5f99a3c1da..9fcd031ef0 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -513,6 +513,7 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
return m_builtins;
Import result;
+ result.name = QStringLiteral("QML");
QStringList qmltypesFiles = { QStringLiteral("builtins.qmltypes"),
QStringLiteral("jsroot.qmltypes") };
@@ -523,7 +524,7 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
readQmltypes(it.next(), &result.objects, &result.dependencies);
qmltypesFiles.removeOne(it.fileName());
}
-
+ setQualifiedNamesOn(result);
importDependencies(result, &m_builtins);
if (qmltypesFiles.isEmpty())
@@ -731,6 +732,7 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
const QFileInfo file(qmldirPath);
if (file.exists()) {
const auto import = readQmldir(file.canonicalPath());
+ setQualifiedNamesOn(import);
m_seenQmldirFiles.insert(qmldirPath, import);
m_seenImports.insert(importId, qmldirPath);
importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
@@ -797,4 +799,23 @@ QQmlJSScope::ConstPtr QQmlJSImporter::jsGlobalObject() const
return m_builtins.cppNames[u"GlobalObject"_s].scope;
}
+void QQmlJSImporter::setQualifiedNamesOn(const Import &import)
+{
+ for (auto &object : import.objects) {
+ if (object.exports.isEmpty())
+ continue;
+ const QString qualifiedName = QQmlJSScope::qualifiedNameFrom(
+ import.name, object.exports.first().type(),
+ object.exports.first().revision(),
+ object.exports.last().revision());
+ if (auto *factory = object.scope.factory()) {
+ factory->setQualifiedName(qualifiedName);
+ factory->setModuleName(import.name);
+ } else {
+ object.scope->setQualifiedName(qualifiedName);
+ object.scope->setModuleName(import.name);
+ }
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h
index 7df909ffa0..b823e0403d 100644
--- a/src/qmlcompiler/qqmljsimporter_p.h
+++ b/src/qmlcompiler/qqmljsimporter_p.h
@@ -145,6 +145,7 @@ private:
Import readDirectory(const QString &directory);
QQmlJSScope::Ptr localFile2ScopeTree(const QString &filePath);
+ static void setQualifiedNamesOn(const Import &import);
QStringList m_importPaths;
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 73a1da74ea..148c8c122e 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -41,6 +41,21 @@
QT_BEGIN_NAMESPACE
+/*!
+ \class QQmlJSScope
+ \internal
+ \brief Tracks the types for the QmlCompiler
+
+ QQmlJSScope tracks the types used in qml for the QmlCompiler.
+
+ Multiple QQmlJSScope objects might be created for the same conceptual type, except when reused
+ due to extensive caching. Two QQmlJSScope objects are considered equal when they are backed
+ by the same implementation, that is, they have the same internalName.
+ The qualifiedName of the QQmlJSScope for a type imported from multiple modules will contain the
+ name of one of the modules that imported it, which is not unique and might change depending
+ on the caching in .
+*/
+
using namespace Qt::StringLiterals;
void QQmlJSScope::reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
@@ -781,6 +796,22 @@ bool QQmlJSScope::isNameDeferred(const QString &name) const
return isDeferred;
}
+QString QQmlJSScope::qualifiedNameFrom(const QString &moduleName, const QString &typeName,
+ const QTypeRevision &firstRevision,
+ const QTypeRevision &lastRevision)
+{
+ QString qualifiedName =
+ u"%1/%2 %3.%4"_s.arg(moduleName, typeName)
+ .arg(firstRevision.hasMajorVersion() ? firstRevision.majorVersion() : 0)
+ .arg(firstRevision.hasMinorVersion() ? firstRevision.minorVersion() : 0);
+ if (firstRevision != lastRevision) {
+ qualifiedName += u"-%1.%2"_s
+ .arg(lastRevision.hasMajorVersion() ? lastRevision.majorVersion() : 0)
+ .arg(lastRevision.hasMinorVersion() ? lastRevision.minorVersion() : 0);
+ }
+ return qualifiedName;
+}
+
void QQmlJSScope::setBaseTypeName(const QString &baseTypeName)
{
m_flags.setFlag(HasBaseTypeError, false);
@@ -915,6 +946,8 @@ bool QQmlJSScope::Export::isValid() const
void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
+ scope->setQualifiedName(m_qualifiedName);
+ scope->setModuleName(m_moduleName);
QQmlJSTypeReader typeReader(m_importer, m_filePath);
typeReader(scope);
m_importer->m_globalWarnings.append(typeReader.errors());
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 9c7b339f47..a2cc9a7e24 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -337,6 +337,14 @@ public:
QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; }
QTypeRevision baseTypeRevision() const { return m_baseType.revision; }
+ QString qualifiedName() const { return m_qualifiedName; }
+ void setQualifiedName(const QString &qualifiedName) { m_qualifiedName = qualifiedName; };
+ static QString qualifiedNameFrom(const QString &moduleName, const QString &typeName,
+ const QTypeRevision &firstRevision,
+ const QTypeRevision &lastRevision);
+ QString moduleName() const { return m_moduleName; }
+ void setModuleName(const QString &moduleName) { m_moduleName = moduleName; }
+
void clearBaseType() { m_baseType = {}; }
void setBaseTypeError(const QString &baseTypeError);
QString baseTypeError() const;
@@ -665,6 +673,9 @@ private:
AccessSemantics m_semantics = AccessSemantics::Reference;
QQmlJS::SourceLocation m_sourceLocation;
+
+ QString m_qualifiedName;
+ QString m_moduleName;
};
Q_DECLARE_TYPEINFO(QQmlJSScope::QmlIRCompatibilityBindingData, Q_RELOCATABLE_TYPE);
@@ -693,6 +704,9 @@ public:
m_isSingleton = isSingleton;
}
+ void setQualifiedName(const QString &qualifiedName) { m_qualifiedName = qualifiedName; }
+ void setModuleName(const QString &moduleName) { m_moduleName = moduleName; }
+
private:
friend class QDeferredSharedPointer<QQmlJSScope>;
friend class QDeferredSharedPointer<const QQmlJSScope>;
@@ -705,6 +719,8 @@ private:
QString m_filePath;
QQmlJSImporter *m_importer = nullptr;
bool m_isSingleton = false;
+ QString m_qualifiedName;
+ QString m_moduleName;
};
using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
diff --git a/tests/auto/qml/qqmljsscope/data/qualifiedName.qml b/tests/auto/qml/qqmljsscope/data/qualifiedName.qml
new file mode 100644
index 0000000000..56663254b0
--- /dev/null
+++ b/tests/auto/qml/qqmljsscope/data/qualifiedName.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.1 as MyQualifiedImport
+import QtQuick 2.0
+
+MyQualifiedImport.Item {
+ id:shouldBeQtQuickItem
+
+ Text {
+ id: shouldBeQtQuickText0
+ }
+
+ TextEdit {}
+
+ MyQualifiedImport.TextEdit {}
+
+ Component {
+ id: shouldBeQtQmlComponent
+
+ Item {
+
+ MyQualifiedImport.Text {
+ id: shouldBeQtQuickText1
+ }
+
+ Text {
+ id: shouldBeQtQuickText2
+ }
+
+ MyQualifiedImport.TextInput {
+ id: shouldBeQtQuickTextInput3
+ }
+
+ Timer {
+ id: indirectlyImportedFromQtQml
+ }
+
+ MyQualifiedImport.Timer {
+ id: indirectlyImportedFromQtQml2
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index cb1a03ab2b..4b7e26bcbc 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -130,6 +130,7 @@ private Q_SLOTS:
void scriptIndices();
void extensions();
void emptyBlockBinding();
+ void qualifiedName();
public:
tst_qqmljsscope()
@@ -640,5 +641,64 @@ void tst_qqmljsscope::emptyBlockBinding()
QVERIFY(root->hasOwnPropertyBindings(u"y"_s));
}
+void tst_qqmljsscope::qualifiedName()
+{
+ QQmlJSScope::ConstPtr root = run(u"qualifiedName.qml"_s);
+
+ auto qualifiedNameOf = [](const QQmlJSScope::ConstPtr &ptr) {
+ return ptr->baseType()->qualifiedName();
+ };
+
+ QQmlJSScope::ConstPtr item = root;
+
+ // normal case
+ QCOMPARE(qualifiedNameOf(item), "QtQuick/Item 2.0-6.3");
+
+ QCOMPARE(item->childScopes().size(), 4);
+ QQmlJSScope::ConstPtr textInItem = item->childScopes()[0];
+ QQmlJSScope::ConstPtr nonQualifiedComponentInItem = item->childScopes()[1];
+ QQmlJSScope::ConstPtr qualifiedComponentInItem = item->childScopes()[2];
+ QQmlJSScope::ConstPtr componentInItem = item->childScopes()[3];
+
+ // qualified case
+ QCOMPARE(qualifiedNameOf(nonQualifiedComponentInItem), "QtQuick/TextEdit 2.0-6.3");
+
+ // qualified case
+ QCOMPARE(qualifiedNameOf(qualifiedComponentInItem), "QtQuick/TextEdit 2.0-6.3");
+
+ // normal case
+ QCOMPARE(qualifiedNameOf(textInItem), "QtQuick/Text 2.0-6.3");
+ // qualified import of builtin variable
+ QCOMPARE(qualifiedNameOf(componentInItem), "QML/Component 1.0");
+ QCOMPARE(componentInItem->baseType()->moduleName(), "QML");
+
+ QCOMPARE(componentInItem->childScopes().size(), 1);
+
+ QQmlJSScope::ConstPtr itemInComponent = componentInItem->childScopes()[0];
+
+ QCOMPARE(qualifiedNameOf(itemInComponent), "QtQuick/Item 2.0-6.3");
+
+ QCOMPARE(itemInComponent->childScopes().size(), 5);
+ QQmlJSScope::ConstPtr qualifiedImportTextInItemInComponent = itemInComponent->childScopes()[0];
+ QQmlJSScope::ConstPtr textInItemInComponent = itemInComponent->childScopes()[1];
+ QQmlJSScope::ConstPtr qualifiedImportTextInputInItemInComponent =
+ itemInComponent->childScopes()[2];
+ QQmlJSScope::ConstPtr indirectImportTimerInItemInComponent = itemInComponent->childScopes()[3];
+ QQmlJSScope::ConstPtr qualifiedImportTimerInItemInComponent = itemInComponent->childScopes()[4];
+
+ QCOMPARE(qualifiedNameOf(qualifiedImportTextInItemInComponent), "QtQuick/Text 2.0-6.3");
+ QCOMPARE(qualifiedNameOf(textInItemInComponent), "QtQuick/Text 2.0-6.3");
+ QCOMPARE(textInItemInComponent->baseType()->moduleName(), "QtQuick");
+ QCOMPARE(qualifiedImportTextInItemInComponent->baseType()->moduleName(), "QtQuick");
+
+ QCOMPARE(qualifiedNameOf(qualifiedImportTextInputInItemInComponent),
+ "QtQuick/TextInput 2.0-6.3");
+
+ QCOMPARE(qualifiedNameOf(indirectImportTimerInItemInComponent), "QtQml/Timer 2.0-6.0");
+ QCOMPARE(qualifiedNameOf(qualifiedImportTimerInItemInComponent), "QtQml/Timer 2.0-6.0");
+ QCOMPARE(indirectImportTimerInItemInComponent->baseType()->moduleName(), "QtQml");
+ QCOMPARE(qualifiedImportTimerInItemInComponent->baseType()->moduleName(), "QtQml");
+}
+
QTEST_MAIN(tst_qqmljsscope)
#include "tst_qqmljsscope.moc"