Refactor QQmlJSMetaPropertyBinding

- Store the "binding content", i.e. the literal, object, interceptor or
  value source in a std::variant. This saves space compared to the
  previous approach (where we had individual fields), and also helps
  with type-safety. We also get rid of m_bindingType, which can now be
  obtained via BindingType(m_bindingContent.index()), as long as we keep
  the types in the variant in the correct order.
- Remove a few methods that were not used anywhere. Those can be brought
  back once we actually need them.
- Removed the setLiteral method in lieu of type-safe setX methods where
  X is one of the literal types. QQmlJSImportVisitor has been refactored
  to make use of this, and its parseLiteralBinding method has been
  changed into a parseLiteralOrScriptBinding method. This simplifies the
  control flow, and ensures that we always add the parsed binding.
- Literals no longer store the literal type (as in, the actual
  QQmlJSScope pointer) themselves. Instead, literalType takes a pointer
  to a QQmlJSTypeResolver, and we use that one to resolve the type on
  demand.

Change-Id: I0612d49f2f46fec0fa90f0f5047d8c9f831214ef
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
Fabian Kosmale 2022-02-24 11:58:38 +01:00
parent 9575b54a4e
commit e88318802d
7 changed files with 310 additions and 157 deletions

View File

@ -17,7 +17,7 @@ qt_internal_add_module(QmlCompilerPrivate
qqmljsimportvisitor.cpp qqmljsimportvisitor_p.h
qqmljsloadergenerator.cpp qqmljsloadergenerator_p.h
qqmljslogger_p.h qqmljslogger.cpp
qqmljsmetatypes_p.h
qqmljsmetatypes_p.h qqmljsmetatypes.cpp
qqmljsregistercontent.cpp qqmljsregistercontent_p.h
qqmljsresourcefilemapper.cpp qqmljsresourcefilemapper_p.h
qqmljsscope.cpp qqmljsscope_p.h

View File

@ -1261,7 +1261,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
if (publicMember->isRequired())
m_currentScope->setPropertyLocallyRequired(prop.propertyName(), true);
parseLiteralBinding(publicMember->name.toString(), publicMember->statement);
parseLiteralOrScriptBinding(publicMember->name.toString(), publicMember->statement);
break;
}
@ -1385,12 +1385,9 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::ClassExpression *)
// ### TODO: add warning about suspicious translation binding when returning false?
static std::optional<QQmlJSMetaPropertyBinding>
handleTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args,
const QQmlJSImporter::ImportedTypes &rootScopeImports,
const QQmlJS::SourceLocation &location)
void handleTranslationBinding(QQmlJSMetaPropertyBinding &binding, QStringView base,
QQmlJS::AST::ArgumentList *args)
{
std::optional<QQmlJSMetaPropertyBinding> maybeBinding = std::nullopt;
QStringView mainString;
auto registerMainString = [&](QStringView string) {
mainString = string;
@ -1399,116 +1396,75 @@ handleTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args,
auto discardCommentString = [](QStringView) {return -1;};
auto finalizeBinding = [&](QV4::CompiledData::Binding::ValueType type,
QV4::CompiledData::TranslationData) {
QQmlJSMetaPropertyBinding binding(location);
if (type == QV4::CompiledData::Binding::Type_Translation) {
binding.setTranslation(mainString);
} else if (type == QV4::CompiledData::Binding::Type_TranslationById) {
binding.setTranslationId(mainString);
} else {
binding.setLiteral(
QQmlJSMetaPropertyBinding::StringLiteral, u"string"_qs,
mainString.toString(), rootScopeImports[u"string"_qs].scope);
binding.setStringLiteral(mainString);
}
maybeBinding = binding;
};
QmlIR::tryGeneratingTranslationBindingBase(base, args, registerMainString, discardCommentString, finalizeBinding);
return maybeBinding;
}
bool QQmlJSImportVisitor::parseLiteralBinding(const QString name,
QQmlJSImportVisitor::LiteralOrScriptParseResult QQmlJSImportVisitor::parseLiteralOrScriptBinding(const QString name,
const QQmlJS::AST::Statement *statement)
{
const auto *exprStatement = cast<const ExpressionStatement *>(statement);
if (exprStatement == nullptr)
return false;
QVariant value;
QString literalType;
QQmlJSMetaPropertyBinding::BindingType bindingType = QQmlJSMetaPropertyBinding::Invalid;
return LiteralOrScriptParseResult::Invalid;
auto expr = exprStatement->expression;
QQmlJSMetaPropertyBinding binding(expr->firstSourceLocation(), name);
switch (expr->kind) {
case Node::Kind_TrueLiteral:
value = true;
literalType = u"bool"_qs;
bindingType = QQmlJSMetaPropertyBinding::BoolLiteral;
binding.setBoolLiteral(true);
break;
case Node::Kind_FalseLiteral:
value = false;
literalType = u"bool"_qs;
bindingType = QQmlJSMetaPropertyBinding::BoolLiteral;
binding.setBoolLiteral(false);
break;
case Node::Kind_NullExpression:
// Note: because we set value to nullptr, Null binding returns false in
// QQmlJSMetaPropertyBinding::hasLiteral()
value = QVariant::fromValue(nullptr);
Q_ASSERT(value.isNull());
literalType = u"$internal$.std::nullptr_t"_qs;
bindingType = QQmlJSMetaPropertyBinding::Null;
binding.setNullLiteral();
break;
case Node::Kind_NumericLiteral:
literalType = u"double"_qs;
value = cast<NumericLiteral *>(expr)->value;
bindingType = QQmlJSMetaPropertyBinding::NumberLiteral;
binding.setNumberLiteral(cast<NumericLiteral *>(expr)->value);
break;
case Node::Kind_StringLiteral:
literalType = u"string"_qs;
value = cast<StringLiteral *>(expr)->value.toString();
bindingType = QQmlJSMetaPropertyBinding::StringLiteral;
binding.setStringLiteral(cast<StringLiteral *>(expr)->value);
break;
case Node::Kind_RegExpLiteral:
literalType = u"regexp"_qs;
value = cast<RegExpLiteral *>(expr)->pattern.toString();
bindingType = QQmlJSMetaPropertyBinding::RegExpLiteral;
binding.setRegexpLiteral(cast<RegExpLiteral *>(expr)->pattern);
break;
case Node::Kind_TemplateLiteral: {
auto templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
Q_ASSERT(templateLit);
value = templateLit->value.toString();
if (templateLit->hasNoSubstitution) {
literalType = u"string"_qs;
bindingType = QQmlJSMetaPropertyBinding::StringLiteral;
binding.setStringLiteral(templateLit->value);
} else {
bindingType = QQmlJSMetaPropertyBinding::Script;
binding.setScriptBinding();
}
break;
}
default:
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;
}
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression))
binding.setNumberLiteral(-lit->value);
} else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
if (auto translationBindingOpt = handleTranslationBinding(
base->name, call->arguments, m_rootScopeImports,
expr->firstSourceLocation())) {
auto translationBinding = translationBindingOpt.value();
translationBinding.setPropertyName(name);
m_currentScope->addOwnPropertyBinding(translationBinding);
if (translationBinding.bindingType() == QQmlJSMetaPropertyBinding::BindingType::StringLiteral)
m_literalScopesToCheck << m_currentScope;
return true;
}
}
if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base))
handleTranslationBinding(binding, base->name, call->arguments);
}
break;
}
if (!QQmlJSMetaPropertyBinding::isLiteralBinding(bindingType))
return false;
Q_ASSERT(m_rootScopeImports.contains(literalType)); // built-ins must contain support for all literal bindings
QQmlJSMetaPropertyBinding binding(exprStatement->expression->firstSourceLocation(), name);
binding.setLiteral(bindingType, literalType, value, m_rootScopeImports[literalType].scope);
m_currentScope->addOwnPropertyBinding(binding);
if (binding.isValid()) // always add the binding to the scope, even if it's not a literal one
m_currentScope->addOwnPropertyBinding(binding);
else
return LiteralOrScriptParseResult::Invalid;
if (!QQmlJSMetaPropertyBinding::isLiteralBinding(binding.bindingType()))
return LiteralOrScriptParseResult::Script;
m_literalScopesToCheck << m_currentScope;
return true;
return LiteralOrScriptParseResult::Literal;
}
void QQmlJSImportVisitor::handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scriptBinding)
@ -1578,11 +1534,7 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
if (!signal.has_value()) {
m_propertyBindings[m_currentScope].append(
{ m_savedBindingOuterScope, group->firstSourceLocation(), name.toString() });
if (!parseLiteralBinding(name.toString(), scriptBinding->statement)) {
QQmlJSMetaPropertyBinding binding(group->firstSourceLocation(), name.toString());
// TODO: Actually store the value
m_savedBindingOuterScope->addOwnPropertyBinding(binding);
}
parseLiteralOrScriptBinding(name.toString(), scriptBinding->statement);
} else {
const auto statement = scriptBinding->statement;
QStringList signalParameters;

View File

@ -203,7 +203,8 @@ protected:
void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
QQmlJSLogger *m_logger;
bool parseLiteralBinding(const QString name, const QQmlJS::AST::Statement *statement);
enum class LiteralOrScriptParseResult { Invalid, Script, Literal };
LiteralOrScriptParseResult parseLiteralOrScriptBinding(const QString name, const QQmlJS::AST::Statement *statement);
// Used to temporarily store annotations for functions and generators wrapped in UiSourceElements
QVector<QQmlJSAnnotation> m_pendingMethodAnnotations;

View File

@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/qqmljsmetatypes_p.h>
#include <private/qqmljstyperesolver_p.h>
QT_BEGIN_NAMESPACE
/*!
\internal
A binding is valid when it has both a target (m_propertyName is set)
and some content set (m_bindingType != Invalid).
*/
bool QQmlJSMetaPropertyBinding::isValid() const { return !m_propertyName.isEmpty() && bindingType() != Invalid; }
QString QQmlJSMetaPropertyBinding::literalTypeName() const
{
if (std::holds_alternative<Content::BoolLiteral>(m_bindingContent))
return QLatin1String("bool");
else if (std::holds_alternative<Content::NumberLiteral>(m_bindingContent))
return QLatin1String("double");
else if (std::holds_alternative<Content::StringLiteral>(m_bindingContent))
return QLatin1String("string");
else if (std::holds_alternative<Content::RegexpLiteral>(m_bindingContent))
return QLatin1String("regexp");
else if (std::holds_alternative<Content::Null>(m_bindingContent))
return QLatin1String("$internal$.std::nullptr_t");
return {};
}
bool QQmlJSMetaPropertyBinding::boolValue() const
{
if (auto boolLit = std::get_if<Content::BoolLiteral>(&m_bindingContent))
return boolLit->value;
// warn
return false;
}
double QQmlJSMetaPropertyBinding::numberValue() const
{
if (auto numberLit = std::get_if<Content::NumberLiteral>(&m_bindingContent))
return numberLit->value;
// warn
return 0;
}
QString QQmlJSMetaPropertyBinding::stringValue() const
{
if (auto stringLiteral = std::get_if<Content::StringLiteral>(&m_bindingContent))
return stringLiteral->value;
// warn
return {};
}
/*!
\internal
Uses \a resolver to return the correct type for the stored literal
and a null scope pointer if the binding does not contain a literal
*/
QSharedPointer<const QQmlJSScope> QQmlJSMetaPropertyBinding::literalType(const QQmlJSTypeResolver *resolver) const
{
Q_ASSERT(resolver);
switch (bindingType()) {
case QQmlJSMetaPropertyBinding::BoolLiteral:
return resolver->boolType();
case QQmlJSMetaPropertyBinding::NumberLiteral:
return resolver->typeForName(QLatin1String("double"));
case QQmlJSMetaPropertyBinding::Translation: // translations are strings
case QQmlJSMetaPropertyBinding::TranslationById:
case QQmlJSMetaPropertyBinding::StringLiteral:
return resolver->stringType();
case QQmlJSMetaPropertyBinding::RegExpLiteral:
return resolver->typeForName(QLatin1String("regexp"));
case QQmlJSMetaPropertyBinding::Null:
return resolver->nullType();
default:
return {};
}
Q_UNREACHABLE();
return {}; // needed on some compilers which do not see that every case in the switch returns
}
QT_END_NAMESPACE

View File

@ -59,6 +59,7 @@
QT_BEGIN_NAMESPACE
class QQmlJSTypeResolver;
class QQmlJSScope;
class QQmlJSMetaEnum
{
@ -390,38 +391,98 @@ public:
};
private:
// needs to be kept in sync with the BindingType enum
struct Content {
using Invalid = std::monostate;
struct BoolLiteral {
bool value;
friend bool operator==(BoolLiteral a, BoolLiteral b) { return a.value == b.value; }
friend bool operator!=(BoolLiteral a, BoolLiteral b) { return !(a == b); }
};
struct NumberLiteral {
friend bool operator==(NumberLiteral a, NumberLiteral b) { return a.value == b.value; }
friend bool operator!=(NumberLiteral a, NumberLiteral b) { return !(a == b); }
double value; // ### TODO: int?
};
struct StringLiteral {
friend bool operator==(StringLiteral a, StringLiteral b) { return a.value == b.value; }
friend bool operator!=(StringLiteral a, StringLiteral b) { return !(a == b); }
QString value;
};
struct RegexpLiteral {
friend bool operator==(RegexpLiteral a, RegexpLiteral b) { return a.value == b.value; }
friend bool operator!=(RegexpLiteral a, RegexpLiteral b) { return !(a == b); }
QString value;
};
struct Null {
friend bool operator==(Null , Null ) { return true; }
friend bool operator!=(Null a, Null b) { return !(a == b); }
};
struct TranslationString {
friend bool operator==(TranslationString a, TranslationString b) { return a.value == b.value; }
friend bool operator!=(TranslationString a, TranslationString b) { return !(a == b); }
QString value;
};
struct TranslationById {
friend bool operator==(TranslationById a, TranslationById b) { return a.value == b.value; }
friend bool operator!=(TranslationById a, TranslationById b) { return !(a == b); }
QString value;
};
struct Script {
friend bool operator==(Script , Script ) { return true; }
friend bool operator!=(Script a, Script b) { return !(a == b); }
};
struct Object {
friend bool operator==(Object a, Object b) { return a.value == b.value && a.typeName == b.typeName; }
friend bool operator!=(Object a, Object b) { return !(a == b); }
QString typeName;
QWeakPointer<const QQmlJSScope> value;
};
struct Interceptor {
friend bool operator==(Interceptor a, Interceptor b)
{
return a.interceptor == b.interceptor && a.interceptorTypeName == b.interceptorTypeName;
}
friend bool operator!=(Interceptor a, Interceptor b) { return !(a == b); }
QString interceptorTypeName;
QWeakPointer<const QQmlJSScope> interceptor;
};
struct ValueSource {
friend bool operator==(ValueSource a, ValueSource b)
{
return a.valueSource == b.valueSource && a.valueSourceTypeName == b.valueSourceTypeName;
}
friend bool operator!=(ValueSource a, ValueSource b) { return !(a == b); }
QString valueSourceTypeName;
QWeakPointer<const QQmlJSScope> valueSource;
};
struct AttachedProperty {
friend bool operator==(AttachedProperty , AttachedProperty ) { return true; }
friend bool operator!=(AttachedProperty a, AttachedProperty b) { return !(a == b); }
};
struct GroupProperty {
friend bool operator==(GroupProperty , GroupProperty ) { return true; }
friend bool operator!=(GroupProperty a, GroupProperty b) { return !(a == b); }
};
using type = std::variant<Invalid, BoolLiteral, NumberLiteral, StringLiteral,
RegexpLiteral, Null, TranslationString,
TranslationById, Script, Object, Interceptor,
ValueSource, AttachedProperty, GroupProperty
>;
};
using BindingContent = Content::type;
QQmlJS::SourceLocation m_sourceLocation;
QString m_propertyName; // TODO: this is a debug-only information
BindingType m_bindingType = BindingType::Invalid;
BindingContent m_bindingContent;
// TODO: the below should really be put into a union (of sorts). despite the
// data being overlapping for different things (which for now is just
// ignored), we would still only have one kind of information stored in a
// binding. separating the non-overlapping bits would indicate what we
// require for each binding type more clearly
//union {
QString m_translationString;
QString m_translationId;
QVariant m_literalValue; // constant in literal (or null) expression
//};
QWeakPointer<const QQmlJSScope> m_value; // object type of Object binding *OR* a literal type
QString m_valueTypeName;
QWeakPointer<const QQmlJSScope> m_interceptor; // QQmlPropertyValueInterceptor derived type
QString m_interceptorTypeName;
QWeakPointer<const QQmlJSScope> m_valueSource; // QQmlPropertyValueSource derived type
QString m_valueSourceTypeName;
void setBindingTypeOnce(BindingType type)
void ensureSetBindingTypeOnce()
{
Q_ASSERT(m_bindingType == BindingType::Invalid);
m_bindingType = type;
Q_ASSERT(bindingType() == BindingType::Invalid);
}
bool isLiteralBinding() const { return isLiteralBinding(m_bindingType); }
bool isLiteralBinding() const { return isLiteralBinding(bindingType()); }
public:
@ -448,90 +509,124 @@ public:
const QQmlJS::SourceLocation &sourceLocation() const { return m_sourceLocation; }
BindingType bindingType() const { return m_bindingType; }
BindingType bindingType() const { return BindingType(m_bindingContent.index()); }
bool isValid() const { return !m_propertyName.isEmpty(); }
bool isValid() const;
void setLiteral(BindingType kind, const QString &typeName, const QVariant &value,
const QSharedPointer<const QQmlJSScope> &type)
void setStringLiteral(QAnyStringView value)
{
Q_ASSERT(isLiteralBinding(kind));
setBindingTypeOnce(kind);
m_value = type;
m_valueTypeName = typeName;
m_literalValue = value;
ensureSetBindingTypeOnce();
m_bindingContent = Content::StringLiteral { value.toString() };
}
void setScriptBinding()
{
// ### TODO: this does not allow us to do anything interesting with the binding
ensureSetBindingTypeOnce();
m_bindingContent = Content::Script {};
}
void setBoolLiteral(bool value)
{
ensureSetBindingTypeOnce();
m_bindingContent = Content::BoolLiteral { value };
}
void setNullLiteral()
{
ensureSetBindingTypeOnce();
m_bindingContent = Content::Null {};
}
void setNumberLiteral(double value)
{
ensureSetBindingTypeOnce();
m_bindingContent = Content::NumberLiteral { value };
}
void setRegexpLiteral(QAnyStringView value)
{
ensureSetBindingTypeOnce();
m_bindingContent = Content::RegexpLiteral { value.toString() };
}
// ### TODO: we might need comment and translation number at some point
void setTranslation(QStringView translation)
{
setBindingTypeOnce(BindingType::Translation);
m_translationString = translation.toString();
ensureSetBindingTypeOnce();
m_bindingContent = Content::TranslationString { translation.toString() };
}
void setTranslationId(QStringView id)
{
setBindingTypeOnce(BindingType::TranslationById);
m_translationId = id.toString();
ensureSetBindingTypeOnce();
m_bindingContent = Content::TranslationById { id.toString() };
}
void setObject(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type)
{
setBindingTypeOnce(BindingType::Object);
m_value = type;
m_valueTypeName = typeName;
ensureSetBindingTypeOnce();
m_bindingContent = Content::Object { typeName, type };
}
void setInterceptor(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type)
{
setBindingTypeOnce(BindingType::Interceptor);
m_interceptor = type;
m_interceptorTypeName = typeName;
ensureSetBindingTypeOnce();
m_bindingContent = Content::Interceptor { typeName, type };
}
void setValueSource(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type)
{
setBindingTypeOnce(BindingType::ValueSource);
m_valueSource = type;
m_valueSourceTypeName = typeName;
ensureSetBindingTypeOnce();
m_bindingContent = Content::ValueSource { typeName, type };
}
QString literalTypeName() const { return m_valueTypeName; }
const QVariant &literalValue() const { return m_literalValue; }
QSharedPointer<const QQmlJSScope> literalType() const { return m_value; }
QString literalTypeName() const;
QString objectTypeName() const { return m_valueTypeName; }
QSharedPointer<const QQmlJSScope> objectType() const { return m_value; }
// ### TODO: here and below: Introduce an allowConversion parameter, if yes, enable conversions e.g. bool -> number?
bool boolValue() const;
QString interceptorTypeName() const { return m_interceptorTypeName; }
QSharedPointer<const QQmlJSScope> interceptorType() const { return m_interceptor; }
double numberValue() const;
QString valueSourceTypeName() const { return m_valueSourceTypeName; }
QSharedPointer<const QQmlJSScope> valueSourceType() const { return m_valueSource; }
QString stringValue() const;
QSharedPointer<const QQmlJSScope> literalType(const QQmlJSTypeResolver *resolver) const;
QString objectTypeName() const
{
if (auto *object = std::get_if<Content::Object>(&m_bindingContent))
return object->typeName;
// warn
return {};
}
QSharedPointer<const QQmlJSScope> objectType() const
{
if (auto *object = std::get_if<Content::Object>(&m_bindingContent))
return object->value.lock();
// warn
return {};
}
bool hasLiteral() const
{
return isLiteralBinding()
&& (!m_literalValue.isNull() || m_bindingType == QQmlJSMetaPropertyBinding::Null);
// TODO: Assumption: if the type is literal, we must have one
return isLiteralBinding();
}
bool hasObject() const { return m_bindingType == BindingType::Object && !m_value.isNull(); }
bool hasObject() const { return bindingType() == BindingType::Object; }
bool hasInterceptor() const
{
return m_bindingType == BindingType::Interceptor && !m_interceptor.isNull();
return bindingType() == BindingType::Interceptor;
}
bool hasValueSource() const
{
return m_bindingType == BindingType::ValueSource && !m_valueSource.isNull();
return bindingType() == BindingType::ValueSource;
}
friend bool operator==(const QQmlJSMetaPropertyBinding &a, const QQmlJSMetaPropertyBinding &b)
{
return a.m_bindingType == b.m_bindingType && a.m_propertyName == b.m_propertyName
&& a.m_valueTypeName == b.m_valueTypeName
&& a.m_interceptorTypeName == b.m_interceptorTypeName
&& a.m_valueSourceTypeName == b.m_valueSourceTypeName
&& a.m_literalValue == b.m_literalValue && a.m_value == b.m_value
&& a.m_interceptor == b.m_interceptor && a.m_sourceLocation == b.m_sourceLocation;
return a.m_propertyName == b.m_propertyName
&& a.m_bindingContent == b.m_bindingContent
&& a.m_sourceLocation == b.m_sourceLocation;
}
friend bool operator!=(const QQmlJSMetaPropertyBinding &a, const QQmlJSMetaPropertyBinding &b)
@ -541,12 +636,9 @@ public:
friend size_t qHash(const QQmlJSMetaPropertyBinding &binding, size_t seed = 0)
{
return qHashMulti(seed, binding.m_propertyName, binding.m_valueTypeName,
binding.m_interceptorTypeName, binding.m_valueSourceTypeName,
binding.m_literalValue.toString(), binding.m_value.toStrongRef().data(),
binding.m_interceptor.toStrongRef().data(),
binding.m_valueSource.toStrongRef().data(), binding.m_sourceLocation,
binding.m_bindingType);
// we don't need to care about the actual binding content when hashing
return qHashMulti(seed, binding.m_propertyName, binding.m_sourceLocation,
binding.bindingType());
}
};

View File

@ -149,12 +149,12 @@ void QQmlJSTypeResolver::init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *p
Log_Type, binding.sourceLocation());
continue;
}
if (!canConvertFromTo(binding.literalType(), property.type())) {
if (!canConvertFromTo(binding.literalType(this), property.type())) {
m_logger->log(u"Cannot assign binding of type %1 to %2"_qs
.arg(binding.literalTypeName(), property.typeName()),
Log_Type, binding.sourceLocation());
} else if (equals(property.type(), m_stringType)
&& isNumeric(binding.literalType())) {
&& isNumeric(binding.literalType(this))) {
m_logger->log(u"Cannot assign a numeric constant to a string property"_qs,
Log_Type, binding.sourceLocation());
}

View File

@ -440,18 +440,18 @@ void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyB
switch (binding.bindingType()) {
case QQmlJSMetaPropertyBinding::BoolLiteral: {
const bool value = binding.literalValue().toBool();
const bool value = binding.boolValue();
generator.generate_assignToProperty(current, type, p, value ? u"true"_qs : u"false"_qs,
accessor.name);
break;
}
case QQmlJSMetaPropertyBinding::NumberLiteral: {
const QString value = QString::number(binding.literalValue().toDouble());
const QString value = QString::number(binding.numberValue());
generator.generate_assignToProperty(current, type, p, value, accessor.name);
break;
}
case QQmlJSMetaPropertyBinding::StringLiteral: {
const QString value = binding.literalValue().toString();
const QString value = binding.stringValue();
generator.generate_assignToProperty(current, type, p, QQmlJSUtils::toLiteral(value),
accessor.name);
break;