QtQml: Disallow multi-step construction of value types
If we coerce the argument for a constructor, we should not call another constructor in the process. Such chaining leads to rather confusing effects and easily ends in infinite recursion. Pick-to: 6.5 6.6 Change-Id: Ia6d5063641170d2cd3bee3fdcbb8b97837d5c700 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
e0235bca55
commit
b4ce8051af
|
@ -120,12 +120,11 @@ static bool fromMatchingType(
|
|||
return true;
|
||||
}
|
||||
|
||||
QVariant converted = QQmlValueTypeProvider::createValueType(s, parameterType);
|
||||
if (converted.isValid()) {
|
||||
callConstructor(mo, i, converted.data(), allocate());
|
||||
return true;
|
||||
}
|
||||
// Do not recursively try to create parameters here. This may end up in infinite recursion.
|
||||
|
||||
// At this point, s should be a builtin type. For builtin types
|
||||
// the QMetaType converters are good enough.
|
||||
QVariant converted(parameterType);
|
||||
if (QMetaType::convert(parameter.metaType(), parameter.constData(),
|
||||
parameterType, converted.data())) {
|
||||
callConstructor(mo, i, converted.data(), allocate());
|
||||
|
@ -157,14 +156,11 @@ static bool fromMatchingType(const QMetaObject *mo, QVariant s, Allocate &&alloc
|
|||
return true;
|
||||
}
|
||||
|
||||
QVariant parameter = QQmlValueTypeProvider::createValueType(s, parameterType);
|
||||
if (parameter.isValid()) {
|
||||
callConstructor(mo, i, parameter.data(), allocate());
|
||||
return true;
|
||||
}
|
||||
// Do not recursively try to create parameters here. This may end up in infinite recursion.
|
||||
|
||||
// At this point, s should be a builtin type. For builtin types
|
||||
// the QMetaType converters are good enough.
|
||||
QVariant parameter(parameterType);
|
||||
if (QMetaType::convert(sourceMetaType, s.constData(), parameterType, parameter.data())) {
|
||||
callConstructor(mo, i, parameter.data(), allocate());
|
||||
return true;
|
||||
|
|
|
@ -485,8 +485,10 @@ bool QQmlJSTypeResolver::adjustTrackedType(
|
|||
|
||||
// If we cannot convert to the new type without the help of e.g. lookupResultMetaType(),
|
||||
// we better not change the type.
|
||||
if (!canPrimitivelyConvertFromTo(tracked, conversion))
|
||||
if (!canPrimitivelyConvertFromTo(tracked, conversion)
|
||||
&& !selectConstructor(conversion, tracked, nullptr).isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->replacement = comparableType(conversion);
|
||||
*it->clone = std::move(*QQmlJSScope::clone(conversion));
|
||||
|
@ -508,8 +510,10 @@ bool QQmlJSTypeResolver::adjustTrackedType(
|
|||
|
||||
// If we cannot convert to the new type without the help of e.g. lookupResultMetaType(),
|
||||
// we better not change the type.
|
||||
if (!canPrimitivelyConvertFromTo(tracked, result))
|
||||
if (!canPrimitivelyConvertFromTo(tracked, result)
|
||||
&& !selectConstructor(result, tracked, nullptr).isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->replacement = comparableType(result);
|
||||
*mutableTracked = std::move(*QQmlJSScope::clone(result));
|
||||
|
@ -569,7 +573,7 @@ QString QQmlJSTypeResolver::containedTypeName(const QQmlJSRegisterContent &conta
|
|||
bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSScope::ConstPtr &from,
|
||||
const QQmlJSScope::ConstPtr &to) const
|
||||
{
|
||||
if (canPrimitivelyConvertFromTo(from, to))
|
||||
if (canPrimitivelyConvertFromTo(from, to) || selectConstructor(to, from, nullptr).isValid())
|
||||
return true;
|
||||
|
||||
// ### need a generic solution for custom cpp types:
|
||||
|
@ -1005,7 +1009,7 @@ QQmlJSMetaMethod QQmlJSTypeResolver::selectConstructor(
|
|||
{
|
||||
// If the "from" type can hold the target type, we should not try to coerce
|
||||
// it to any constructor argument.
|
||||
if (canHold(passedArgumentType, type))
|
||||
if (type.isNull() || canHold(passedArgumentType, type))
|
||||
return QQmlJSMetaMethod();
|
||||
|
||||
if (QQmlJSScope::ConstPtr extension = type->extensionType().scope) {
|
||||
|
@ -1041,6 +1045,8 @@ QQmlJSMetaMethod QQmlJSTypeResolver::selectConstructor(
|
|||
if (equals(passedArgumentType, methodArgumentType))
|
||||
return method;
|
||||
|
||||
// Do not select further ctors here. We don't want to do multi-step construction as that
|
||||
// is confusing and easily leads to infinite recursion.
|
||||
if (!candidate.isValid()
|
||||
&& canPrimitivelyConvertFromTo(passedArgumentType, methodArgumentType)) {
|
||||
candidate = method;
|
||||
|
@ -1165,7 +1171,7 @@ bool QQmlJSTypeResolver::canPrimitivelyConvertFromTo(
|
|||
return true;
|
||||
}
|
||||
|
||||
return selectConstructor(to, from, nullptr).isValid();
|
||||
return false;
|
||||
}
|
||||
|
||||
QQmlJSRegisterContent QQmlJSTypeResolver::lengthProperty(
|
||||
|
|
Loading…
Reference in New Issue