moc: Fix QProperty code generation

This addresses two issues:
1. The generated code for QNotifiedProperty<T, ...> was broken when T is
   a pointer. Notably, const S* &  is not a constant reference to S*.
   This is addressed by consistently using T const& instead of const T&.
2. The Q_PRIVATE_QPROPERTY approach assumed that the property name and
   the getter are equal. This does break when they are not, and we are
   unable to change either of them due to API compatibility concerns. An
   example of this would be QQuickItem's parent property with a
   parentItem getter. Therefore, we now allow the usage of NAME to
   override the name of the property.

Change-Id: Idf2e85576c74371b5b0f6db15dbe6f2d17c5e33d
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2020-06-24 08:25:17 +02:00
parent b20c7df63a
commit 844e4f7b98
4 changed files with 15 additions and 8 deletions

View File

@ -96,8 +96,8 @@ QT_BEGIN_NAMESPACE
type value() const; \ type value() const; \
type operator()() const { return value(); } \ type operator()() const { return value(); } \
void setValue(type &&); \ void setValue(type &&); \
void setValue(const type &); \ void setValue(type const &); \
void operator=(const type &v) { setValue(v); } \ void operator=(type const &v) { setValue(v); } \
void operator=(type &&v) { setValue(std::move(v)); } \ void operator=(type &&v) { setValue(std::move(v)); } \
QPropertyBinding<type> setBinding(const QPropertyBinding<type> &); \ QPropertyBinding<type> setBinding(const QPropertyBinding<type> &); \
QPropertyBinding<type> setBinding(QPropertyBinding<type> &&); \ QPropertyBinding<type> setBinding(QPropertyBinding<type> &&); \
@ -114,7 +114,7 @@ QT_BEGIN_NAMESPACE
QPropertyBinding<type> binding() const; \ QPropertyBinding<type> binding() const; \
QPropertyBinding<type> takeBinding(); \ QPropertyBinding<type> takeBinding(); \
}; \ }; \
void setter(const type &value); void setter(type const& value);
#if __has_cpp_attribute(no_unique_address) #if __has_cpp_attribute(no_unique_address)
#define Q_PRIVATE_QPROPERTIES_BEGIN #define Q_PRIVATE_QPROPERTIES_BEGIN
#define QT_PRIVATE_QPROPERTY_PREFIX [[no_unique_address]] #define QT_PRIVATE_QPROPERTY_PREFIX [[no_unique_address]]

View File

@ -1419,7 +1419,7 @@ void Generator::generateStaticMetacall()
prefix += p.inPrivateClass + "->"; prefix += p.inPrivateClass + "->";
} }
fprintf(out, " case %d: observer->setSource(%s%s); break;\n", fprintf(out, " case %d: observer->setSource(%s%s); break;\n",
propindex, prefix.constData(), p.name.constData()); propindex, prefix.constData(), p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData());
} }
fprintf(out, " default: break;\n"); fprintf(out, " default: break;\n");
fprintf(out, " }\n"); fprintf(out, " }\n");
@ -1447,7 +1447,7 @@ void Generator::generateStaticMetacall()
else else
objectAccessor.clear(); objectAccessor.clear();
fprintf(out, " case %d: %s%s.setBinding(%s*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n", fprintf(out, " case %d: %s%s.setBinding(%s*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
propindex, prefix.constData(), p.name.constData(), objectAccessor.constData(), p.type.constData()); propindex, prefix.constData(), p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData(), objectAccessor.constData(), p.type.constData());
} }
fprintf(out, " default: break;\n"); fprintf(out, " default: break;\n");
fprintf(out, " }\n"); fprintf(out, " }\n");
@ -1557,7 +1557,7 @@ void Generator::generateQPropertyApi()
fprintf(out, "}\n"); fprintf(out, "}\n");
// property value setter // property value setter
fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(const %s &value)\n{\n", fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(%s const &value)\n{\n",
cdef->qualified.constData(), cdef->qualified.constData(),
property.name.constData(), property.name.constData(),
property.type.name.constData()); property.type.name.constData());
@ -1629,7 +1629,7 @@ void Generator::generateQPropertyApi()
fprintf(out, "}\n"); fprintf(out, "}\n");
// property setter function // property setter function
fprintf(out, "\nvoid %s::%s(const %s &value)\n{\n", fprintf(out, "\nvoid %s::%s(%s const& value)\n{\n",
cdef->qualified.constData(), cdef->qualified.constData(),
property.setter.constData(), property.setter.constData(),
property.type.name.constData()); property.type.name.constData());

View File

@ -1317,6 +1317,12 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
} else if(l[0] == 'F' && l == "FINAL") { } else if(l[0] == 'F' && l == "FINAL") {
propDef.final = true; propDef.final = true;
continue; continue;
} else if (l[0] == 'N' && l == "NAME") {
if (!propDef.isQProperty)
error(1);
next(IDENTIFIER);
propDef.name = lexem();
continue;
} else if (l[0] == 'R' && l == "REQUIRED") { } else if (l[0] == 'R' && l == "REQUIRED") {
propDef.required = true; propDef.required = true;
continue; continue;
@ -1525,6 +1531,7 @@ void Moc::parsePrivateQProperty(ClassDef *def)
PropertyDef propDef; PropertyDef propDef;
propDef.name = name; propDef.name = name;
propDef.qpropertyname = name;
propDef.type = type.name; propDef.type = type.name;
propDef.read = name + ".value"; propDef.read = name + ".value";
propDef.write = name + ".setValue"; propDef.write = name + ".setValue";

View File

@ -132,7 +132,7 @@ struct PropertyDef
return (s == write); return (s == write);
} }
QByteArray name, type, member, read, write, reset, designable, scriptable, stored, user, notify, inPrivateClass; QByteArray name, type, member, read, write, reset, designable, scriptable, stored, user, notify, inPrivateClass, qpropertyname;
int notifyId = -1; // -1 means no notifyId, >= 0 means signal defined in this class, < -1 means signal not defined in this class int notifyId = -1; // -1 means no notifyId, >= 0 means signal defined in this class, < -1 means signal not defined in this class
enum Specification { ValueSpec, ReferenceSpec, PointerSpec }; enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
Specification gspec = ValueSpec; Specification gspec = ValueSpec;