diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2022-01-12 15:41:24 +0100 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2022-01-17 19:53:06 +0100 |
commit | 0790bc85a121275a0fd48090706b72a28b51f1e0 (patch) | |
tree | 3b0a8846771fffb815da002f7388dfc436ef70d6 | |
parent | c2598d344dfeb339ef791380737c9ad660151896 (diff) | |
download | qtdeclarative-0790bc85a121275a0fd48090706b72a28b51f1e0.tar.gz |
qmlcompiler: Add proper null type
Previously we treated null as a generic primitive value (in functions)
or as a var type (in literal bindings), this change ends this practice
by introducing an uniform null type used everywhere and defined in
builtins.
Now we can also properly warn about setting properties to null if they
aren't variants.
Fixes: QTBUG-98409
Change-Id: If32420a59948696491f24521bbc0f251095a9699
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/imports/builtins/builtins.qmltypes | 5 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsmetatypes_p.h | 6 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstyperesolver.cpp | 9 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstyperesolver_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/nullBinding.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/nullBindingFunction.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 8 |
10 files changed, 40 insertions, 6 deletions
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes index 0bc89d8c9c..93f6019901 100644 --- a/src/imports/builtins/builtins.qmltypes +++ b/src/imports/builtins/builtins.qmltypes @@ -11,6 +11,11 @@ Module { } Component { + name: "std::nullptr_t" + accessSemantics: "none" + } + + Component { name: "QVariant" accessSemantics: "value" exports: ["QML/var 1.0", "QML/variant 1.0"] diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp index e6efb9d649..1d52a2582b 100644 --- a/src/qmlcompiler/qqmljscodegenerator.cpp +++ b/src/qmlcompiler/qqmljscodegenerator.cpp @@ -473,7 +473,7 @@ void QQmlJSCodeGenerator::generate_LoadNull() INJECT_TRACE_INFO(generate_LoadNull); m_body += m_state.accumulatorVariableOut; - m_body += u" = QJSPrimitiveNull()"_qs; + m_body += u" = nullptr"_qs; m_body += u";\n"_qs; } diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 1530a6cc89..87e6b0d7e0 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -1412,7 +1412,7 @@ bool QQmlJSImportVisitor::parseLiteralBinding(const QString name, // QQmlJSMetaPropertyBinding::hasLiteral() value = QVariant::fromValue(nullptr); Q_ASSERT(value.isNull()); - literalType = u"var"_qs; // QTBUG-98409 + literalType = u"$anonymous$.std::nullptr_t"_qs; bindingType = QQmlJSMetaPropertyBinding::Null; break; case Node::Kind_NumericLiteral: diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h index 903ab1992d..c68010be30 100644 --- a/src/qmlcompiler/qqmljsmetatypes_p.h +++ b/src/qmlcompiler/qqmljsmetatypes_p.h @@ -503,7 +503,11 @@ public: QString valueSourceTypeName() const { return m_valueSourceTypeName; } QSharedPointer<const QQmlJSScope> valueSourceType() const { return m_valueSource; } - bool hasLiteral() const { return isLiteralBinding() && !m_literalValue.isNull(); } + bool hasLiteral() const + { + return isLiteralBinding() + && (!m_literalValue.isNull() || m_bindingType == QQmlJSMetaPropertyBinding::Null); + } bool hasObject() const { return m_bindingType == BindingType::Object && !m_value.isNull(); } bool hasInterceptor() const { diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index 54cbf1e02b..900d642cff 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -139,7 +139,7 @@ void QQmlJSTypePropagator::generate_LoadFalse() void QQmlJSTypePropagator::generate_LoadNull() { - m_state.accumulatorOut = m_typeResolver->globalType(m_typeResolver->jsPrimitiveType()); + m_state.accumulatorOut = m_typeResolver->globalType(m_typeResolver->nullType()); } void QQmlJSTypePropagator::generate_LoadUndefined() diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index 9c5264e68d..0cc4a83963 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -67,6 +67,7 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer) { const QHash<QString, QQmlJSScope::ConstPtr> builtinTypes = importer->builtinInternalNames(); m_voidType = builtinTypes[u"void"_qs]; + m_nullType = builtinTypes[u"std::nullptr_t"_qs]; m_realType = builtinTypes[u"double"_qs]; m_floatType = builtinTypes[u"float"_qs]; m_intType = builtinTypes[u"int"_qs]; @@ -291,7 +292,8 @@ bool QQmlJSTypeResolver::isNumeric(const QQmlJSRegisterContent &type) const bool QQmlJSTypeResolver::isPrimitive(const QQmlJSScope::ConstPtr &type) const { return type == m_intType || type == m_realType || type == m_floatType || type == m_boolType - || type == m_voidType || type == m_stringType || type == m_jsPrimitiveType; + || type == m_voidType || type == m_nullType || type == m_stringType + || type == m_jsPrimitiveType; } bool QQmlJSTypeResolver::isNumeric(const QQmlJSScope::ConstPtr &type) const @@ -386,8 +388,11 @@ bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSScope::ConstPtr &from, if (to.isNull()) return false; + if (from == m_nullType && to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) + return true; + if (from == m_jsPrimitiveType) { - // You can cast any primitive (in particular null) to a nullptr + // You can cast any primitive to a nullptr return isPrimitive(to) || to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference; } diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h index a59ffd6e37..893d287170 100644 --- a/src/qmlcompiler/qqmljstyperesolver_p.h +++ b/src/qmlcompiler/qqmljstyperesolver_p.h @@ -68,6 +68,7 @@ public: void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program); QQmlJSScope::ConstPtr voidType() const { return m_voidType; } + QQmlJSScope::ConstPtr nullType() const { return m_nullType; } QQmlJSScope::ConstPtr realType() const { return m_realType; } QQmlJSScope::ConstPtr floatType() const { return m_floatType; } QQmlJSScope::ConstPtr intType() const { return m_intType; } @@ -153,6 +154,7 @@ protected: QQmlJSRegisterContent lengthProperty(bool isWritable, const QQmlJSScope::ConstPtr &scope) const; QQmlJSScope::ConstPtr m_voidType; + QQmlJSScope::ConstPtr m_nullType; QQmlJSScope::ConstPtr m_numberPrototype; QQmlJSScope::ConstPtr m_realType; QQmlJSScope::ConstPtr m_floatType; diff --git a/tests/auto/qml/qmllint/data/nullBinding.qml b/tests/auto/qml/qmllint/data/nullBinding.qml new file mode 100644 index 0000000000..f185ce9eda --- /dev/null +++ b/tests/auto/qml/qmllint/data/nullBinding.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + x: null +} diff --git a/tests/auto/qml/qmllint/data/nullBindingFunction.qml b/tests/auto/qml/qmllint/data/nullBindingFunction.qml new file mode 100644 index 0000000000..89142bd581 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nullBindingFunction.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + x: { return null } +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index b1fe3fc103..1359264a10 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -829,6 +829,14 @@ void TestQmllint::dirtyQmlCode_data() << QStringLiteral("didYouMeanComponent.qml") << QStringLiteral("Itym was not found. Did you add all import paths?") << QString() << QStringLiteral("Item") << false; + QTest::newRow("nullBinding") + << QStringLiteral("nullBinding.qml") + << QStringLiteral("Cannot assign binding of type $anonymous$.std::nullptr_t to double") + << QString() << QString() << false; + QTest::newRow("nullBindingFunction") + << QStringLiteral("nullBindingFunction.qml") + << QStringLiteral("Cannot assign binding of type std::nullptr_t to double") << QString() + << QString() << false; } void TestQmllint::dirtyQmlCode() |