diff options
Diffstat (limited to 'sources/pyside6/libpyside/feature_select.cpp')
-rw-r--r-- | sources/pyside6/libpyside/feature_select.cpp | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp index c12869777..cfd465267 100644 --- a/sources/pyside6/libpyside/feature_select.cpp +++ b/sources/pyside6/libpyside/feature_select.cpp @@ -89,11 +89,11 @@ 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; @@ -107,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 @@ -129,18 +129,18 @@ 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); + PyObject_SetAttr(dict, PySideName::dict_ring(), next_dict); } static inline void setSelectId(PyObject *dict, int select_id) { - PyObject_SetAttr(dict, PyName::select_id(), PyLong_FromLong(select_id)); + PyObject_SetAttr(dict, PySideName::select_id(), PyLong_FromLong(select_id)); } static inline int getSelectId(PyObject *dict) @@ -162,7 +162,7 @@ static bool replaceClassDict(PyTypeObject *type) * This is mandatory for all type dicts when they are touched. */ ensureNewDictType(); - auto *dict = type->tp_dict; + 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) @@ -172,9 +172,9 @@ static bool replaceClassDict(PyTypeObject *type) // 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; + 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; } @@ -184,7 +184,8 @@ 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; + 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) @@ -194,7 +195,9 @@ static bool addNewDict(PyTypeObject *type, int select_id) auto next_dict = nextInCircle(dict); setNextDict(dict, new_dict); setNextDict(new_dict, next_dict); - type->tp_dict = new_dict; + 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; } @@ -204,18 +207,19 @@ 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; + AutoDecRef tpDict(PepType_GetDict(type)); + auto *initial_dict = tpDict.object(); auto *dict = initial_dict; do { int current_id = getSelectId(dict); // This works because small numbers are singleton objects. if (current_id == select_id) { - type->tp_dict = dict; + PepType_SetDict(type, dict); return true; } dict = nextInCircle(dict); } while (dict != initial_dict); - type->tp_dict = initial_dict; + PepType_SetDict(type, initial_dict); return false; } @@ -234,8 +238,7 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id) 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; int id = select_id; @@ -245,13 +248,14 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id) 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; } @@ -266,7 +270,9 @@ 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)) { @@ -320,7 +326,9 @@ static inline void 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)) { Py_FatalError("failed to replace class dict!"); @@ -388,12 +396,18 @@ static FeatureProc featureProcArray[] = { 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) { featurePointer = featureProcArray; initSelectableFeature(SelectFeatureSet); + setSelectableFeatureCallback(featureEnableCallback); patch_property_impl(); is_initialized = true; } @@ -454,7 +468,8 @@ static PyObject *methodWithNewName(PyTypeObject *type, 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. @@ -501,12 +516,12 @@ 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) { @@ -585,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; @@ -611,9 +626,9 @@ static QByteArrayList GetPropertyStringsMro(PyTypeObject *type) auto res = QByteArrayList(); PyObject *mro = type->tp_mro; - Py_ssize_t idx, n = PyTuple_GET_SIZE(mro); + const Py_ssize_t n = PyTuple_GET_SIZE(mro); // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2". - for (idx = 0; idx < n - 2; idx++) { + 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) @@ -630,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) @@ -744,11 +760,11 @@ 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; + 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; } @@ -763,7 +779,8 @@ static bool patch_property_impl() #define SIMILAR_FEATURE(xx) \ 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) \ @@ -778,5 +795,4 @@ SIMILAR_FEATURE(20) SIMILAR_FEATURE(40) SIMILAR_FEATURE(80) -} // namespace PySide -} // namespace Feature +} // namespace PySide::Feature |