aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-05-19 16:38:55 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-05-24 15:44:16 +0200
commit6ff6c088c22938fc35690d385a9625f33c18a35a (patch)
tree30806408c396730e85fa4f3fe22424b49ad80d59
parenta75ddda71b9a1af2fccad85aca725798eb8aa8e4 (diff)
QmlCompiler: Add support for LoadElement on strings
In JavaScript the [] operator on strings returns a string. QString's operator[] returns a QChar, but we can easily create a string from that. Fixes: QTBUG-103371 Change-Id: Id5c960f00ecc7a5dfe30ccbcaac3ffb2a30308b9 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp15
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp3
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp2
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/typedArray.qml9
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/valueTypeLists.qml3
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp18
6 files changed, 45 insertions, 5 deletions
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 8568154e3c..8c89745a37 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -622,7 +622,9 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
const QQmlJSRegisterContent baseType = registerType(base);
- if (!m_typeResolver->isNumeric(m_state.accumulatorIn()) || !baseType.isList()) {
+ if (!m_typeResolver->isNumeric(m_state.accumulatorIn())
+ || (!baseType.isList()
+ && !m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType()))) {
reject(u"LoadElement with non-list base type or non-numeric arguments"_s);
return;
}
@@ -662,11 +664,16 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
const auto elementType = m_typeResolver->valueType(baseType);
+ QString access = baseName + u".at("_s + indexName + u')';
+
+ // TODO: Once we get a char type in QML, use it here.
+ if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType()))
+ access = u"QString("_s + access + u")"_s;
+
m_body += u"if ("_s + indexName + u" >= 0 && "_s + indexName
- + u" < "_s + baseName + u".count())\n"_s;
+ + u" < "_s + baseName + u".size())\n"_s;
m_body += u" "_s + m_state.accumulatorVariableOut + u" = "_s +
- conversion(elementType, m_state.accumulatorOut(),
- baseName + u".at("_s + indexName + u')') + u";\n"_s;
+ conversion(elementType, m_state.accumulatorOut(), access) + u";\n"_s;
m_body += u"else\n"_s
+ voidAssignment;
}
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 7f859061fa..27e120a832 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -652,7 +652,8 @@ void QQmlJSTypePropagator::generate_LoadElement(int base)
{
const QQmlJSRegisterContent baseRegister = m_state.registers[base];
- if (baseRegister.storedType()->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence
+ if ((baseRegister.storedType()->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence
+ && !m_typeResolver->registerIsStoredIn(baseRegister, m_typeResolver->stringType()))
|| !m_typeResolver->isNumeric(m_state.accumulatorIn())) {
const auto jsValue = m_typeResolver->globalType(m_typeResolver->jsValueType());
addReadAccumulator(jsValue);
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index c01cf5dfb3..623772027f 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -1178,6 +1178,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::valueType(const QQmlJSRegisterContent
return scope->valueType();
else if (equals(scope, m_jsValueType) || equals(scope, m_varType))
return m_jsValueType;
+ else if (equals(scope, m_stringType))
+ return m_stringType;
return QQmlJSScope::ConstPtr();
};
diff --git a/tests/auto/qml/qmlcppcodegen/data/typedArray.qml b/tests/auto/qml/qmlcppcodegen/data/typedArray.qml
index f9a40f5584..8d94d0832f 100644
--- a/tests/auto/qml/qmlcppcodegen/data/typedArray.qml
+++ b/tests/auto/qml/qmlcppcodegen/data/typedArray.qml
@@ -10,8 +10,17 @@ QtObject {
property list<date> values4: [aDate, aDate, aDate]
property list<real> values5: [1, 2, 3.4, "30", undefined, null]
property list<QtObject> values6: [self, self, self]
+ property string values7: "abcdef"
property int inIntList: values3[1]
property date inDateList: values4[2]
property real inRealList: values5[3]
+ property string inCharList: values7[5]
+
+ function stringAt10(s: string): int {
+ if (!s[10])
+ return 10;
+ else
+ return 20;
+ }
}
diff --git a/tests/auto/qml/qmlcppcodegen/data/valueTypeLists.qml b/tests/auto/qml/qmlcppcodegen/data/valueTypeLists.qml
index 83325641ab..cf58ae68c5 100644
--- a/tests/auto/qml/qmlcppcodegen/data/valueTypeLists.qml
+++ b/tests/auto/qml/qmlcppcodegen/data/valueTypeLists.qml
@@ -4,6 +4,7 @@ QtObject {
property list<rect> rectList: [ Qt.rect(1,2,3,4), Qt.rect(5,6,7,8), Qt.rect(9,10,11,12) ]
property list<string> stringList: ["aaa", "bbb", "ccc"]
property list<int> intList: [5, 6, 7, 8]
+ property string charList: "abcde"
property var rectInBounds: rectList[0]
property var rectOutOfBounds: rectList[32]
@@ -11,4 +12,6 @@ QtObject {
property var stringOutOfBounds: stringList[33]
property var intInBounds: intList[2]
property var intOutOfBounds: intList[34]
+ property var charInBounds: charList[3]
+ property var charOutOfBounds: charList[35]
}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index b4993d1752..84c5ad2deb 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -1955,6 +1955,20 @@ void tst_QmlCppCodegen::typedArray()
QCOMPARE(o->property("inIntList").toInt(), 2);
QCOMPARE(qvariant_cast<QDateTime>(o->property("inDateList")), date);
QCOMPARE(o->property("inRealList").toDouble(), 30.0);
+ QCOMPARE(o->property("inCharList").toString(), QStringLiteral("f"));
+
+ const QMetaObject *metaObject = o->metaObject();
+ QMetaMethod method = metaObject->method(metaObject->indexOfMethod("stringAt10(QString)"));
+ QVERIFY(method.isValid());
+
+ // If LoadElement threw an exception the function would certainly return neither 10 nor 20.
+ int result = 0;
+ method.invoke(
+ o.data(), Q_RETURN_ARG(int, result), Q_ARG(QString, QStringLiteral("a")));
+ QCOMPARE(result, 10);
+ method.invoke(
+ o.data(), Q_RETURN_ARG(int, result), Q_ARG(QString, QStringLiteral("aaaaaaaaaaa")));
+ QCOMPARE(result, 20);
}
void tst_QmlCppCodegen::prefixedType()
@@ -2126,6 +2140,10 @@ void tst_QmlCppCodegen::valueTypeLists()
QCOMPARE(qvariant_cast<int>(o->property("intInBounds")), 7);
QVERIFY(o->metaObject()->indexOfProperty("intOutOfBounds") > 0);
QVERIFY(!o->property("intOutOfBounds").isValid());
+
+ QCOMPARE(qvariant_cast<QString>(o->property("charInBounds")), QStringLiteral("d"));
+ QVERIFY(o->metaObject()->indexOfProperty("charOutOfBounds") > 0);
+ QVERIFY(!o->property("charOutOfBounds").isValid());
}
void tst_QmlCppCodegen::boundComponents()