aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp')
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp329
1 files changed, 263 insertions, 66 deletions
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index 09c6601858..4dacc17f94 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuickTestUtils/private/qmlutils_p.h>
@@ -35,9 +35,9 @@ class tst_qqmljsscope : public QQmlDataTest
{
const QFileInfo fi(url);
QFile f(fi.absoluteFilePath());
- f.open(QIODevice::ReadOnly);
- QByteArray data(fi.size(), Qt::Uninitialized);
- f.read(data.data(), data.size());
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Could not open file %s", qPrintable(url));
+ QByteArray data = f.readAll();
return QString::fromUtf8(data);
}
@@ -71,6 +71,7 @@ class tst_qqmljsscope : public QQmlDataTest
logger.setCode(sourceCode);
logger.setSilent(expectErrorsOrWarnings);
QQmlJSScope::Ptr target = QQmlJSScope::create();
+ target->setOwnModuleName(u"HelloModule"_s);
QQmlJSImportVisitor visitor(target, &m_importer, &logger, dataDirectory());
QQmlJSTypeResolver typeResolver { &m_importer };
typeResolver.init(&visitor, document->program);
@@ -92,6 +93,7 @@ private Q_SLOTS:
void signalCreationDifferences();
void allTypesAvailable();
void shadowing();
+ void requiredAlias();
#ifdef LABS_QML_MODELS_PRESENT
void componentWrappedObjects();
@@ -106,9 +108,15 @@ private Q_SLOTS:
void scriptIndices();
void extensions();
void emptyBlockBinding();
- void qualifiedName();
+ void hasOwnEnumerationKeys();
+ void ownModuleName();
void resolvedNonUniqueScopes();
void compilationUnitsAreCompatible();
+ void attachedTypeResolution_data();
+ void attachedTypeResolution();
+ void builtinTypeResolution_data();
+ void builtinTypeResolution();
+ void methodAndSignalSourceLocation();
public:
tst_qqmljsscope()
@@ -160,14 +168,14 @@ void tst_qqmljsscope::orderedBindings()
QCOMPARE(std::distance(pBindingsBegin, pBindingsEnd), 2);
// check that the bindings are properly ordered
- QCOMPARE(pBindingsBegin->bindingType(), QQmlJSMetaPropertyBinding::Object);
- QCOMPARE(std::next(pBindingsBegin)->bindingType(), QQmlJSMetaPropertyBinding::Interceptor);
+ QCOMPARE(pBindingsBegin->bindingType(), QQmlSA::BindingType::Object);
+ QCOMPARE(std::next(pBindingsBegin)->bindingType(), QQmlSA::BindingType::Interceptor);
auto [itemsBindingsBegin, itemsBindingsEnd] = root->ownPropertyBindings(u"items"_s);
QCOMPARE(std::distance(itemsBindingsBegin, itemsBindingsEnd), 2);
- QCOMPARE(itemsBindingsBegin->bindingType(), QQmlJSMetaPropertyBinding::Object);
- QCOMPARE(std::next(itemsBindingsBegin)->bindingType(), QQmlJSMetaPropertyBinding::Object);
+ QCOMPARE(itemsBindingsBegin->bindingType(), QQmlSA::BindingType::Object);
+ QCOMPARE(std::next(itemsBindingsBegin)->bindingType(), QQmlSA::BindingType::Object);
QCOMPARE(itemsBindingsBegin->objectType()->baseTypeName(), u"Item"_s);
QCOMPARE(std::next(itemsBindingsBegin)->objectType()->baseTypeName(), u"Text"_s);
@@ -184,8 +192,8 @@ void tst_qqmljsscope::signalCreationDifferences()
const auto conflicting = root->ownMethods(u"conflictingPropertyChanged"_s);
QCOMPARE(conflicting.size(), 2);
- QCOMPARE(conflicting[0].methodType(), QQmlJSMetaMethod::Signal);
- QCOMPARE(conflicting[1].methodType(), QQmlJSMetaMethod::Signal);
+ QCOMPARE(conflicting[0].methodType(), QQmlJSMetaMethodType::Signal);
+ QCOMPARE(conflicting[1].methodType(), QQmlJSMetaMethodType::Signal);
const QQmlJSMetaMethod *explicitMethod = nullptr;
if (conflicting[0].isImplicitQmlPropertyChangeSignal())
@@ -204,7 +212,7 @@ void tst_qqmljsscope::allTypesAvailable()
QQmlJSImporter importer { importPaths, /* resource file mapper */ nullptr };
const auto imported = importer.importModule(u"QtQml"_s);
- QCOMPARE(imported.context(), QQmlJSScope::ContextualTypes::QML);
+ QCOMPARE(imported.context(), QQmlJS::ContextualTypes::QML);
const auto types = imported.types();
QVERIFY(types.contains(u"$internal$.QObject"_s));
QVERIFY(types.contains(u"QtObject"_s));
@@ -235,6 +243,16 @@ void tst_qqmljsscope::shadowing()
QCOMPARE(methods[u"method_shadowed"_s].parameterNames().size(), 0);
}
+void tst_qqmljsscope::requiredAlias()
+{
+ QQmlJSScope::ConstPtr root = run(u"requiredAlias.qml"_s);
+ QVERIFY(root);
+
+ // Check whether aliases marked as required are required
+ QVERIFY(root->isPropertyRequired("sameScopeAlias"));
+ QVERIFY(root->isPropertyRequired("innerScopeAlias"));
+}
+
#ifdef LABS_QML_MODELS_PRESENT
void tst_qqmljsscope::componentWrappedObjects()
{
@@ -302,7 +320,7 @@ void tst_qqmljsscope::groupedProperties()
const auto getBindingsWithinGroup =
[&](QMultiHash<QString, QQmlJSMetaPropertyBinding> *bindings, qsizetype index) -> void {
const auto &binding = anchorBindings[index];
- QCOMPARE(binding.bindingType(), QQmlJSMetaPropertyBinding::GroupProperty);
+ QCOMPARE(binding.bindingType(), QQmlSA::BindingType::GroupProperty);
auto anchorScope = binding.groupType();
QVERIFY(anchorScope);
*bindings = anchorScope->ownPropertyBindings();
@@ -316,14 +334,14 @@ void tst_qqmljsscope::groupedProperties()
QMultiHash<QString, QQmlJSMetaPropertyBinding> bindingsOfType;
getBindingsWithinGroup(&bindingsOfType, 0);
QCOMPARE(bindingsOfType.size(), 2);
- QCOMPARE(value(bindingsOfType, u"left"_s).bindingType(), QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(value(bindingsOfType, u"left"_s).bindingType(), QQmlSA::BindingType::Script);
QCOMPARE(value(bindingsOfType, u"leftMargin"_s).bindingType(),
- QQmlJSMetaPropertyBinding::NumberLiteral);
+ QQmlSA::BindingType::NumberLiteral);
QMultiHash<QString, QQmlJSMetaPropertyBinding> bindingsOfBaseType;
getBindingsWithinGroup(&bindingsOfBaseType, 1);
QCOMPARE(bindingsOfBaseType.size(), 1);
- QCOMPARE(value(bindingsOfBaseType, u"top"_s).bindingType(), QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(value(bindingsOfBaseType, u"top"_s).bindingType(), QQmlSA::BindingType::Script);
}
void tst_qqmljsscope::descriptiveNameOfNull()
@@ -337,8 +355,10 @@ void tst_qqmljsscope::descriptiveNameOfNull()
property.setPropertyName(u"foo"_s);
property.setTypeName(u"baz"_s);
QQmlJSRegisterContent unscoped = QQmlJSRegisterContent::create(
- stored, property, QQmlJSRegisterContent::ScopeProperty, QQmlJSScope::ConstPtr());
- QCOMPARE(unscoped.descriptiveName(), u"bar of (invalid type)::foo with type baz"_s);
+ stored, property, QQmlJSRegisterContent::InvalidLookupIndex,
+ QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ScopeProperty,
+ QQmlJSScope::ConstPtr());
+ QCOMPARE(unscoped.descriptiveName(), u"(invalid type)::foo with type baz (stored as bar)"_s);
}
void tst_qqmljsscope::groupedPropertiesConsistency()
@@ -363,8 +383,8 @@ void tst_qqmljsscope::groupedPropertiesConsistency()
// The binding order in QQmlJSScope case is "reversed": first come
// bindings on the leaf type, followed by the bindings on the base type
- QCOMPARE(fontBindings[0].bindingType(), QQmlJSMetaPropertyBinding::GroupProperty);
- QCOMPARE(fontBindings[1].bindingType(), QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(fontBindings[0].bindingType(), QQmlSA::BindingType::GroupProperty);
+ QCOMPARE(fontBindings[1].bindingType(), QQmlSA::BindingType::Script);
}
}
@@ -378,7 +398,7 @@ void tst_qqmljsscope::groupedPropertySyntax()
// The binding order in QQmlJSScope case is "reversed": first come
// bindings on the leaf type, followed by the bindings on the base type
- QCOMPARE(fontBindings[0].bindingType(), QQmlJSMetaPropertyBinding::GroupProperty);
+ QCOMPARE(fontBindings[0].bindingType(), QQmlSA::BindingType::GroupProperty);
auto fontScope = fontBindings[0].groupType();
QVERIFY(fontScope);
QCOMPARE(fontScope->accessSemantics(), QQmlJSScope::AccessSemantics::Value);
@@ -390,9 +410,8 @@ void tst_qqmljsscope::groupedPropertySyntax()
return bindings.value(key, QQmlJSMetaPropertyBinding(QQmlJS::SourceLocation {}));
};
- QCOMPARE(value(subbindings, u"pixelSize"_s).bindingType(),
- QQmlJSMetaPropertyBinding::NumberLiteral);
- QCOMPARE(value(subbindings, u"bold"_s).bindingType(), QQmlJSMetaPropertyBinding::BoolLiteral);
+ QCOMPARE(value(subbindings, u"pixelSize"_s).bindingType(), QQmlSA::BindingType::NumberLiteral);
+ QCOMPARE(value(subbindings, u"bold"_s).bindingType(), QQmlSA::BindingType::BoolLiteral);
}
void tst_qqmljsscope::attachedProperties()
@@ -407,7 +426,7 @@ void tst_qqmljsscope::attachedProperties()
const auto getBindingsWithinAttached =
[&](QMultiHash<QString, QQmlJSMetaPropertyBinding> *bindings, qsizetype index) -> void {
const auto &binding = keysBindings[index];
- QCOMPARE(binding.bindingType(), QQmlJSMetaPropertyBinding::AttachedProperty);
+ QCOMPARE(binding.bindingType(), QQmlSA::BindingType::AttachedProperty);
auto keysScope = binding.attachingType();
QVERIFY(keysScope);
QCOMPARE(keysScope->accessSemantics(), QQmlJSScope::AccessSemantics::Reference);
@@ -422,23 +441,21 @@ void tst_qqmljsscope::attachedProperties()
QMultiHash<QString, QQmlJSMetaPropertyBinding> bindingsOfType;
getBindingsWithinAttached(&bindingsOfType, 0);
QCOMPARE(bindingsOfType.size(), 2);
- QCOMPARE(value(bindingsOfType, u"enabled"_s).bindingType(),
- QQmlJSMetaPropertyBinding::BoolLiteral);
- QCOMPARE(value(bindingsOfType, u"forwardTo"_s).bindingType(),
- QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(value(bindingsOfType, u"enabled"_s).bindingType(), QQmlSA::BindingType::BoolLiteral);
+ QCOMPARE(value(bindingsOfType, u"forwardTo"_s).bindingType(), QQmlSA::BindingType::Script);
QMultiHash<QString, QQmlJSMetaPropertyBinding> bindingsOfBaseType;
getBindingsWithinAttached(&bindingsOfBaseType, 1);
QCOMPARE(bindingsOfBaseType.size(), 1);
- QCOMPARE(value(bindingsOfBaseType, u"priority"_s).bindingType(),
- QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(value(bindingsOfBaseType, u"priority"_s).bindingType(), QQmlSA::BindingType::Script);
}
inline QString getScopeName(const QQmlJSScope::ConstPtr &scope)
{
Q_ASSERT(scope);
QQmlJSScope::ScopeType type = scope->scopeType();
- if (type == QQmlJSScope::GroupedPropertyScope || type == QQmlJSScope::AttachedPropertyScope)
+ if (type == QQmlSA::ScopeType::GroupedPropertyScope
+ || type == QQmlSA::ScopeType::AttachedPropertyScope)
return scope->internalName();
return scope->baseTypeName();
}
@@ -507,7 +524,7 @@ void tst_qqmljsscope::scriptIndices()
QmlIR::Document document(false); // we need QmlIR information here
QQmlJSScope::ConstPtr root = run(u"functionAndBindingIndices.qml"_s, &document);
QVERIFY(root);
- QVERIFY(document.javaScriptCompilationUnit.unitData());
+ QVERIFY(document.javaScriptCompilationUnit->unitData());
// compare QQmlJSScope and QmlIR:
@@ -537,8 +554,9 @@ void tst_qqmljsscope::scriptIndices()
const auto suitableScope = [](const QQmlJSScope::ConstPtr &scope) {
const auto type = scope->scopeType();
- return type == QQmlJSScope::QMLScope || type == QQmlJSScope::GroupedPropertyScope
- || type == QQmlJSScope::AttachedPropertyScope;
+ return type == QQmlSA::ScopeType::QMLScope
+ || type == QQmlSA::ScopeType::GroupedPropertyScope
+ || type == QQmlSA::ScopeType::AttachedPropertyScope;
};
QList<QQmlJSScope::ConstPtr> queue;
@@ -550,7 +568,7 @@ void tst_qqmljsscope::scriptIndices()
if (suitableScope(current)) {
const auto methods = current->ownMethods();
for (const auto &method : methods) {
- if (method.methodType() == QQmlJSMetaMethod::Signal)
+ if (method.methodType() == QQmlJSMetaMethodType::Signal)
continue;
QString name = method.methodName();
auto relativeIndex = method.jsFunctionIndex();
@@ -563,7 +581,7 @@ void tst_qqmljsscope::scriptIndices()
const auto bindings = current->ownPropertyBindings();
for (const auto &binding : bindings) {
- if (binding.bindingType() != QQmlJSMetaPropertyBinding::Script)
+ if (binding.bindingType() != QQmlSA::BindingType::Script)
continue;
QString name = binding.propertyName();
auto relativeIndex = binding.scriptIndex();
@@ -674,28 +692,50 @@ void tst_qqmljsscope::emptyBlockBinding()
QVERIFY(root->hasOwnPropertyBindings(u"y"_s));
}
-void tst_qqmljsscope::qualifiedName()
+void tst_qqmljsscope::hasOwnEnumerationKeys()
{
- QQmlJSScope::ConstPtr root = run(u"qualifiedName.qml"_s);
+ QQmlJSScope::ConstPtr root = run(u"extensions.qml"_s);
QVERIFY(root);
+ QQmlJSScope::ConstPtr extendedDerived = root->childScopes().front();
+ QVERIFY(extendedDerived);
+ // test that enumeration keys from base cannot be found
+ QVERIFY(!extendedDerived->hasOwnEnumerationKey(u"ThisIsTheEnumFromExtended"_s));
+ QVERIFY(!extendedDerived->hasOwnEnumerationKey(u"ThisIsTheFlagFromExtended"_s));
+
+ QQmlJSScope::ConstPtr extended = extendedDerived->baseType();
+ QVERIFY(extended);
+
+ QVERIFY(extended->hasOwnEnumerationKey(u"ThisIsTheEnumFromExtended"_s));
+ QVERIFY(extended->hasOwnEnumerationKey(u"ThisIsTheFlagFromExtended"_s));
+ QVERIFY(!extended->hasOwnEnumerationKey(u"ThisIsTheEnumFromExtension"_s));
+ QVERIFY(!extended->hasOwnEnumerationKey(u"ThisIsTheFlagFromExtension"_s));
+}
- auto qualifiedNameOf = [](const QQmlJSScope::ConstPtr &ptr) -> QString {
- if (ptr->baseType())
- return ptr->baseType()->qualifiedName();
- else
- return u""_s;
- };
-
- QCOMPARE(root->childScopes().size(), 4);
- QQmlJSScope::ConstPtr b = root->childScopes()[0];
- QQmlJSScope::ConstPtr d = root->childScopes()[1];
- QQmlJSScope::ConstPtr qualifiedA = root->childScopes()[2];
- QQmlJSScope::ConstPtr qualifiedB = root->childScopes()[3];
-
- QCOMPARE(qualifiedNameOf(b), "QualifiedNamesTests/B 5.0-6.0");
- QCOMPARE(qualifiedNameOf(d), "QualifiedNamesTests/D 6.0");
- QCOMPARE(qualifiedNameOf(qualifiedA), "QualifiedNamesTests/A 5.0");
- QCOMPARE(qualifiedNameOf(qualifiedB), "QualifiedNamesTests/B 5.0-6.0");
+void tst_qqmljsscope::ownModuleName()
+{
+ const QString moduleName = u"HelloModule"_s;
+ QQmlJSScope::ConstPtr root = run(u"ownModuleName.qml"_s);
+ QVERIFY(root);
+ QCOMPARE(root->moduleName(), moduleName);
+ QCOMPARE(root->ownModuleName(), moduleName);
+
+ QCOMPARE(root->childScopes().size(), 2);
+ QQmlJSScope::ConstPtr child = root->childScopes().front();
+ QVERIFY(child);
+ // only root and inline components have own module names, but the child should be able to query
+ // its component's module Name via moduleName()
+ QCOMPARE(child->ownModuleName(), QString());
+ QCOMPARE(child->moduleName(), moduleName);
+
+ QQmlJSScope::ConstPtr ic = root->childScopes()[1];
+ QVERIFY(ic);
+ QCOMPARE(ic->ownModuleName(), moduleName);
+ QCOMPARE(ic->moduleName(), moduleName);
+
+ QQmlJSScope::ConstPtr icChild = ic->childScopes().front();
+ QVERIFY(icChild);
+ QCOMPARE(icChild->ownModuleName(), QString());
+ QCOMPARE(icChild->moduleName(), moduleName);
}
void tst_qqmljsscope::resolvedNonUniqueScopes()
@@ -711,32 +751,32 @@ void tst_qqmljsscope::resolvedNonUniqueScopes()
{
auto topLevelBindings = root->propertyBindings(u"Component"_s);
QCOMPARE(topLevelBindings.size(), 1);
- QCOMPARE(topLevelBindings[0].bindingType(), QQmlJSMetaPropertyBinding::AttachedProperty);
+ QCOMPARE(topLevelBindings[0].bindingType(), QQmlSA::BindingType::AttachedProperty);
auto componentScope = topLevelBindings[0].attachingType();
auto componentBindings = componentScope->ownPropertyBindings();
QCOMPARE(componentBindings.size(), 2);
auto onCompletedBinding = value(componentBindings, u"onCompleted"_s);
QVERIFY(onCompletedBinding.isValid());
- QCOMPARE(onCompletedBinding.bindingType(), QQmlJSMetaPropertyBinding::Script);
- QCOMPARE(onCompletedBinding.scriptKind(), QQmlJSMetaPropertyBinding::Script_SignalHandler);
+ QCOMPARE(onCompletedBinding.bindingType(), QQmlSA::BindingType::Script);
+ QCOMPARE(onCompletedBinding.scriptKind(), QQmlSA::ScriptBindingKind::SignalHandler);
auto onDestructionBinding = value(componentBindings, u"onDestruction"_s);
QVERIFY(onDestructionBinding.isValid());
- QCOMPARE(onDestructionBinding.bindingType(), QQmlJSMetaPropertyBinding::Script);
+ QCOMPARE(onDestructionBinding.bindingType(), QQmlSA::BindingType::Script);
QCOMPARE(onDestructionBinding.scriptKind(),
- QQmlJSMetaPropertyBinding::Script_SignalHandler);
+ QQmlSA::ScriptBindingKind::SignalHandler);
}
{
auto topLevelBindings = root->propertyBindings(u"p"_s);
QCOMPARE(topLevelBindings.size(), 1);
- QCOMPARE(topLevelBindings[0].bindingType(), QQmlJSMetaPropertyBinding::GroupProperty);
+ QCOMPARE(topLevelBindings[0].bindingType(), QQmlSA::BindingType::GroupProperty);
auto pScope = topLevelBindings[0].groupType();
auto pBindings = pScope->ownPropertyBindings();
QCOMPARE(pBindings.size(), 1);
auto onXChangedBinding = value(pBindings, u"onXChanged"_s);
QVERIFY(onXChangedBinding.isValid());
- QCOMPARE(onXChangedBinding.bindingType(), QQmlJSMetaPropertyBinding::Script);
- QCOMPARE(onXChangedBinding.scriptKind(), QQmlJSMetaPropertyBinding::Script_SignalHandler);
+ QCOMPARE(onXChangedBinding.bindingType(), QQmlSA::BindingType::Script);
+ QCOMPARE(onXChangedBinding.scriptKind(), QQmlSA::ScriptBindingKind::SignalHandler);
}
}
@@ -777,8 +817,8 @@ void tst_qqmljsscope::compilationUnitsAreCompatible()
QmlIR::Document document(false); // we need QmlIR information here
QVERIFY(run(url, &document));
- QVERIFY(document.javaScriptCompilationUnit.unitData());
- getRuntimeInfoFromCompilationUnit(document.javaScriptCompilationUnit.unitData(),
+ QVERIFY(document.javaScriptCompilationUnit->unitData());
+ getRuntimeInfoFromCompilationUnit(document.javaScriptCompilationUnit->unitData(),
cachegenFunctions);
if (QTest::currentTestFailed())
return;
@@ -791,5 +831,162 @@ void tst_qqmljsscope::compilationUnitsAreCompatible()
QCOMPARE(uint(cachegenFunctions[i]->nameIndex), uint(componentFunctions[i]->nameIndex));
}
+void tst_qqmljsscope::attachedTypeResolution_data()
+{
+ QTest::addColumn<bool>("creatable");
+ QTest::addColumn<QString>("moduleName");
+ QTest::addColumn<QString>("typeName");
+ QTest::addColumn<QString>("attachedTypeName");
+ QTest::addColumn<QString>("propertyOnSelf");
+ QTest::addColumn<QString>("propertyOnAttached");
+
+ QTest::addRow("ListView") << true
+ << "QtQuick"
+ << "ListView"
+ << "QQuickListViewAttached"
+ << "orientation"
+ << "";
+ QTest::addRow("Keys") << false
+ << "QtQuick"
+ << "Keys"
+ << "QQuickKeysAttached"
+ << "priority"
+ << "priority";
+}
+
+class TestPass : public QQmlSA::ElementPass
+{
+public:
+ TestPass(QQmlSA::PassManager *manager) : QQmlSA::ElementPass(manager) { }
+ bool shouldRun(const QQmlSA::Element &) override { return true; }
+ void run(const QQmlSA::Element &) override { }
+};
+
+using PassManagerPtr = std::unique_ptr<
+ QQmlSA::PassManager, decltype(&QQmlSA::PassManagerPrivate::deletePassManager)>;
+
+void tst_qqmljsscope::attachedTypeResolution()
+{
+ QFETCH(bool, creatable);
+ QFETCH(QString, moduleName);
+ QFETCH(QString, typeName);
+ QFETCH(QString, attachedTypeName);
+ QFETCH(QString, propertyOnSelf);
+ QFETCH(QString, propertyOnAttached);
+
+ std::unique_ptr<QQmlJSLogger> logger = std::make_unique<QQmlJSLogger>();
+ QFile qmlFile("data/attachedTypeResolution.qml");
+ if (!qmlFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ QSKIP("Unable to open qml file");
+
+ logger->setCode(qmlFile.readAll());
+ logger->setFileName(QString(qmlFile.filesystemFileName().string().c_str()));
+ QQmlJSImporter importer{ { "data" }, nullptr, true };
+ QStringList defaultImportPaths =
+ QStringList{ QLibraryInfo::path(QLibraryInfo::QmlImportsPath) };
+ importer.setImportPaths(defaultImportPaths);
+ QQmlJSTypeResolver resolver(&importer);
+ const auto &implicitImportDirectory = QQmlJSImportVisitor::implicitImportDirectory(
+ logger->fileName(), importer.resourceFileMapper());
+ QQmlJSImportVisitor v{
+ QQmlJSScope::create(), &importer, logger.get(), implicitImportDirectory, {}
+ };
+
+ PassManagerPtr manager(
+ QQmlSA::PassManagerPrivate::createPassManager(&v, &resolver),
+ &QQmlSA::PassManagerPrivate::deletePassManager);
+
+ TestPass pass{ manager.get() };
+ const auto &resolved = pass.resolveType(moduleName, typeName);
+
+ QVERIFY(!resolved.isNull());
+ const auto &attachedType = pass.resolveAttached(moduleName, typeName);
+ QVERIFY(!attachedType.isNull());
+ QCOMPARE(attachedType.name(), attachedTypeName);
+
+ if (propertyOnAttached != "") {
+ QEXPECT_FAIL("Keys", "Keys and QQuickKeysAttached have the same properties", Continue);
+ QVERIFY(!resolved.hasProperty(propertyOnAttached));
+ QVERIFY(attachedType.hasProperty(propertyOnAttached));
+ }
+ if (propertyOnSelf != "") {
+ QEXPECT_FAIL("Keys", "Keys and QQuickKeysAttached have the same properties", Continue);
+ QVERIFY(!attachedType.hasProperty(propertyOnSelf));
+ }
+
+ if (creatable)
+ QVERIFY(resolved.hasProperty(propertyOnSelf));
+}
+
+
+
+void tst_qqmljsscope::builtinTypeResolution_data()
+{
+ QTest::addColumn<bool>("valid");
+ QTest::addColumn<QString>("typeName");
+
+ QTest::addRow("global_QtObject") << true << "Qt";
+ QTest::addRow("function") << true << "function";
+ QTest::addRow("Array") << true << "Array";
+ QTest::addRow("invalid") << false << "foobar";
+ QTest::addRow("Number") << true << "Number";
+ QTest::addRow("bool") << true << "bool";
+ QTest::addRow("QString") << true << "QString";
+}
+
+void tst_qqmljsscope::builtinTypeResolution()
+{
+ QFETCH(bool, valid);
+ QFETCH(QString, typeName);
+
+ QQmlJSImporter importer{ { "data" }, nullptr, true };
+ QStringList defaultImportPaths =
+ QStringList{ QLibraryInfo::path(QLibraryInfo::QmlImportsPath) };
+ importer.setImportPaths(defaultImportPaths);
+ QQmlJSTypeResolver resolver(&importer);
+ const auto &implicitImportDirectory = QQmlJSImportVisitor::implicitImportDirectory({}, nullptr);
+ QQmlJSLogger logger;
+ QQmlJSImportVisitor v{
+ QQmlJSScope::create(), &importer, &logger, implicitImportDirectory, {}
+ };
+
+ PassManagerPtr manager(
+ QQmlSA::PassManagerPrivate::createPassManager(&v, &resolver),
+ &QQmlSA::PassManagerPrivate::deletePassManager);
+
+ TestPass pass{ manager.get() };
+ auto element = pass.resolveBuiltinType(typeName);
+ QCOMPARE(element.isNull(), !valid);
+}
+
+void tst_qqmljsscope::methodAndSignalSourceLocation()
+{
+ QmlIR::Document document(false);
+ auto jsscope = run(u"methodAndSignalSourceLocation.qml"_s, false);
+
+ std::array<std::array<int, 9>, 2> offsetsByLineEnding = {
+ std::array{ 29, 51, 74, 102, 128, 160, 219, 235, 257 }, // 1 char line endings
+ std::array{ 32, 55, 79, 108, 135, 168, 231, 248, 271 } // 2 char line endinds
+ };
+
+ // Try to detect the size of line endings as they lead to different source locations
+ auto offset1 = jsscope->methods("f1")[0].sourceLocation().offset;
+ QVERIFY(offset1 == 29 || offset1 == 32);
+ bool oneCharEndings = offset1 == 29;
+ std::array<int, 9> &offsets = oneCharEndings ? offsetsByLineEnding[0] : offsetsByLineEnding[1];
+
+ using namespace QQmlJS;
+ QCOMPARE(jsscope->methods("f1")[0].sourceLocation(), SourceLocation(offsets[0], 17, 4, 5));
+ QCOMPARE(jsscope->methods("f2")[0].sourceLocation(), SourceLocation(offsets[1], 18, 5, 5));
+ QCOMPARE(jsscope->methods("f3")[0].sourceLocation(), SourceLocation(offsets[2], 23, 6, 5));
+ QCOMPARE(jsscope->methods("f4")[0].sourceLocation(), SourceLocation(offsets[3], 21, 7, 5));
+ QCOMPARE(jsscope->methods("f5")[0].sourceLocation(), SourceLocation(offsets[4], 27, 8, 5));
+ QCOMPARE(jsscope->methods("f6")[0].sourceLocation(), SourceLocation(offsets[5], oneCharEndings ? 53 : 55, 9, 5));
+
+ QCOMPARE(jsscope->methods("s1")[0].sourceLocation(), SourceLocation(offsets[6], 11, 13, 5));
+ QCOMPARE(jsscope->methods("s2")[0].sourceLocation(), SourceLocation(offsets[7], 17, 14, 5));
+ QCOMPARE(jsscope->methods("s3")[0].sourceLocation(), SourceLocation(offsets[8], 28, 15, 5));
+}
+
QTEST_MAIN(tst_qqmljsscope)
#include "tst_qqmljsscope.moc"