From 7917b7ad6435b9a340f8c748b17f6ddcc5732544 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 6 Dec 2021 16:48:41 +0100 Subject: [PATCH] qmllint: Warn about assigning numeric types to strings While it is generally possible to assign a numeric to a value of string type, this is not the case for literal bindings: There, the engine's QQmlTypeValidator notices the mismatch, and rejects the program. Bring qmllint in line with that behavior. Additionally, teach parseLiteralBinding to treat constant UnaryMinusExpressions as NumberLiteral bindings. Change-Id: Iad221e90eb1de81cabdddf5d601cc30f53ef20d3 Reviewed-by: Andrei Golubev --- src/qmlcompiler/qqmljsimportvisitor.cpp | 20 +++++++++++++------ src/qmlcompiler/qqmljstyperesolver.cpp | 3 +++ .../qmllint/data/numberToStringProperty.qml | 5 +++++ .../data/unaryMinusToStringProperty.qml | 5 +++++ tests/auto/qml/qmllint/tst_qmllint.cpp | 10 ++++++++++ 5 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 tests/auto/qml/qmllint/data/numberToStringProperty.qml create mode 100644 tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 69c40790d9..254c282e26 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -1335,7 +1335,8 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name, QString literalType; QQmlJSMetaPropertyBinding::BindingType bindingType = QQmlJSMetaPropertyBinding::Invalid; - switch (exprStatement->expression->kind) { + auto expr = exprStatement->expression; + switch (expr->kind) { case Node::Kind_TrueLiteral: value = true; literalType = u"bool"_qs; @@ -1356,21 +1357,21 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name, break; case Node::Kind_NumericLiteral: literalType = u"double"_qs; - value = cast(exprStatement->expression)->value; + value = cast(expr)->value; bindingType = QQmlJSMetaPropertyBinding::NumberLiteral; break; case Node::Kind_StringLiteral: literalType = u"string"_qs; - value = cast(exprStatement->expression)->value.toString(); + value = cast(expr)->value.toString(); bindingType = QQmlJSMetaPropertyBinding::StringLiteral; break; case Node::Kind_RegExpLiteral: literalType = u"regexp"_qs; - value = cast(exprStatement->expression)->pattern.toString(); + value = cast(expr)->pattern.toString(); bindingType = QQmlJSMetaPropertyBinding::RegExpLiteral; break; case Node::Kind_TemplateLiteral: { - auto templateLit = QQmlJS::AST::cast(exprStatement->expression); + auto templateLit = QQmlJS::AST::cast(expr); Q_ASSERT(templateLit); value = templateLit->value.toString(); if (templateLit->hasNoSubstitution) { @@ -1382,7 +1383,14 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name, break; } default: - return; + if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast(expr)) { + if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast(unaryMinus->expression)) { + literalType = u"double"_qs; + bindingType = QQmlJSMetaPropertyBinding::NumberLiteral; + value = -lit->value; + } + } + break; } if (!QQmlJSMetaPropertyBinding::isLiteralBinding(bindingType)) diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index 16df494770..6cfe756ab8 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -146,6 +146,9 @@ void QQmlJSTypeResolver::init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *p .arg(binding.literalTypeName()) .arg(property.typeName()), Log_Type, binding.sourceLocation()); + } else if (property.type() == m_stringType && isNumeric(binding.literalType())) { + m_logger->logWarning(u"Cannot assign a numeric constant to a string property"_qs, + Log_Type, binding.sourceLocation()); } } } diff --git a/tests/auto/qml/qmllint/data/numberToStringProperty.qml b/tests/auto/qml/qmllint/data/numberToStringProperty.qml new file mode 100644 index 0000000000..6da8566ce3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/numberToStringProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property string i: 1 +} diff --git a/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml b/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml new file mode 100644 index 0000000000..c1c51fa796 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property string i: -1 +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index dab4663227..37ba64fdd2 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -515,6 +515,16 @@ void TestQmllint::dirtyQmlCode_data() << QStringLiteral("Cannot assign binding of type QString to int") << QString() << false; + QTest::newRow("bad constant number to string") + << QStringLiteral("numberToStringProperty.qml") + << QStringLiteral("Cannot assign a numeric constant to a string property") + << QString() + << false; + QTest::newRow("bad unary minus to string") + << QStringLiteral("unaryMinusToStringProperty.qml") + << QStringLiteral("Cannot assign a numeric constant to a string property") + << QString() + << false; QTest::newRow("BadBinding") << QStringLiteral("badBinding.qml") << QStringLiteral("Binding assigned to \"doesNotExist\", but no property "