diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-09-24 11:10:24 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-09-28 11:19:29 +0200 |
commit | cb073f6eee9e21b62d7c14e0357beb6cecf33e31 (patch) | |
tree | 36a32fae9cf3f9c8d505a8dbaf31b228b08844f9 /sources/shiboken2/generator | |
parent | 5a7429cc895824a4eafd27e1a5c95b40bba86bdf (diff) |
shiboken2: Generate properties as fields
- Add an XML attribute specifying whether code is to
be generated to the XML properties.
- Split the generator functions for field setters and getters
apart so that they can be used for generating property
setters and getters.
- Generate code for all properties from XML when the PySide
extension is not used, otherwise only for those with
the attribute set.
Task-number: PYSIDE-1019
Change-Id: Iab2ba38b90038edc667a233c23c7113fdc6fb438
Reviewed-by: Christian Tismer <tismer@stackless.com>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/shiboken2/generator')
4 files changed, 162 insertions, 28 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 32b9cf24f..6d9884d39 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -317,6 +317,13 @@ static QString buildPropertyString(QPropertySpec *spec) return text; } +static void writePyGetSetDefEntry(QTextStream &s, const QString &name, + const QString &getFunc, const QString &setFunc) +{ + s << "{const_cast<char *>(\"" << name << "\"), " << getFunc << ", " + << (setFunc.isEmpty() ? QLatin1String(NULL_PTR) : setFunc) << "},\n"; +} + /*! Function used to write the class generated binding code on the buffer \param s the output buffer @@ -590,8 +597,10 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo // PYSIDE-1019: Write a compressed list of all properties `name:getter[:setter]`. // Default values are suppressed. QStringList sorter; - for (const auto spec : metaClass->propertySpecs()) - sorter.append(buildPropertyString(spec)); + for (const auto spec : metaClass->propertySpecs()) { + if (!spec->generateGetSetDef()) + sorter.append(buildPropertyString(spec)); + } sorter.sort(); s << '\n'; @@ -689,19 +698,34 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo s << Qt::endl; } + for (const QPropertySpec *property : metaClass->propertySpecs()) { + if (property->generateGetSetDef() || !usePySideExtensions()) { + writeGetterFunction(s, property, classContext); + if (property->hasWrite()) + writeSetterFunction(s, property, classContext); + } + } + s << "// Getters and Setters for " << metaClass->name() << Qt::endl; s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {\n"; for (const AbstractMetaField *metaField : fields) { - if (metaField->isStatic()) - continue; + if (!metaField->isStatic()) { + s << INDENT; + const QString setter = canGenerateFieldSetter(metaField) + ? cpythonSetterFunctionName(metaField) : QString(); + writePyGetSetDefEntry(s, metaField->name(), + cpythonGetterFunctionName(metaField), setter); + } + } - s << INDENT << "{const_cast<char *>(\"" << metaField->name() << "\"), "; - s << cpythonGetterFunctionName(metaField) << ", "; - if (canGenerateFieldSetter(metaField)) - s << cpythonSetterFunctionName(metaField); - else - s << NULL_PTR; - s << "},\n"; + for (const QPropertySpec *property : metaClass->propertySpecs()) { + if (property->generateGetSetDef() || !usePySideExtensions()) { + s << INDENT; + const QString setter = property->hasWrite() + ? cpythonSetterFunctionName(property, metaClass) : QString(); + writePyGetSetDefEntry(s, property->name(), + cpythonGetterFunctionName(property, metaClass), setter); + } } s << INDENT << '{' << NULL_PTR << "} // Sentinel\n"; s << "};\n\n"; @@ -3976,6 +4000,13 @@ bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass *metaClass) if (!f->isStatic()) return true; } + // Generate all user-added properties unless Pyside extensions are used, + // in which only the explicitly specified ones are generated (rest is handled + // in libpyside). + return usePySideExtensions() + ? std::any_of(metaClass->propertySpecs().cbegin(), metaClass->propertySpecs().cend(), + [] (const QPropertySpec *s) { return s->generateGetSetDef(); }) + : !metaClass->propertySpecs().isEmpty(); return false; } @@ -4416,13 +4447,18 @@ void CppGenerator::writeCopyFunction(QTextStream &s, const GeneratorContext &con s << Qt::endl; } +static inline void writeGetterFunctionStart(QTextStream &s, const QString &funcName) +{ + s << "static PyObject *" << funcName << "(PyObject *self, void *)\n"; + s << "{\n"; +} + void CppGenerator::writeGetterFunction(QTextStream &s, const AbstractMetaField *metaField, const GeneratorContext &context) { ErrorCode errorCode(QString::fromLatin1(NULL_PTR)); - s << "static PyObject *" << cpythonGetterFunctionName(metaField) << "(PyObject *self, void *)\n"; - s << "{\n"; + writeGetterFunctionStart(s, cpythonGetterFunctionName(metaField)); writeCppSelfDefinition(s, context); @@ -4503,12 +4539,35 @@ void CppGenerator::writeGetterFunction(QTextStream &s, s << "}\n"; } -void CppGenerator::writeSetterFunction(QTextStream &s, - const AbstractMetaField *metaField, +// Write a getter for QPropertySpec +void CppGenerator::writeGetterFunction(QTextStream &s, const QPropertySpec *property, const GeneratorContext &context) { ErrorCode errorCode(0); - s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject *self, PyObject *pyIn, void *)\n"; + writeGetterFunctionStart(s, cpythonGetterFunctionName(property, context.metaClass())); + writeCppSelfDefinition(s, context); + const QString value = QStringLiteral("value"); + s << INDENT << "auto " << value << " = " << CPP_SELF_VAR << "->" << property->read() << "();\n" + << INDENT << "auto pyResult = "; + writeToPythonConversion(s, property->type(), context.metaClass(), value); + s << ";\n" + << INDENT << "if (PyErr_Occurred() || !pyResult) {\n"; + { + Indentation indent(INDENT); + s << INDENT << "Py_XDECREF(pyResult);\n" + << INDENT << " return {};\n"; + } + s << INDENT << "}\n" + << INDENT << "return pyResult;\n}\n\n"; +} + +// Write setter function preamble (type checks on "pyIn") +void CppGenerator::writeSetterFunctionPreamble(QTextStream &s, const QString &name, + const QString &funcName, + const AbstractMetaType *type, + const GeneratorContext &context) +{ + s << "static int " << funcName << "(PyObject *self, PyObject *pyIn, void *)\n"; s << "{\n"; writeCppSelfDefinition(s, context); @@ -4517,24 +4576,33 @@ void CppGenerator::writeSetterFunction(QTextStream &s, { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'"; - s << metaField->name() << "' may not be deleted\");\n"; + s << name << "' may not be deleted\");\n"; s << INDENT << "return -1;\n"; } s << INDENT << "}\n"; - AbstractMetaType *fieldType = metaField->type(); - s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};\n"; s << INDENT << "if (!"; - writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry())); + writeTypeCheck(s, type, QLatin1String("pyIn"), isNumber(type->typeEntry())); s << ") {\n"; { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '"; - s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");\n"; + s << name << "', '" << type->name() << "' or convertible type expected\");\n"; s << INDENT << "return -1;\n"; } s << INDENT<< "}\n\n"; +} + +void CppGenerator::writeSetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + const GeneratorContext &context) +{ + ErrorCode errorCode(0); + + AbstractMetaType *fieldType = metaField->type(); + writeSetterFunctionPreamble(s, metaField->name(), cpythonSetterFunctionName(metaField), + fieldType, context); QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name()); s << INDENT; @@ -4568,6 +4636,26 @@ void CppGenerator::writeSetterFunction(QTextStream &s, s << "}\n"; } +// Write a setter for QPropertySpec +void CppGenerator::writeSetterFunction(QTextStream &s, const QPropertySpec *property, + const GeneratorContext &context) +{ + ErrorCode errorCode(0); + writeSetterFunctionPreamble(s, property->name(), + cpythonSetterFunctionName(property, context.metaClass()), + property->type(), context); + + s << INDENT << "auto cppOut = " << CPP_SELF_VAR << "->" << property->read() << "();\n" + << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);\n" + << INDENT << "if (PyErr_Occurred())\n"; + { + Indentation indent(INDENT); + s << INDENT << "return -1;\n"; + } + s << INDENT << CPP_SELF_VAR << "->" << property->write() << "(cppOut);\n" + << INDENT << "return 0;\n}\n\n"; +} + void CppGenerator::writeRichCompareFunction(QTextStream &s, const GeneratorContext &context) { const AbstractMetaClass *metaClass = context.metaClass(); diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 1cc6c1ca0..8c56dd758 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -290,9 +290,20 @@ private: void writeGetterFunction(QTextStream &s, const AbstractMetaField *metaField, const GeneratorContext &context); + void writeGetterFunction(QTextStream &s, + const QPropertySpec *property, + const GeneratorContext &context); + void writeSetterFunctionPreamble(QTextStream &s, + const QString &name, + const QString &funcName, + const AbstractMetaType *type, + const GeneratorContext &context); void writeSetterFunction(QTextStream &s, const AbstractMetaField *metaField, const GeneratorContext &context); + void writeSetterFunction(QTextStream &s, + const QPropertySpec *property, + const GeneratorContext &context); void writeRichCompareFunction(QTextStream &s, const GeneratorContext &context); diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index ff1478d58..df8bf392a 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -31,6 +31,7 @@ #include <abstractmetalang.h> #include <messages.h> #include "overloaddata.h" +#include "propertyspec.h" #include <reporthandler.h> #include <typedatabase.h> #include <abstractmetabuilder.h> @@ -452,14 +453,38 @@ QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass * return cpythonBaseName(metaClass) + QLatin1String("_getattro"); } +QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name, + const AbstractMetaClass *enclosingClass) +{ + return cpythonBaseName(enclosingClass) + QStringLiteral("_get_") + name; +} + +QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name, + const AbstractMetaClass *enclosingClass) +{ + return cpythonBaseName(enclosingClass) + QStringLiteral("_set_") + name; +} + QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField *metaField) { - return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name()); + return cpythonGetterFunctionName(metaField->name(), metaField->enclosingClass()); } QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField *metaField) { - return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name()); + return cpythonSetterFunctionName(metaField->name(), metaField->enclosingClass()); +} + +QString ShibokenGenerator::cpythonGetterFunctionName(const QPropertySpec *property, + const AbstractMetaClass *metaClass) +{ + return cpythonGetterFunctionName(property->name(), metaClass); +} + +QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec *property, + const AbstractMetaClass *metaClass) +{ + return cpythonSetterFunctionName(property->name(), metaClass); } static QString cpythonEnumFlagsName(const QString &moduleName, diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index da0c16851..83e7cf5b9 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -53,6 +53,7 @@ extern const char *END_ALLOW_THREADS; class DocParser; class CodeSnip; +class QPropertySpec; class OverloadData; struct GeneratorClassInfoCacheEntry; @@ -308,9 +309,9 @@ protected: static QString cpythonBaseName(const AbstractMetaClass *metaClass); static QString cpythonBaseName(const TypeEntry *type); - QString cpythonBaseName(const AbstractMetaType *type); - QString cpythonTypeName(const AbstractMetaClass *metaClass); - QString cpythonTypeName(const TypeEntry *type); + static QString cpythonBaseName(const AbstractMetaType *type); + static QString cpythonTypeName(const AbstractMetaClass *metaClass); + static QString cpythonTypeName(const TypeEntry *type); QString cpythonTypeNameExt(const TypeEntry *type) const; QString cpythonTypeNameExt(const AbstractMetaType *type) const; QString cpythonCheckFunction(const TypeEntry *type, bool genericNumberType = false); @@ -341,8 +342,12 @@ protected: QString cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass); static QString cpythonGetattroFunctionName(const AbstractMetaClass *metaClass); static QString cpythonSetattroFunctionName(const AbstractMetaClass *metaClass); - QString cpythonGetterFunctionName(const AbstractMetaField *metaField); - QString cpythonSetterFunctionName(const AbstractMetaField *metaField); + static QString cpythonGetterFunctionName(const AbstractMetaField *metaField); + static QString cpythonSetterFunctionName(const AbstractMetaField *metaField); + static QString cpythonGetterFunctionName(const QPropertySpec *property, + const AbstractMetaClass *metaClass); + static QString cpythonSetterFunctionName(const QPropertySpec *property, + const AbstractMetaClass *metaClass); QString cpythonWrapperCPtr(const AbstractMetaClass *metaClass, const QString &argName = QLatin1String("self")) const; QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName) const; @@ -461,6 +466,11 @@ protected: static QStringList m_knownPythonTypes; private: + static QString cpythonGetterFunctionName(const QString &name, + const AbstractMetaClass *enclosingClass); + static QString cpythonSetterFunctionName(const QString &name, + const AbstractMetaClass *enclosingClass); + static const GeneratorClassInfoCacheEntry &getGeneratorClassInfo(const AbstractMetaClass *scope); static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClass *scope); static bool classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass); |