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.cpp82
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