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>
This commit is contained in:
parent
6e2d70f2b8
commit
69cd8c2779
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue