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 <andrei.golubev@qt.io>
This commit is contained in:
parent
30251c0781
commit
7917b7ad64
|
@ -1335,7 +1335,8 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name,
|
||||||
QString literalType;
|
QString literalType;
|
||||||
QQmlJSMetaPropertyBinding::BindingType bindingType = QQmlJSMetaPropertyBinding::Invalid;
|
QQmlJSMetaPropertyBinding::BindingType bindingType = QQmlJSMetaPropertyBinding::Invalid;
|
||||||
|
|
||||||
switch (exprStatement->expression->kind) {
|
auto expr = exprStatement->expression;
|
||||||
|
switch (expr->kind) {
|
||||||
case Node::Kind_TrueLiteral:
|
case Node::Kind_TrueLiteral:
|
||||||
value = true;
|
value = true;
|
||||||
literalType = u"bool"_qs;
|
literalType = u"bool"_qs;
|
||||||
|
@ -1356,21 +1357,21 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name,
|
||||||
break;
|
break;
|
||||||
case Node::Kind_NumericLiteral:
|
case Node::Kind_NumericLiteral:
|
||||||
literalType = u"double"_qs;
|
literalType = u"double"_qs;
|
||||||
value = cast<NumericLiteral *>(exprStatement->expression)->value;
|
value = cast<NumericLiteral *>(expr)->value;
|
||||||
bindingType = QQmlJSMetaPropertyBinding::NumberLiteral;
|
bindingType = QQmlJSMetaPropertyBinding::NumberLiteral;
|
||||||
break;
|
break;
|
||||||
case Node::Kind_StringLiteral:
|
case Node::Kind_StringLiteral:
|
||||||
literalType = u"string"_qs;
|
literalType = u"string"_qs;
|
||||||
value = cast<StringLiteral *>(exprStatement->expression)->value.toString();
|
value = cast<StringLiteral *>(expr)->value.toString();
|
||||||
bindingType = QQmlJSMetaPropertyBinding::StringLiteral;
|
bindingType = QQmlJSMetaPropertyBinding::StringLiteral;
|
||||||
break;
|
break;
|
||||||
case Node::Kind_RegExpLiteral:
|
case Node::Kind_RegExpLiteral:
|
||||||
literalType = u"regexp"_qs;
|
literalType = u"regexp"_qs;
|
||||||
value = cast<RegExpLiteral *>(exprStatement->expression)->pattern.toString();
|
value = cast<RegExpLiteral *>(expr)->pattern.toString();
|
||||||
bindingType = QQmlJSMetaPropertyBinding::RegExpLiteral;
|
bindingType = QQmlJSMetaPropertyBinding::RegExpLiteral;
|
||||||
break;
|
break;
|
||||||
case Node::Kind_TemplateLiteral: {
|
case Node::Kind_TemplateLiteral: {
|
||||||
auto templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(exprStatement->expression);
|
auto templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
|
||||||
Q_ASSERT(templateLit);
|
Q_ASSERT(templateLit);
|
||||||
value = templateLit->value.toString();
|
value = templateLit->value.toString();
|
||||||
if (templateLit->hasNoSubstitution) {
|
if (templateLit->hasNoSubstitution) {
|
||||||
|
@ -1382,7 +1383,14 @@ void QQmlJSImportVisitor::parseLiteralBinding(const QString name,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return;
|
if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
|
||||||
|
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
|
||||||
|
literalType = u"double"_qs;
|
||||||
|
bindingType = QQmlJSMetaPropertyBinding::NumberLiteral;
|
||||||
|
value = -lit->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QQmlJSMetaPropertyBinding::isLiteralBinding(bindingType))
|
if (!QQmlJSMetaPropertyBinding::isLiteralBinding(bindingType))
|
||||||
|
|
|
@ -146,6 +146,9 @@ void QQmlJSTypeResolver::init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *p
|
||||||
.arg(binding.literalTypeName())
|
.arg(binding.literalTypeName())
|
||||||
.arg(property.typeName()),
|
.arg(property.typeName()),
|
||||||
Log_Type, binding.sourceLocation());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQml
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
property string i: 1
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQml
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
property string i: -1
|
||||||
|
}
|
|
@ -515,6 +515,16 @@ void TestQmllint::dirtyQmlCode_data()
|
||||||
<< QStringLiteral("Cannot assign binding of type QString to int")
|
<< QStringLiteral("Cannot assign binding of type QString to int")
|
||||||
<< QString()
|
<< QString()
|
||||||
<< false;
|
<< 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")
|
QTest::newRow("BadBinding")
|
||||||
<< QStringLiteral("badBinding.qml")
|
<< QStringLiteral("badBinding.qml")
|
||||||
<< QStringLiteral("Binding assigned to \"doesNotExist\", but no property "
|
<< QStringLiteral("Binding assigned to \"doesNotExist\", but no property "
|
||||||
|
|
Loading…
Reference in New Issue