aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside/feature_select.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpyside/feature_select.cpp')
-rw-r--r--sources/pyside6/libpyside/feature_select.cpp339
1 files changed, 182 insertions, 157 deletions
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp
index d6a6300d7..cfd465267 100644
--- a/sources/pyside6/libpyside/feature_select.cpp
+++ b/sources/pyside6/libpyside/feature_select.cpp
@@ -89,18 +89,14 @@ This is everything that the following code does.
*****************************************************************************/
-namespace PySide { namespace Feature {
+namespace PySide::Feature {
using namespace Shiboken;
-typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict, int id);
+using FeatureProc = bool(*)(PyTypeObject *type, PyObject *prev_dict, int id);
static FeatureProc *featurePointer = nullptr;
-static PyObject *_fast_id_array[1 + 256] = {};
-// this will point to element 1 to allow indexing from -1
-static PyObject **fast_id_array;
-
// Create a derived dict class
static PyTypeObject *
createDerivedDictType()
@@ -111,7 +107,7 @@ createDerivedDictType()
PyObject *ChameleonDict = PepRun_GetResult(R"CPP(if True:
class ChameleonDict(dict):
- __slots__ = ("dict_ring", "select_id")
+ __slots__ = ("dict_ring", "select_id", "orig_dict")
result = ChameleonDict
@@ -133,43 +129,30 @@ static void ensureNewDictType()
static inline PyObject *nextInCircle(PyObject *dict)
{
// returns a borrowed ref
- AutoDecRef next_dict(PyObject_GetAttr(dict, PyName::dict_ring()));
+ AutoDecRef next_dict(PyObject_GetAttr(dict, PySideName::dict_ring()));
return next_dict;
}
static inline void setNextDict(PyObject *dict, PyObject *next_dict)
{
- PyObject_SetAttr(dict, PyName::dict_ring(), next_dict);
-}
-
-static inline void setSelectId(PyObject *dict, PyObject *select_id)
-{
- PyObject_SetAttr(dict, PyName::select_id(), select_id);
-}
-
-static inline PyObject *getSelectId(PyObject *dict)
-{
- auto select_id = PyObject_GetAttr(dict, PyName::select_id());
- return select_id;
-}
-
-static inline void setCurrentSelectId(PyTypeObject *type, PyObject *select_id)
-{
- SbkObjectType_SetReserved(type, PyLong_AsSsize_t(select_id)); // int/long cheating
+ PyObject_SetAttr(dict, PySideName::dict_ring(), next_dict);
}
-static inline void setCurrentSelectId(PyTypeObject *type, int id)
+static inline void setSelectId(PyObject *dict, int select_id)
{
- SbkObjectType_SetReserved(type, id);
+ PyObject_SetAttr(dict, PySideName::select_id(), PyLong_FromLong(select_id));
}
-static inline PyObject *getCurrentSelectId(PyTypeObject *type)
+static inline int getSelectId(PyObject *dict)
{
- int id = SbkObjectType_GetReserved(type);
- // This can be too early.
- if (id < 0)
- id = 0;
- return fast_id_array[id];
+ auto *py_select_id = PyObject_GetAttr(dict, PyName::select_id());
+ if (py_select_id == nullptr) {
+ PyErr_Clear();
+ return 0;
+ }
+ int ret = PyLong_AsLong(py_select_id);
+ Py_DECREF(py_select_id);
+ return ret;
}
static bool replaceClassDict(PyTypeObject *type)
@@ -179,33 +162,32 @@ static bool replaceClassDict(PyTypeObject *type)
* This is mandatory for all type dicts when they are touched.
*/
ensureNewDictType();
- PyObject *dict = type->tp_dict;
- auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
- PyObject *new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ AutoDecRef dict(PepType_GetDict(type));
+ auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr || PyDict_Update(new_dict, dict) < 0)
return false;
// Insert the default id. Cannot fail for small numbers.
- AutoDecRef select_id(PyLong_FromLong(0));
- setSelectId(new_dict, select_id);
+ setSelectId(new_dict, 0);
// insert the dict into itself as ring
setNextDict(new_dict, new_dict);
// We have now an exact copy of the dict with a new type.
- // Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py)
- Py_DECREF(type->tp_dict);
- type->tp_dict = new_dict;
- setCurrentSelectId(type, select_id.object());
+ PepType_SetDict(type, new_dict);
+ // PYSIDE-2404: Retain the original dict for easy late init.
+ PyObject_SetAttr(new_dict, PySideName::orig_dict(), dict);
return true;
}
-static bool addNewDict(PyTypeObject *type, PyObject *select_id)
+static bool addNewDict(PyTypeObject *type, int select_id)
{
/*
* Add a new dict to the ring and set it as `type->tp_dict`.
* A 'false' return is fatal.
*/
- auto dict = type->tp_dict;
- auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
- auto new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ AutoDecRef dict(PepType_GetDict(type));
+ AutoDecRef orig_dict(PyObject_GetAttr(dict, PySideName::orig_dict()));
+ auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr)
return false;
setSelectId(new_dict, select_id);
@@ -213,35 +195,35 @@ static bool addNewDict(PyTypeObject *type, PyObject *select_id)
auto next_dict = nextInCircle(dict);
setNextDict(dict, new_dict);
setNextDict(new_dict, next_dict);
- type->tp_dict = new_dict;
- setCurrentSelectId(type, select_id);
+ PepType_SetDict(type, new_dict);
+ // PYSIDE-2404: Retain the original dict for easy late init.
+ PyObject_SetAttr(new_dict, PySideName::orig_dict(), orig_dict);
return true;
}
-static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
+static inline bool moveToFeatureSet(PyTypeObject *type, int select_id)
{
/*
* Rotate the ring to the given `select_id` and return `true`.
* If not found, stay at the current position and return `false`.
*/
- auto initial_dict = type->tp_dict;
- auto dict = initial_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *initial_dict = tpDict.object();
+ auto *dict = initial_dict;
do {
- dict = nextInCircle(dict);
- AutoDecRef current_id(getSelectId(dict));
+ int current_id = getSelectId(dict);
// This works because small numbers are singleton objects.
if (current_id == select_id) {
- type->tp_dict = dict;
- setCurrentSelectId(type, select_id);
+ PepType_SetDict(type, dict);
return true;
}
+ dict = nextInCircle(dict);
} while (dict != initial_dict);
- type->tp_dict = initial_dict;
- setCurrentSelectId(type, getSelectId(initial_dict));
+ PepType_SetDict(type, initial_dict);
return false;
}
-static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
+static bool createNewFeatureSet(PyTypeObject *type, int select_id)
{
/*
* Create a new feature set.
@@ -251,37 +233,29 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
* content in `prev_dict`. It is responsible of filling `type->tp_dict`
* with modified content.
*/
- static auto small_1 = PyLong_FromLong(255);
- Q_UNUSED(small_1);
- static auto small_2 = PyLong_FromLong(255);
- Q_UNUSED(small_2);
- // make sure that small integers are cached
- assert(small_1 != nullptr && small_1 == small_2);
-
- static auto zero = fast_id_array[0];
- bool ok = moveToFeatureSet(type, zero);
+
+ bool ok = moveToFeatureSet(type, 0);
Q_UNUSED(ok);
assert(ok);
- AutoDecRef prev_dict(type->tp_dict);
- Py_INCREF(prev_dict); // keep the first ref unchanged
+ AutoDecRef prev_dict(PepType_GetDict(type));
if (!addNewDict(type, select_id))
return false;
- auto id = PyLong_AsSsize_t(select_id); // int/long cheating
+ int id = select_id;
if (id == -1)
return false;
- setCurrentSelectId(type, id);
FeatureProc *proc = featurePointer;
for (int idx = id; *proc != nullptr; ++proc, idx >>= 1) {
if (idx & 1) {
// clear the tp_dict that will get new content
- PyDict_Clear(type->tp_dict);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyDict_Clear(tpDict);
// let the proc re-fill the tp_dict
if (!(*proc)(type, prev_dict, id))
return false;
// if there is still a step, prepare `prev_dict`
if (idx >> 1) {
- prev_dict.reset(PyDict_Copy(type->tp_dict));
+ prev_dict.reset(PyDict_Copy(tpDict.object()));
if (prev_dict.isNull())
return false;
}
@@ -290,30 +264,59 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
return true;
}
-static bool SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
+static inline void SelectFeatureSetSubtype(PyTypeObject *type, int select_id)
{
/*
* This is the selector for one sublass. We need to call this for
* every subclass until no more subclasses or reaching the wanted id.
*/
- if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
+ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) {
// On first touch, we initialize the dynamic naming.
// The dict type will be replaced after the first call.
if (!replaceClassDict(type)) {
Py_FatalError("failed to replace class dict!");
- return false;
+ return;
}
}
if (!moveToFeatureSet(type, select_id)) {
if (!createNewFeatureSet(type, select_id)) {
Py_FatalError("failed to create a new feature set!");
- return false;
+ return;
}
}
- return true;
-}
+ }
+
+static PyObject *cached_globals{};
+static int last_select_id{};
-static inline PyObject *SelectFeatureSet(PyTypeObject *type)
+static inline int getFeatureSelectId()
+{
+ static auto *undef = PyLong_FromLong(-1);
+ static auto *feature_dict = GetFeatureDict();
+ // these things are all borrowed
+ auto *globals = PyEval_GetGlobals();
+ if (globals == nullptr
+ || globals == cached_globals)
+ return last_select_id;
+
+ auto *modname = PyDict_GetItem(globals, PyMagicName::name());
+ if (modname == nullptr)
+ return last_select_id;
+
+ auto *py_select_id = PyDict_GetItem(feature_dict, modname);
+ if (py_select_id == nullptr
+ || !PyLong_Check(py_select_id)
+ || py_select_id == undef)
+ return last_select_id;
+
+ cached_globals = globals;
+ last_select_id = PyLong_AsLong(py_select_id) & 0xff;
+ return last_select_id;
+}
+
+static inline void SelectFeatureSet(PyTypeObject *type)
{
/*
* This is the main function of the module.
@@ -323,33 +326,35 @@ static inline PyObject *SelectFeatureSet(PyTypeObject *type)
* Generated functions call this directly.
* Shiboken will assign it via a public hook of `basewrapper.cpp`.
*/
- if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
+ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) {
// We initialize the dynamic features by using our own dict type.
- if (!replaceClassDict(type))
- return nullptr;
- }
- PyObject *select_id = getFeatureSelectId(); // borrowed
- PyObject *current_id = getCurrentSelectId(type); // borrowed
- static PyObject *undef = fast_id_array[-1];
-
- // PYSIDE-1019: During import PepType_SOTP is still zero.
- if (current_id == undef)
- current_id = select_id = fast_id_array[0];
-
- if (select_id != current_id) {
- PyObject *mro = type->tp_mro;
- Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
- // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2".
- for (idx = 0; idx < n - 2; idx++) {
- auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
- // When any subtype is already resolved (false), we can stop.
- if (!SelectFeatureSetSubtype(sub_type, select_id))
- break;
+ if (!replaceClassDict(type)) {
+ Py_FatalError("failed to replace class dict!");
+ return;
}
- // PYSIDE-1436: Clear all caches for the type and subtypes.
- PyType_Modified(type);
}
- return type->tp_dict;
+
+ int select_id = getFeatureSelectId();
+ static int last_select_id{};
+ static PyTypeObject *last_type{};
+
+ // PYSIDE-2029: Implement a very simple but effective cache that cannot fail.
+ if (type == last_type && select_id == last_select_id)
+ return;
+ last_type = type;
+ last_select_id = select_id;
+
+ auto *mro = type->tp_mro;
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2".
+ for (idx = 0; idx < n - 2; idx++) {
+ auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ SelectFeatureSetSubtype(sub_type, select_id);
+ }
+ // PYSIDE-1436: Clear all caches for the type and subtypes.
+ PyType_Modified(type);
}
// For cppgenerator:
@@ -357,15 +362,14 @@ void Select(PyObject *obj)
{
if (featurePointer == nullptr)
return;
- auto type = Py_TYPE(obj);
- type->tp_dict = SelectFeatureSet(type);
+ auto *type = Py_TYPE(obj);
+ SelectFeatureSet(type);
}
-PyObject *Select(PyTypeObject *type)
+void Select(PyTypeObject *type)
{
if (featurePointer != nullptr)
- type->tp_dict = SelectFeatureSet(type);
- return type->tp_dict;
+ SelectFeatureSet(type);
}
static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id);
@@ -389,30 +393,27 @@ static FeatureProc featureProcArray[] = {
nullptr
};
-void finalize()
-{
- for (int idx = -1; idx < 256; ++idx)
- Py_DECREF(fast_id_array[idx]);
-}
-
static bool patch_property_impl();
static bool is_initialized = false;
+static void featureEnableCallback(bool enable)
+{
+ featurePointer = enable ? featureProcArray : nullptr;
+}
+
void init()
{
// This function can be called multiple times.
if (!is_initialized) {
- fast_id_array = &_fast_id_array[1];
- for (int idx = -1; idx < 256; ++idx)
- fast_id_array[idx] = PyLong_FromLong(idx);
featurePointer = featureProcArray;
initSelectableFeature(SelectFeatureSet);
- registerCleanupFunction(finalize);
+ setSelectableFeatureCallback(featureEnableCallback);
patch_property_impl();
is_initialized = true;
}
+ last_select_id = 0;
// Reset the cache. This is called at any "from __feature__ import".
- initFeatureShibokenPart();
+ cached_globals = nullptr;
}
void Enable(bool enable)
@@ -442,7 +443,7 @@ static PyObject *methodWithNewName(PyTypeObject *type,
/*
* Create a method with a lower case name.
*/
- auto obtype = reinterpret_cast<PyObject *>(type);
+ auto *obtype = reinterpret_cast<PyObject *>(type);
int len = strlen(new_name);
auto name = new char[len + 1];
strcpy(name, new_name);
@@ -464,10 +465,11 @@ static PyObject *methodWithNewName(PyTypeObject *type,
return descr;
}
-static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id)
+static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int /* id */)
{
PyMethodDef *meth = type->tp_methods;
- PyObject *lower_dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *lower_dict = tpDict.object();
// PYSIDE-1702: A user-defined class in Python has no internal method list.
// We are not going to change anything.
@@ -514,20 +516,20 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, in
// This is the Python 2 version for inspection of m_ml, only.
// The actual Python 3 version is larget.
-typedef struct {
+struct PyCFunctionObject {
PyObject_HEAD
PyMethodDef *m_ml; /* Description of the C function to call */
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
PyObject *m_module; /* The __module__ attribute, can be anything */
-} PyCFunctionObject;
+};
static PyObject *modifyStaticToClassMethod(PyTypeObject *type, PyObject *sm)
{
AutoDecRef func_ob(PyObject_GetAttr(sm, PyMagicName::func()));
if (func_ob.isNull())
return nullptr;
- auto func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
- auto new_func = new PyMethodDef;
+ auto *func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
+ auto *new_func = new PyMethodDef;
new_func->ml_name = func->m_ml->ml_name;
new_func->ml_meth = func->m_ml->ml_meth;
new_func->ml_flags = (func->m_ml->ml_flags & ~METH_STATIC) | METH_CLASS;
@@ -541,26 +543,26 @@ static PyObject *createProperty(PyTypeObject *type, PyObject *getter, PyObject *
assert(getter != nullptr);
if (setter == nullptr)
setter = Py_None;
- auto ptype = &PyProperty_Type;
+ auto *ptype = &PyProperty_Type;
if (Py_TYPE(getter) == PepStaticMethod_TypePtr) {
ptype = PyClassProperty_TypeF();
getter = modifyStaticToClassMethod(type, getter);
if (setter != Py_None)
setter = modifyStaticToClassMethod(type, setter);
}
- auto obtype = reinterpret_cast<PyObject *>(ptype);
+ auto *obtype = reinterpret_cast<PyObject *>(ptype);
PyObject *prop = PyObject_CallFunctionObjArgs(obtype, getter, setter, nullptr);
return prop;
}
-static QStringList parseFields(const char *propstr, bool *stdwrite)
+static const QByteArrayList parseFields(const char *propStr, bool *stdWrite)
{
/*
* Break the string into subfields at ':' and add defaults.
*/
- if (stdwrite)
- *stdwrite = true;
- QString s = QString(QLatin1String(propstr));
+ if (stdWrite)
+ *stdWrite = true;
+ QByteArray s = QByteArray(propStr);
auto list = s.split(u':');
assert(list.size() == 2 || list.size() == 3);
auto name = list[0];
@@ -570,20 +572,20 @@ static QStringList parseFields(const char *propstr, bool *stdwrite)
if (list.size() == 2)
return list;
auto write = list[2];
- if (stdwrite)
- *stdwrite = write.isEmpty();
+ if (stdWrite)
+ *stdWrite = write.isEmpty();
if (write.isEmpty()) {
- list[2] = QLatin1String("set") + name;
- list[2][3] = list[2][3].toUpper();
+ list[2] = "set" + name;
+ list[2][3] = std::toupper(list[2][3]);
}
return list;
}
-static PyObject *make_snake_case(QString s, bool lower)
+static PyObject *make_snake_case(const QByteArray &s, bool lower)
{
if (s.isNull())
return nullptr;
- return String::getSnakeCaseName(s.toLatin1().data(), lower);
+ return String::getSnakeCaseName(s.constData(), lower);
}
PyObject *adjustPropertyName(PyObject *dict, PyObject *name)
@@ -598,7 +600,7 @@ PyObject *adjustPropertyName(PyObject *dict, PyObject *name)
if (PyList_CheckExact(sig)) {
name_clash = true;
} else {
- Shiboken::AutoDecRef params(PyObject_GetAttr(sig, PyName::parameters()));
+ Shiboken::AutoDecRef params(PyObject_GetAttr(sig, PySideName::parameters()));
// Are there parameters except self or cls?
if (PyObject_Size(params.object()) > 1)
name_clash = true;
@@ -614,6 +616,28 @@ PyObject *adjustPropertyName(PyObject *dict, PyObject *name)
return name;
}
+static QByteArrayList GetPropertyStringsMro(PyTypeObject *type)
+{
+ /*
+ * PYSIDE-2042: There are possibly more methods which should become properties,
+ * because the wrapping process does not obey inheritance.
+ * Therefore, we need to walk the mro to find property strings.
+ */
+ auto res = QByteArrayList();
+
+ PyObject *mro = type->tp_mro;
+ const Py_ssize_t n = PyTuple_GET_SIZE(mro);
+ // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2".
+ for (Py_ssize_t idx = 0; idx < n - 2; idx++) {
+ auto *subType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ auto props = SbkObjectType_GetPropertyStrings(subType);
+ if (props != nullptr)
+ for (; *props != nullptr; ++props)
+ res << QByteArray(*props);
+ }
+ return res;
+}
+
static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id)
{
/*
@@ -621,7 +645,8 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
*/
PyMethodDef *meth = type->tp_methods;
- PyObject *prop_dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *prop_dict = tpDict.object();
// The empty `tp_dict` gets populated by the previous dict.
if (PyDict_Update(prop_dict, prev_dict) < 0)
@@ -643,13 +668,13 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
}
// We then replace methods by properties.
bool lower = (id & 0x01) != 0;
- auto props = SbkObjectType_GetPropertyStrings(type);
- if (props == nullptr || *props == nullptr)
+ auto props = GetPropertyStringsMro(type);
+ if (props.isEmpty())
return true;
- for (; *props != nullptr; ++props) {
+
+ for (const auto &propStr : std::as_const(props)) {
bool isStdWrite;
- auto propstr = *props;
- auto fields = parseFields(propstr, &isStdWrite);
+ auto fields = parseFields(propStr, &isStdWrite);
bool haveWrite = fields.size() == 3;
PyObject *name = make_snake_case(fields[0], lower);
PyObject *read = make_snake_case(fields[1], lower);
@@ -695,7 +720,7 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
static PyObject *property_doc_get(PyObject *self, void *)
{
- auto po = reinterpret_cast<propertyobject *>(self);
+ auto *po = reinterpret_cast<propertyobject *>(self);
if (po->prop_doc != nullptr && po->prop_doc != Py_None) {
Py_INCREF(po->prop_doc);
@@ -703,7 +728,7 @@ static PyObject *property_doc_get(PyObject *self, void *)
}
if (po->prop_get) {
// PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
- auto txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc());
+ auto *txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc());
if (txt != nullptr) {
Py_INCREF(txt);
po->prop_doc = txt;
@@ -717,7 +742,7 @@ static PyObject *property_doc_get(PyObject *self, void *)
static int property_doc_set(PyObject *self, PyObject *value, void *)
{
- auto po = reinterpret_cast<propertyobject *>(self);
+ auto *po = reinterpret_cast<propertyobject *>(self);
Py_INCREF(value);
po->prop_doc = value;
@@ -734,12 +759,12 @@ static bool patch_property_impl()
{
// Turn `__doc__` into a computed attribute without changing writability.
auto gsp = property_getset;
- auto type = &PyProperty_Type;
- auto dict = type->tp_dict;
+ auto *type = &PyProperty_Type;
+ AutoDecRef dict(PepType_GetDict(type));
AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
if (descr.isNull())
return false;
- if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ if (PyDict_SetItemString(dict.object(), gsp->name, descr) < 0)
return false;
return true;
}
@@ -748,13 +773,14 @@ static bool patch_property_impl()
//
// PYSIDE-1019: Support switchable extensions
//
-// Feature 0x04..0x40: A fake switchable option for testing
+// Feature 0x04..0x80: A fake switchable option for testing
//
#define SIMILAR_FEATURE(xx) \
-static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id) \
+static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int /* id */) \
{ \
- PyObject *dict = type->tp_dict; \
+ AutoDecRef tpDict(PepType_GetDict(type)); \
+ PyObject *dict = tpDict.object(); \
if (PyDict_Update(dict, prev_dict) < 0) \
return false; \
if (PyDict_SetItemString(dict, "fake_feature_" #xx, Py_None) < 0) \
@@ -769,5 +795,4 @@ SIMILAR_FEATURE(20)
SIMILAR_FEATURE(40)
SIMILAR_FEATURE(80)
-} // namespace PySide
-} // namespace Feature
+} // namespace PySide::Feature