diff options
Diffstat (limited to 'tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp')
-rw-r--r-- | tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp | 329 |
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" |