aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken')
-rw-r--r--sources/shiboken6/libshiboken/CMakeLists.txt199
-rw-r--r--sources/shiboken6/libshiboken/autodecref.h87
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp1924
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h519
-rw-r--r--sources/shiboken6/libshiboken/basewrapper_p.h167
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp549
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.h93
-rw-r--r--sources/shiboken6/libshiboken/bufferprocs_py37.cpp360
-rw-r--r--sources/shiboken6/libshiboken/bufferprocs_py37.h109
-rw-r--r--sources/shiboken6/libshiboken/debugfreehook.cpp158
-rw-r--r--sources/shiboken6/libshiboken/debugfreehook.h25
-rw-r--r--sources/shiboken6/libshiboken/embed/embedding_generator.py220
-rw-r--r--sources/shiboken6/libshiboken/embed/module_collector.py71
-rw-r--r--sources/shiboken6/libshiboken/embed/qt_python_license.txt48
-rw-r--r--sources/shiboken6/libshiboken/embed/signature_bootstrap.py204
-rw-r--r--sources/shiboken6/libshiboken/gilstate.cpp38
-rw-r--r--sources/shiboken6/libshiboken/gilstate.h33
-rw-r--r--sources/shiboken6/libshiboken/helper.cpp637
-rw-r--r--sources/shiboken6/libshiboken/helper.h120
-rw-r--r--sources/shiboken6/libshiboken/pep384ext.h89
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.cpp1319
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.h611
-rw-r--r--sources/shiboken6/libshiboken/pyobjectholder.h86
-rw-r--r--sources/shiboken6/libshiboken/qt_attribution.json12
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter.cpp246
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter.h136
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter_p.h26
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.cpp19
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.h259
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp910
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.h422
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter_p.h542
-rw-r--r--sources/shiboken6/libshiboken/sbkcppstring.cpp54
-rw-r--r--sources/shiboken6/libshiboken/sbkcppstring.h22
-rw-r--r--sources/shiboken6/libshiboken/sbkcpptonumpy.cpp67
-rw-r--r--sources/shiboken6/libshiboken/sbkcpptonumpy.h41
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp455
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.h102
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.cpp215
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.h78
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp424
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.h18
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.cpp526
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.h89
-rw-r--r--sources/shiboken6/libshiboken/sbknumpy.cpp57
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp270
-rw-r--r--sources/shiboken6/libshiboken/sbknumpycheck.h30
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyview.cpp265
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyview.h47
-rw-r--r--sources/shiboken6/libshiboken/sbkpython.h75
-rw-r--r--sources/shiboken6/libshiboken/sbksmartpointer.cpp58
-rw-r--r--sources/shiboken6/libshiboken/sbksmartpointer.h18
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings.cpp88
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings.h61
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings_p.h37
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.cpp254
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.h42
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.cpp407
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.h26
-rw-r--r--sources/shiboken6/libshiboken/sbkversion.h.in17
-rw-r--r--sources/shiboken6/libshiboken/sbkwindows.h17
-rw-r--r--sources/shiboken6/libshiboken/shiboken.h27
-rw-r--r--sources/shiboken6/libshiboken/shibokenbuffer.cpp70
-rw-r--r--sources/shiboken6/libshiboken/shibokenbuffer.h57
-rw-r--r--sources/shiboken6/libshiboken/shibokenmacros.h26
-rw-r--r--sources/shiboken6/libshiboken/signature.h21
-rw-r--r--sources/shiboken6/libshiboken/signature/signature.cpp640
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_extend.cpp230
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_globals.cpp264
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_helper.cpp389
-rw-r--r--sources/shiboken6/libshiboken/signature_p.h78
-rw-r--r--sources/shiboken6/libshiboken/threadstatesaver.cpp31
-rw-r--r--sources/shiboken6/libshiboken/threadstatesaver.h32
-rw-r--r--sources/shiboken6/libshiboken/voidptr.cpp434
-rw-r--r--sources/shiboken6/libshiboken/voidptr.h33
75 files changed, 16430 insertions, 0 deletions
diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt
new file mode 100644
index 000000000..b5bbb498a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/CMakeLists.txt
@@ -0,0 +1,199 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libshiboken)
+
+option(ENABLE_VERSION_SUFFIX "Used to use current version in suffix to generated files. This is used to allow multiples versions installed simultaneous." FALSE)
+if(ENABLE_VERSION_SUFFIX)
+ set(shiboken6_SUFFIX "-${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+else()
+ set(shiboken6_SUFFIX "")
+endif()
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY)
+
+# Variable from enclosing scope.
+list(TRANSFORM shiboken_python_files
+ PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/"
+ OUTPUT_VARIABLE embedded_shiboken_files)
+
+if (QUIET_BUILD)
+ set(embedding_option "--quiet")
+else()
+ set(embedding_option "")
+endif()
+
+if(SHIBOKEN_IS_CROSS_BUILD)
+ set(host_python_path "${QFP_PYTHON_HOST_PATH}")
+ set(use_pyc_in_embedding FALSE)
+else()
+ set(host_python_path "${Python_EXECUTABLE}")
+ if(PYTHON_LIMITED_API)
+ set(use_pyc_in_embedding FALSE)
+ else()
+ set(use_pyc_in_embedding TRUE)
+ endif()
+endif()
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h"
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h"
+ COMMAND ${host_python_path} -E
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ --cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed"
+ --use-pyc ${use_pyc_in_embedding}
+ ${embedding_option}
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ ${embedded_shiboken_files}
+ )
+
+set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION})
+set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION})
+set(libshiboken_MICRO_VERSION ${shiboken_MICRO_VERSION})
+set(libshiboken_VERSION "${libshiboken_MAJOR_VERSION}.${libshiboken_MINOR_VERSION}.${libshiboken_MICRO_VERSION}")
+set(libshiboken_SOVERSION "${shiboken6_library_so_version}")
+
+set(libshiboken_SRC
+autodecref.h
+basewrapper.cpp basewrapper.h basewrapper_p.h
+bindingmanager.cpp bindingmanager.h
+bufferprocs_py37.cpp bufferprocs_py37.h
+debugfreehook.cpp debugfreehook.h
+gilstate.cpp gilstate.h
+helper.cpp helper.h
+pep384impl.cpp pep384impl.h
+pyobjectholder.h
+sbkarrayconverter.cpp sbkarrayconverter.h sbkarrayconverter_p.h
+sbkcontainer.cpp sbkcontainer.h
+sbkconverter.cpp sbkconverter.h sbkconverter_p.h
+sbkcppstring.cpp sbkcppstring.h sbkcpptonumpy.h
+sbkenum.cpp sbkenum.h
+sbkerrors.cpp sbkerrors.h
+sbkfeature_base.cpp sbkfeature_base.h
+sbkmodule.cpp sbkmodule.h
+sbknumpy.cpp sbknumpycheck.h
+sbknumpyview.h
+sbkpython.h
+sbksmartpointer.cpp sbksmartpointer.h
+sbkstaticstrings.cpp sbkstaticstrings.h sbkstaticstrings_p.h
+sbkstring.cpp sbkstring.h
+sbktypefactory.cpp sbktypefactory.h
+sbkwindows.h
+shiboken.h
+shibokenbuffer.cpp shibokenbuffer.h
+shibokenmacros.h
+threadstatesaver.cpp threadstatesaver.h
+voidptr.cpp voidptr.h
+
+embed/signature_bootstrap_inc.h
+embed/signature_inc.h
+
+signature/signature.cpp signature.h signature_p.h
+signature/signature_globals.cpp
+signature/signature_extend.cpp
+signature/signature_helper.cpp
+)
+
+# This is needed to let the header obey a variable in "pep384impl.h".
+# Note: This must be set on the cpp file!
+set_property(SOURCE "pep384impl.cpp" PROPERTY SKIP_UNITY_BUILD_INCLUSION ON)
+
+add_library(libshiboken SHARED ${libshiboken_SRC})
+add_library(Shiboken6::libshiboken ALIAS libshiboken)
+
+target_include_directories(libshiboken PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+ $<INSTALL_INTERFACE:include/shiboken6>
+)
+
+if (NOT "${NUMPY_INCLUDE_DIR}" STREQUAL "")
+ message(STATUS "NUMPY_INCLUDE_DIR: " ${NUMPY_INCLUDE_DIR})
+ target_include_directories(libshiboken PRIVATE ${NUMPY_INCLUDE_DIR})
+ target_compile_definitions(libshiboken PRIVATE -DHAVE_NUMPY
+ PRIVATE -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION)
+else()
+ message(STATUS "NUMPY not found")
+endif()
+
+if(SHIBOKEN_IS_CROSS_BUILD)
+ target_compile_definitions(libshiboken PRIVATE -DSHIBOKEN_NO_EMBEDDING_PYC=1)
+endif()
+
+shiboken_compute_python_includes()
+# On Windows we need to link against the python.lib import library.
+# On macOS and Linux we don't link against the python shared / static library,
+# the dynamic linker will pick up the python symbols at runtime automatically.
+shiboken_compute_python_libraries()
+
+if(PYTHON_LIMITED_API)
+ target_compile_definitions(libshiboken PUBLIC "-DPy_LIMITED_API=0x03060000")
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ if(PYTHON_WITH_DEBUG)
+ target_compile_definitions(libshiboken PUBLIC "-DPy_DEBUG")
+ endif()
+ if (PYTHON_WITH_COUNT_ALLOCS)
+ target_compile_definitions(libshiboken PUBLIC "-DCOUNT_ALLOCS")
+ endif()
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+ target_compile_definitions(libshiboken PUBLIC "-DNDEBUG")
+endif()
+
+set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken6${shiboken6_SUFFIX}${PYTHON_SHARED_LIBRARY_SUFFIX}"
+ VERSION ${libshiboken_VERSION}
+ SOVERSION ${libshiboken_SOVERSION}
+ DEFINE_SYMBOL BUILD_LIBSHIBOKEN)
+
+qfp_strip_library("libshiboken")
+
+install(FILES
+ autodecref.h
+ basewrapper.h
+ basewrapper_p.h
+ bindingmanager.h
+ gilstate.h
+ helper.h
+ pyobjectholder.h
+ sbkarrayconverter.h
+ sbkcontainer.h
+ sbkconverter.h
+ sbkcpptonumpy.h
+ sbkenum.h
+ sbkerrors.h
+ sbkfeature_base.h
+ sbkmodule.h
+ sbknumpycheck.h
+ sbknumpyview.h
+ sbkstring.h
+ sbkcppstring.h
+ sbksmartpointer.h
+ sbkstaticstrings.h
+ sbktypefactory.h
+ shiboken.h
+ shibokenmacros.h
+ threadstatesaver.h
+ shibokenbuffer.h
+ sbkpython.h
+ sbkwindows.h
+ pep384impl.h
+ pep384ext.h
+ voidptr.h
+ bufferprocs_py37.h
+ "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
+
+ signature.h
+ signature_p.h
+
+ DESTINATION include/shiboken6${shiboken6_SUFFIX})
+install(TARGETS libshiboken EXPORT Shiboken6Targets
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+ RUNTIME DESTINATION bin)
+install(EXPORT Shiboken6Targets NAMESPACE Shiboken6::
+ DESTINATION ${LIB_INSTALL_DIR}/cmake/Shiboken6)
diff --git a/sources/shiboken6/libshiboken/autodecref.h b/sources/shiboken6/libshiboken/autodecref.h
new file mode 100644
index 000000000..62a8584e1
--- /dev/null
+++ b/sources/shiboken6/libshiboken/autodecref.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef AUTODECREF_H
+#define AUTODECREF_H
+
+#include "sbkpython.h"
+
+#include <utility>
+
+struct SbkObject;
+namespace Shiboken
+{
+
+/**
+ * AutoDecRef holds a PyObject pointer and decrement its reference counter when destroyed.
+ */
+struct AutoDecRef
+{
+public:
+ AutoDecRef(const AutoDecRef &) = delete;
+ AutoDecRef(AutoDecRef &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
+ AutoDecRef &operator=(const AutoDecRef &) = delete;
+ AutoDecRef &operator=(AutoDecRef &&o) noexcept
+ {
+ m_pyObj = std::exchange(o.m_pyObj, nullptr);
+ return *this;
+ }
+
+ /// AutoDecRef constructor.
+ /// \param pyobj A borrowed reference to a Python object
+ explicit AutoDecRef(PyObject *pyObj) noexcept : m_pyObj(pyObj) {}
+ /// AutoDecRef constructor.
+ /// \param pyobj A borrowed reference to a wrapped Python object
+ explicit AutoDecRef(SbkObject *pyObj) noexcept : m_pyObj(reinterpret_cast<PyObject *>(pyObj)) {}
+ /// AutoDecref default constructor.
+ /// To be used later with reset():
+ AutoDecRef() noexcept = default;
+
+ /// Decref the borrowed python reference
+ ~AutoDecRef()
+ {
+ Py_XDECREF(m_pyObj);
+ }
+
+ [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
+ /// Returns the pointer of the Python object being held.
+ [[nodiscard]] PyObject *object() const { return m_pyObj; }
+ [[nodiscard]] operator PyObject *() const { return m_pyObj; }
+#ifndef Py_LIMITED_API
+ [[deprecated]] inline operator PyTupleObject *()
+ { return reinterpret_cast<PyTupleObject *>(m_pyObj); }
+#endif
+ inline operator bool() const { return m_pyObj != nullptr; }
+ inline PyObject *operator->() { return m_pyObj; }
+
+ template<typename T>
+ [[deprecated]] T cast()
+ {
+ return reinterpret_cast<T>(m_pyObj);
+ }
+
+ /**
+ * Decref the current borrowed python reference and borrow \p other.
+ */
+ void reset(PyObject *other)
+ {
+ // Safely decref m_pyObj. See Py_XSETREF in object.h .
+ PyObject *_py_tmp = m_pyObj;
+ m_pyObj = other;
+ Py_XDECREF(_py_tmp);
+ }
+
+ PyObject *release()
+ {
+ PyObject *result = m_pyObj;
+ m_pyObj = nullptr;
+ return result;
+ }
+
+private:
+ PyObject *m_pyObj = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // AUTODECREF_H
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
new file mode 100644
index 000000000..0ce80d0c6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -0,0 +1,1924 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "helper.h"
+#include "pep384ext.h"
+#include "sbkconverter.h"
+#include "sbkenum.h"
+#include "sbkerrors.h"
+#include "sbkfeature_base.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "autodecref.h"
+#include "gilstate.h"
+#include <string>
+#include <cstring>
+#include <cstddef>
+#include <set>
+#include <sstream>
+#include <algorithm>
+#include "threadstatesaver.h"
+#include "signature.h"
+#include "signature_p.h"
+#include "voidptr.h"
+
+#include <string>
+#include <iostream>
+#include <sstream>
+
+#if defined(__APPLE__)
+#include <dlfcn.h>
+#endif
+
+namespace {
+ void _destroyParentInfo(SbkObject *obj, bool keepReference);
+}
+
+namespace Shiboken
+{
+// Walk through the first level of non-user-type Sbk base classes relevant for
+// C++ object allocation. Return true from the predicate to terminate.
+template <class Predicate>
+bool walkThroughBases(PyTypeObject *currentType, Predicate predicate)
+{
+ PyObject *bases = currentType->tp_bases;
+ const Py_ssize_t numBases = PyTuple_Size(bases);
+ bool result = false;
+ for (Py_ssize_t i = 0; !result && i < numBases; ++i) {
+ auto type = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(bases, i));
+ if (PyType_IsSubtype(type, SbkObject_TypeF()) != 0) {
+ result = PepType_SOTP(type)->is_user_type
+ ? walkThroughBases(type, predicate) : predicate(type);
+ }
+ }
+ return result;
+}
+
+int getTypeIndexOnHierarchy(PyTypeObject *baseType, PyTypeObject *desiredType)
+{
+ int index = -1;
+ walkThroughBases(baseType, [&index, desiredType](PyTypeObject *node) {
+ ++index;
+ return PyType_IsSubtype(node, desiredType) != 0;
+ });
+ return index;
+}
+
+int getNumberOfCppBaseClasses(PyTypeObject *baseType)
+{
+ int count = 0;
+ walkThroughBases(baseType, [&count](PyTypeObject *) {
+ ++count;
+ return false;
+ });
+ return count;
+}
+
+std::vector<PyTypeObject *> getCppBaseClasses(PyTypeObject *baseType)
+{
+ std::vector<PyTypeObject *> cppBaseClasses;
+ walkThroughBases(baseType, [&cppBaseClasses](PyTypeObject *node) {
+ cppBaseClasses.push_back(node);
+ return false;
+ });
+ return cppBaseClasses;
+}
+
+using DestructorEntries = std::vector<DestructorEntry>;
+
+DestructorEntries getDestructorEntries(SbkObject *o)
+{
+ DestructorEntries result;
+ void **cptrs = o->d->cptr;
+ walkThroughBases(Py_TYPE(o), [&result, cptrs](PyTypeObject *node) {
+ auto *sotp = PepType_SOTP(node);
+ auto index = result.size();
+ result.push_back(DestructorEntry{sotp->cpp_dtor,
+ cptrs[index]});
+ return false;
+ });
+ return result;
+}
+
+static void callDestructor(const DestructorEntries &dts)
+{
+ for (const auto &e : dts) {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ e.destructor(e.cppInstance);
+ }
+}
+
+} // namespace Shiboken
+
+extern "C"
+{
+
+// PYSIDE-939: A general replacement for object_dealloc.
+void Sbk_object_dealloc(PyObject *self)
+{
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(Py_TYPE(self));
+ }
+ PepExt_TypeCallFree(self);
+}
+
+static void SbkObjectType_tp_dealloc(PyTypeObject *pyType);
+static PyTypeObject *SbkObjectType_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds);
+
+static DestroyQAppHook DestroyQApplication = nullptr;
+
+// PYSIDE-1470: Provide a hook to kill an Application from Shiboken.
+void setDestroyQApplication(DestroyQAppHook func)
+{
+ DestroyQApplication = func;
+}
+
+// PYSIDE-535: Use the C API in PyPy instead of `op->ob_dict`, directly
+LIBSHIBOKEN_API PyObject *SbkObject_GetDict_NoRef(PyObject *op)
+{
+ assert(Shiboken::Object::checkType(op));
+#ifdef PYPY_VERSION
+ Shiboken::GilState state;
+ auto *ret = PyObject_GenericGetDict(op, nullptr);
+ Py_DECREF(ret);
+ return ret;
+#else
+ auto *sbkObj = reinterpret_cast<SbkObject *>(op);
+ if (!sbkObj->ob_dict) {
+ Shiboken::GilState state;
+ sbkObj->ob_dict = PyDict_New();
+ }
+ return sbkObj->ob_dict;
+#endif
+}
+
+static int
+check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name)
+{
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "can't set %s.%s", type->tp_name, name);
+ return 0;
+ }
+ if (!value) {
+ PyErr_Format(PyExc_TypeError,
+ "can't delete %s.%s", type->tp_name, name);
+ return 0;
+ }
+ return 1;
+}
+
+// PYSIDE-1177: Add a setter to allow setting type doc.
+static int
+type_set_doc(PyTypeObject *type, PyObject *value, void * /* context */)
+{
+ if (!check_set_special_type_attr(type, value, "__doc__"))
+ return -1;
+ PyType_Modified(type);
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(type));
+ return PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::doc(), value);
+}
+
+// PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to
+// explicitly pass __doc__.
+static PyGetSetDef SbkObjectType_tp_getset[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(Sbk_TypeGet___doc__),
+ reinterpret_cast<setter>(type_set_doc), nullptr, nullptr},
+ {const_cast<char *>("__dict__"), reinterpret_cast<getter>(Sbk_TypeGet___dict__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel
+};
+
+static PyTypeObject *createObjectTypeType()
+{
+ PyType_Slot SbkObjectType_Type_slots[] = {
+ {Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectType_tp_dealloc)},
+ {Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)},
+ {Py_tp_base, static_cast<void *>(&PyType_Type)},
+ {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
+ {Py_tp_new, reinterpret_cast<void *>(SbkObjectType_tp_new)},
+ {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_tp_getset)},
+ {0, nullptr}
+ };
+
+ // PYSIDE-535: The tp_itemsize field is inherited and does not need to be set.
+ // In PyPy, it _must_ not be set, because it would have the meanin
+ // that a `__len__` field must be defined. Not doing so creates
+ // a hard-to-find crash.
+ //
+ // PYSIDE-2230: In Python < 3.12, the decision which base class should create
+ // the instance is arbitrarily drawn by the size of the type.
+ // Ignoring this creates a bug in the new version of bug_825 that
+ // selects the wrong metatype.
+ //
+ PyType_Spec SbkObjectType_Type_spec = {
+ "1:Shiboken.ObjectType",
+ static_cast<int>(PyType_Type.tp_basicsize) + 1, // see above
+ 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
+ SbkObjectType_Type_slots,
+ };
+
+ PyType_Spec SbkObjectType_Type_spec_312 = {
+ "1:Shiboken.ObjectType",
+ -long(sizeof(SbkObjectTypePrivate)),
+ 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
+ SbkObjectType_Type_slots,
+ };
+
+ return SbkType_FromSpec(_PepRuntimeVersion() >= 0x030C00 ?
+ &SbkObjectType_Type_spec_312 :
+ &SbkObjectType_Type_spec);
+}
+
+PyTypeObject *SbkObjectType_TypeF(void)
+{
+ static auto *type = createObjectTypeType();
+ return type;
+}
+
+static PyObject *SbkObjectGetDict(PyObject *pObj, void *)
+{
+ auto ret = SbkObject_GetDict_NoRef(pObj);
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyGetSetDef SbkObject_tp_getset[] = {
+ {const_cast<char *>("__dict__"), SbkObjectGetDict, nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel
+};
+
+static int SbkObject_tp_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ auto *sbkSelf = reinterpret_cast<SbkObject *>(self);
+
+ //Visit children
+ Shiboken::ParentInfo *pInfo = sbkSelf->d->parentInfo;
+ if (pInfo) {
+ for (SbkObject *c : pInfo->children)
+ Py_VISIT(c);
+ }
+
+ //Visit refs
+ Shiboken::RefCountMap *rInfo = sbkSelf->d->referredObjects;
+ if (rInfo) {
+ for (auto it = rInfo->begin(), end = rInfo->end(); it != end; ++it)
+ Py_VISIT(it->second);
+ }
+
+ if (sbkSelf->ob_dict)
+ Py_VISIT(sbkSelf->ob_dict);
+
+ // This was not needed before Python 3.9 (Python issue 35810 and 40217)
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
+static int SbkObject_tp_clear(PyObject *self)
+{
+ auto *sbkSelf = reinterpret_cast<SbkObject *>(self);
+
+ Shiboken::Object::removeParent(sbkSelf);
+
+ if (sbkSelf->d->parentInfo)
+ _destroyParentInfo(sbkSelf, true);
+
+ Shiboken::Object::clearReferences(sbkSelf);
+
+ if (sbkSelf->ob_dict)
+ Py_CLEAR(sbkSelf->ob_dict);
+ return 0;
+}
+
+static PyTypeObject *createObjectType()
+{
+ PyType_Slot SbkObject_Type_slots[] = {
+ {Py_tp_getattro, reinterpret_cast<void *>(SbkObject_GenericGetAttr)},
+ {Py_tp_setattro, reinterpret_cast<void *>(SbkObject_GenericSetAttr)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(SbkDeallocWrapperWithPrivateDtor)},
+ {Py_tp_traverse, reinterpret_cast<void *>(SbkObject_tp_traverse)},
+ {Py_tp_clear, reinterpret_cast<void *>(SbkObject_tp_clear)},
+ // unsupported: {Py_tp_weaklistoffset, (void *)offsetof(SbkObject, weakreflist)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObject_tp_getset)},
+ // unsupported: {Py_tp_dictoffset, (void *)offsetof(SbkObject, ob_dict)},
+ {0, nullptr}
+ };
+
+ PyType_Spec SbkObject_Type_spec = {
+ "1:Shiboken.Object",
+ sizeof(SbkObject),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
+ SbkObject_Type_slots,
+ };
+
+ // PYSIDE-2230: When creating this type, we cannot easily handle the metaclass.
+ // In versions < Python 3.12, the metaclass can only be set
+ // indirectly by a base which has that metaclass.
+ // But before 3.12 is the minimum version, we cannot use the new
+ // function, although we would need this for 3.12 :-D
+ // We do a special patching here that is triggered through Py_None.
+ auto *type = SbkType_FromSpec_BMDWB(&SbkObject_Type_spec,
+ Py_None, // bases, spectial flag!
+ SbkObjectType_TypeF(),
+ offsetof(SbkObject, ob_dict),
+ offsetof(SbkObject, weakreflist),
+ nullptr); // bufferprocs
+ return type;
+}
+
+PyTypeObject *SbkObject_TypeF(void)
+{
+ static auto *type = createObjectType(); // bufferprocs
+ return type;
+}
+
+static const char *SbkObject_SignatureStrings[] = {
+ "Shiboken.Object(self)",
+ nullptr}; // Sentinel
+
+static int mainThreadDeletionHandler(void *)
+{
+ if (Py_IsInitialized())
+ Shiboken::BindingManager::instance().runDeletionInMainThread();
+ return 0;
+}
+
+static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete)
+{
+ auto *sbkObj = reinterpret_cast<SbkObject *>(pyObj);
+ PyTypeObject *pyType = Py_TYPE(pyObj);
+
+ // Need to decref the type if this is the dealloc func; if type
+ // is subclassed, that dealloc func will decref (see subtype_dealloc
+ // in typeobject.c in the python sources)
+ auto dealloc = PyType_GetSlot(pyType, Py_tp_dealloc);
+ bool needTypeDecref = dealloc == SbkDeallocWrapper
+ || dealloc == SbkDeallocWrapperWithPrivateDtor;
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Additional rule: Also when a subtype is heap allocated,
+ // then the subtype_dealloc deref will be suppressed, and we need again
+ // to supply a decref.
+ needTypeDecref |= (pyType->tp_base->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0;
+ }
+
+#if defined(__APPLE__)
+ // Just checking once that our assumptions are right.
+ if (false) {
+ void *p = PyType_GetSlot(pyType, Py_tp_dealloc);
+ Dl_info dl_info;
+ dladdr(p, &dl_info);
+ fprintf(stderr, "tp_dealloc is %s\n", dl_info.dli_sname);
+ }
+ // Gives one of our functions
+ // "Sbk_object_dealloc"
+ // "SbkDeallocWrapperWithPrivateDtor"
+ // "SbkDeallocQAppWrapper"
+ // "SbkDeallocWrapper"
+ // but for typedealloc_test.py we get
+ // "subtype_dealloc"
+#endif
+
+ // Ensure that the GC is no longer tracking this object to avoid a
+ // possible reentrancy problem. Since there are multiple steps involved
+ // in deallocating a SbkObject it is possible for the garbage collector to
+ // be invoked and it trying to delete this object while it is still in
+ // progress from the first time around, resulting in a double delete and a
+ // crash.
+ PyObject_GC_UnTrack(pyObj);
+
+ // Check that Python is still initialized as sometimes this is called by a static destructor
+ // after Python interpeter is shutdown.
+ if (sbkObj->weakreflist && Py_IsInitialized())
+ PyObject_ClearWeakRefs(pyObj);
+
+ // If I have ownership and is valid delete C++ pointer
+ auto *sotp = PepType_SOTP(pyType);
+ canDelete &= sbkObj->d->hasOwnership && sbkObj->d->validCppObject;
+ if (canDelete) {
+ if (sotp->delete_in_main_thread && Shiboken::currentThreadId() != Shiboken::mainThreadId()) {
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ if (sotp->is_multicpp) {
+ const auto entries = Shiboken::getDestructorEntries(sbkObj);
+ for (const auto &e : entries)
+ bindingManager.addToDeletionInMainThread(e);
+ } else {
+ Shiboken::DestructorEntry e{sotp->cpp_dtor, sbkObj->d->cptr[0]};
+ bindingManager.addToDeletionInMainThread(e);
+ }
+ Py_AddPendingCall(mainThreadDeletionHandler, nullptr);
+ canDelete = false;
+ }
+ }
+
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* Save the current exception, if any. */
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ if (canDelete) {
+ if (sotp->is_multicpp) {
+ const auto entries = Shiboken::getDestructorEntries(sbkObj);
+ Shiboken::Object::deallocData(sbkObj, true);
+ callDestructor(entries);
+ } else {
+ void *cptr = sbkObj->d->cptr[0];
+ Shiboken::Object::deallocData(sbkObj, true);
+
+ Shiboken::ThreadStateSaver threadSaver;
+ if (Py_IsInitialized())
+ threadSaver.save();
+ sotp->cpp_dtor(cptr);
+ }
+ } else {
+ Shiboken::Object::deallocData(sbkObj, true);
+ }
+
+ /* Restore the saved exception. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ if (needTypeDecref)
+ Py_DECREF(pyType);
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(pyType);
+ }
+}
+
+static inline PyObject *_Sbk_NewVarObject(PyTypeObject *type)
+{
+ // PYSIDE-1970: Support __slots__, implemented by PyVarObject
+ auto const baseSize = sizeof(SbkObject);
+ auto varCount = Py_SIZE(type);
+ auto *self = PyObject_GC_NewVar(PyObject, type, varCount);
+ if (varCount)
+ std::memset(reinterpret_cast<char *>(self) + baseSize, 0, varCount * sizeof(void *));
+ return self;
+}
+
+void SbkDeallocWrapper(PyObject *pyObj)
+{
+ SbkDeallocWrapperCommon(pyObj, true);
+}
+
+void SbkDeallocQAppWrapper(PyObject *pyObj)
+{
+ SbkDeallocWrapper(pyObj);
+ // PYSIDE-571: make sure to create a singleton deleted qApp.
+ Py_DECREF(MakeQAppWrapper(nullptr));
+}
+
+void SbkDeallocWrapperWithPrivateDtor(PyObject *self)
+{
+ SbkDeallocWrapperCommon(self, false);
+}
+
+void SbkObjectType_tp_dealloc(PyTypeObject *sbkType)
+{
+ SbkObjectTypePrivate *sotp = PepType_SOTP(sbkType);
+ auto pyObj = reinterpret_cast<PyObject *>(sbkType);
+
+ PyObject_GC_UnTrack(pyObj);
+#if !defined(Py_LIMITED_API) && !defined(PYPY_VERSION)
+# if PY_VERSION_HEX >= 0x030A0000
+ Py_TRASHCAN_BEGIN(pyObj, 1);
+# else
+ Py_TRASHCAN_SAFE_BEGIN(pyObj);
+# endif
+#endif
+ if (sotp) {
+ if (sotp->user_data && sotp->d_func) {
+ sotp->d_func(sotp->user_data);
+ sotp->user_data = nullptr;
+ }
+ free(sotp->original_name);
+ sotp->original_name = nullptr;
+ if (!Shiboken::ObjectType::isUserType(sbkType))
+ Shiboken::Conversions::deleteConverter(sotp->converter);
+ PepType_SOTP_delete(sbkType);
+ }
+#if !defined(Py_LIMITED_API) && !defined(PYPY_VERSION)
+# if PY_VERSION_HEX >= 0x030A0000
+ Py_TRASHCAN_END;
+# else
+ Py_TRASHCAN_SAFE_END(pyObj);
+# endif
+#endif
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(Py_TYPE(pyObj));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Support for the qApp macro.
+//
+// qApp is a macro in Qt5. In Python, we simulate that a little by a
+// variable that monitors Q*Application.instance().
+// This variable is also able to destroy the app by qApp.shutdown().
+//
+
+PyObject *MakeQAppWrapper(PyTypeObject *type)
+{
+ static PyObject *qApp_last = nullptr;
+
+ // protecting from multiple application instances
+ if (!(type == nullptr || qApp_last == Py_None)) {
+ const char *res_name = qApp_last != nullptr
+ ? PepType_GetNameStr(Py_TYPE(qApp_last)) : "<Unknown>";
+ const char *type_name = PepType_GetNameStr(type);
+ PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before"
+ " creating a new %s instance.", res_name, type_name);
+ return nullptr;
+ }
+
+ // monitoring the last application state
+ PyObject *qApp_curr = type != nullptr ? _Sbk_NewVarObject(type) : Py_None;
+ static PyObject *builtins = PyEval_GetBuiltins();
+ if (PyDict_SetItem(builtins, Shiboken::PyName::qApp(), qApp_curr) < 0)
+ return nullptr;
+ qApp_last = qApp_curr;
+ // Note: This Py_INCREF would normally be wrong because the qApp
+ // object already has a reference from PyObject_GC_New. But this is
+ // exactly the needed reference that keeps qApp alive from alone!
+ Py_INCREF(qApp_curr);
+ // PYSIDE-1470: As a side effect, the interactive "_" variable tends to
+ // create reference cycles. This is disturbing when trying
+ // to remove qApp with del.
+ // PYSIDE-1758: Since we moved to an explicit qApp.shutdown() call, we
+ // no longer initialize "_" with Py_None.
+ return qApp_curr;
+}
+
+static PyTypeObject *SbkObjectType_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ // Check if all bases are new style before calling type.tp_new
+ // Was causing gc assert errors in test_bug704.py when
+ // this check happened after creating the type object.
+ // Argument parsing take from type.tp_new code.
+
+ // PYSIDE-595: Also check if all bases allow inheritance.
+ // Before we changed to heap types, it was sufficient to remove the
+ // Py_TPFLAGS_BASETYPE flag. That does not work, because PySide does
+ // not respect this flag itself!
+ PyObject *name;
+ PyObject *pyBases;
+ PyObject *dict;
+ static const char *kwlist[] = { "name", "bases", "dict", nullptr};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!O!:sbktype", const_cast<char **>(kwlist),
+ &name,
+ &PyTuple_Type, &pyBases,
+ &PyDict_Type, &dict))
+ return nullptr;
+
+ for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) {
+ PyObject *baseType = PyTuple_GET_ITEM(pyBases, i);
+ if (PepExt_Type_GetNewSlot(reinterpret_cast<PyTypeObject *>(baseType)) == SbkDummyNew) {
+ // PYSIDE-595: A base class does not allow inheritance.
+ return reinterpret_cast<PyTypeObject *>(SbkDummyNew(metatype, args, kwds));
+ }
+ }
+
+ // PYSIDE-939: This is still a temporary patch that circumvents the problem
+ // with Py_TPFLAGS_METHOD_DESCRIPTOR. The problem exists in Python 3.8
+ // until 3.9.12, only. We check the runtime and hope for this version valishing.
+ // https://github.com/python/cpython/issues/92112 will not be fixed for 3.8 :/
+ PyTypeObject *newType{};
+ static auto triplet = _PepRuntimeVersion();
+ if (triplet >= (3 << 16 | 8 << 8 | 0) && triplet < (3 << 16 | 9 << 8 | 13)) {
+ auto hold = PyMethodDescr_Type.tp_flags;
+ PyMethodDescr_Type.tp_flags &= ~Py_TPFLAGS_METHOD_DESCRIPTOR;
+ newType = PepType_Type_tp_new(metatype, args, kwds);
+ PyMethodDescr_Type.tp_flags = hold;
+ } else {
+ newType = PepType_Type_tp_new(metatype, args, kwds);
+ }
+
+ if (!newType)
+ return nullptr;
+
+ SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
+
+ const auto bases = Shiboken::getCppBaseClasses(newType);
+ if (bases.size() == 1) {
+ SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front());
+ sotp->mi_offsets = parentType->mi_offsets;
+ sotp->mi_init = parentType->mi_init;
+ sotp->mi_specialcast = parentType->mi_specialcast;
+ sotp->type_discovery = parentType->type_discovery;
+ sotp->cpp_dtor = parentType->cpp_dtor;
+ sotp->is_multicpp = 0;
+ sotp->converter = parentType->converter;
+ } else {
+ sotp->mi_offsets = nullptr;
+ sotp->mi_init = nullptr;
+ sotp->mi_specialcast = nullptr;
+ sotp->type_discovery = nullptr;
+ sotp->cpp_dtor = nullptr;
+ sotp->is_multicpp = 1;
+ sotp->converter = nullptr;
+ }
+ if (bases.size() == 1) {
+ const char *original_name = PepType_SOTP(bases.front())->original_name;
+ if (original_name == nullptr)
+ original_name = "object";
+ sotp->original_name = strdup(original_name);
+ }
+ else
+ sotp->original_name = strdup("object");
+ sotp->user_data = nullptr;
+ sotp->d_func = nullptr;
+ sotp->is_user_type = 1;
+
+ // PYSIDE-1463: Prevent feature switching while in the creation process
+ auto saveFeature = initSelectableFeature(nullptr);
+ for (PyTypeObject *base : bases) {
+ sotp = PepType_SOTP(base);
+ if (sotp->subtype_init)
+ sotp->subtype_init(newType, args, kwds);
+ }
+ initSelectableFeature(saveFeature);
+ return newType;
+}
+
+static PyObject *_setupNew(PyObject *obSelf, PyTypeObject *subtype)
+{
+ auto *obSubtype = reinterpret_cast<PyObject *>(subtype);
+ auto *sbkSubtype = subtype;
+ auto *self = reinterpret_cast<SbkObject *>(obSelf);
+
+ Py_INCREF(obSubtype);
+ auto d = new SbkObjectPrivate;
+
+ auto *sotp = PepType_SOTP(sbkSubtype);
+ int numBases = ((sotp && sotp->is_multicpp) ?
+ Shiboken::getNumberOfCppBaseClasses(subtype) : 1);
+ d->cptr = new void *[numBases];
+ std::memset(d->cptr, 0, sizeof(void *) *size_t(numBases));
+ d->hasOwnership = 1;
+ d->containsCppWrapper = 0;
+ d->validCppObject = 0;
+ d->parentInfo = nullptr;
+ d->referredObjects = nullptr;
+ d->cppObjectCreated = 0;
+ d->isQAppSingleton = 0;
+ self->ob_dict = nullptr;
+ self->weakreflist = nullptr;
+ self->d = d;
+ PyObject_GC_Track(obSelf);
+ return obSelf;
+}
+
+PyObject *SbkObject_tp_new(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+{
+ PyObject *self = _Sbk_NewVarObject(subtype);
+ return _setupNew(self, subtype);
+}
+
+PyObject *SbkQApp_tp_new(PyTypeObject *subtype, PyObject *, PyObject *)
+{
+ auto *obSelf = MakeQAppWrapper(subtype);
+ auto *self = reinterpret_cast<SbkObject *>(obSelf);
+ if (self == nullptr)
+ return nullptr;
+ auto ret = _setupNew(obSelf, subtype);
+ auto priv = self->d;
+ priv->isQAppSingleton = 1;
+ return ret;
+}
+
+PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *)
+{
+ // PYSIDE-595: Give the same error as type_call does when tp_new is NULL.
+ const char regret[] = "¯\\_(ツ)_/¯";
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances %s", type->tp_name, regret);
+ return nullptr;
+}
+
+// PYSIDE-74: Fallback used in all types now.
+PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op)
+{
+ // This is a very simple implementation that supplies a simple identity.
+ static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="};
+ PyObject *res;
+
+ switch (op) {
+
+ case Py_EQ:
+ res = (self == other) ? Py_True : Py_False;
+ break;
+ case Py_NE:
+ res = (self != other) ? Py_True : Py_False;
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError,
+ "'%s' not supported between instances of '%.100s' and '%.100s'",
+ opstrings[op],
+ self->ob_type->tp_name,
+ other->ob_type->tp_name);
+ return nullptr;
+ }
+ Py_INCREF(res);
+ return res;
+}
+
+bool SbkObjectType_Check(PyTypeObject *type)
+{
+ static auto *meta = SbkObjectType_TypeF();
+ return Py_TYPE(type) == meta || PyType_IsSubtype(Py_TYPE(type), meta);
+}
+
+} //extern "C"
+
+
+namespace
+{
+
+void _destroyParentInfo(SbkObject *obj, bool keepReference)
+{
+ Shiboken::ParentInfo *pInfo = obj->d->parentInfo;
+ if (pInfo) {
+ while(!pInfo->children.empty()) {
+ SbkObject *first = *pInfo->children.begin();
+ // Mark child as invalid
+ Shiboken::Object::invalidate(first);
+ Shiboken::Object::removeParent(first, false, keepReference);
+ }
+ Shiboken::Object::removeParent(obj, false);
+ }
+}
+
+}
+
+namespace Shiboken
+{
+
+// Wrapper metatype and base type ----------------------------------------------------------
+
+void _initMainThreadId(); // helper.cpp
+
+static std::string msgFailedToInitializeType(const char *description)
+{
+ std::ostringstream stream;
+ stream << "[libshiboken] Failed to initialize " << description;
+ if (auto *error = PepErr_GetRaisedException()) {
+ if (auto *str = PyObject_Str(error))
+ stream << ": " << Shiboken::String::toCString(str);
+ Py_DECREF(error);
+ }
+ stream << '.';
+ return stream.str();
+}
+
+namespace Conversions { void init(); }
+
+void init()
+{
+ static bool shibokenAlreadInitialised = false;
+ if (shibokenAlreadInitialised)
+ return;
+
+ _initMainThreadId();
+
+ Conversions::init();
+
+ //Init private data
+ Pep384_Init();
+
+ auto *type = SbkObjectType_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapperType metatype").c_str());
+
+ type = SbkObject_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapper type").c_str());
+
+ VoidPtr::init();
+
+ shibokenAlreadInitialised = true;
+}
+
+// PYSIDE-1415: Publish Shiboken objects.
+// PYSIDE-1735: Initialize the whole Shiboken startup.
+void initShibokenSupport(PyObject *module)
+{
+ Py_INCREF(SbkObject_TypeF());
+ PyModule_AddObject(module, "Object", reinterpret_cast<PyObject *>(SbkObject_TypeF()));
+
+ // PYSIDE-1735: When the initialization was moved into Shiboken import, this
+ // Py_INCREF became necessary. No idea why.
+ Py_INCREF(module);
+ init_shibokensupport_module();
+
+ auto *type = SbkObject_TypeF();
+ if (InitSignatureStrings(type, SbkObject_SignatureStrings) < 0)
+ Py_FatalError("Error in initShibokenSupport");
+}
+
+// setErrorAboutWrongArguments now gets overload info from the signature module.
+// Info can be nullptr and contains extra info.
+void setErrorAboutWrongArguments(PyObject *args, const char *funcName, PyObject *info)
+{
+ SetError_Argument(args, funcName, info);
+}
+
+PyObject *returnWrongArguments(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return {};
+}
+
+int returnWrongArguments_Zero(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return 0;
+}
+
+int returnWrongArguments_MinusOne(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return -1;
+}
+
+PyObject *returnFromRichCompare(PyObject *result)
+{
+ if (result && !PyErr_Occurred())
+ return result;
+ Shiboken::Errors::setOperatorNotImplemented();
+ return {};
+}
+
+PyObject *checkInvalidArgumentCount(Py_ssize_t numArgs, Py_ssize_t minArgs, Py_ssize_t maxArgs)
+{
+ PyObject *result = nullptr;
+ // for seterror_argument(), signature/errorhandler.py
+ if (numArgs > maxArgs) {
+ static PyObject *const tooMany = Shiboken::String::createStaticString(">");
+ result = tooMany;
+ Py_INCREF(result);
+ } else if (numArgs < minArgs) {
+ static PyObject *const tooFew = Shiboken::String::createStaticString("<");
+ static PyObject *const noArgs = Shiboken::String::createStaticString("0");
+ result = numArgs > 0 ? tooFew : noArgs;
+ Py_INCREF(result);
+ }
+ return result;
+}
+
+std::vector<SbkObject *> splitPyObject(PyObject *pyObj)
+{
+ std::vector<SbkObject *> result;
+ if (PySequence_Check(pyObj)) {
+ AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object."));
+ if (!lst.isNull()) {
+ for (Py_ssize_t i = 0, i_max = PySequence_Fast_GET_SIZE(lst.object()); i < i_max; ++i) {
+ PyObject *item = PySequence_Fast_GET_ITEM(lst.object(), i);
+ if (Object::checkType(item))
+ result.push_back(reinterpret_cast<SbkObject *>(item));
+ }
+ }
+ } else {
+ result.push_back(reinterpret_cast<SbkObject *>(pyObj));
+ }
+ return result;
+}
+
+template <class Iterator>
+inline void decRefPyObjectList(Iterator i1, Iterator i2)
+{
+ for (; i1 != i2; ++i1)
+ Py_DECREF(i1->second);
+}
+
+namespace ObjectType
+{
+
+bool checkType(PyTypeObject *type)
+{
+ return PyType_IsSubtype(type, SbkObject_TypeF()) != 0;
+}
+
+bool isUserType(PyTypeObject *type)
+{
+ return checkType(type) && PepType_SOTP(type)->is_user_type;
+}
+
+bool canCallConstructor(PyTypeObject *myType, PyTypeObject *ctorType)
+{
+ auto findBasePred = [ctorType](PyTypeObject *type) { return type == ctorType; };
+ if (!walkThroughBases(myType, findBasePred)) {
+ PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name);
+ return false;
+ }
+ return true;
+}
+
+bool hasCast(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->mi_specialcast != nullptr;
+}
+
+void *cast(PyTypeObject *sourceType, SbkObject *obj, PyTypeObject *pyTargetType)
+{
+ auto *sotp = PepType_SOTP(sourceType);
+ return sotp->mi_specialcast(Object::cppPointer(obj, pyTargetType), pyTargetType);
+}
+
+void setCastFunction(PyTypeObject *type, SpecialCastFunction func)
+{
+ auto *sotp = PepType_SOTP(type);
+ sotp->mi_specialcast = func;
+}
+
+void setOriginalName(PyTypeObject *type, const char *name)
+{
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->original_name)
+ free(sotp->original_name);
+ sotp->original_name = strdup(name);
+}
+
+const char *getOriginalName(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->original_name;
+}
+
+void setTypeDiscoveryFunctionV2(PyTypeObject *type, TypeDiscoveryFuncV2 func)
+{
+ PepType_SOTP(type)->type_discovery = func;
+}
+
+void copyMultipleInheritance(PyTypeObject *type, PyTypeObject *other)
+{
+ auto *sotp_type = PepType_SOTP(type);
+ auto *sotp_other = PepType_SOTP(other);
+ sotp_type->mi_init = sotp_other->mi_init;
+ sotp_type->mi_offsets = sotp_other->mi_offsets;
+ sotp_type->mi_specialcast = sotp_other->mi_specialcast;
+}
+
+void setMultipleInheritanceFunction(PyTypeObject *type, MultipleInheritanceInitFunction function)
+{
+ PepType_SOTP(type)->mi_init = function;
+}
+
+MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->mi_init;
+}
+
+void setDestructorFunction(PyTypeObject *type, ObjectDestructor func)
+{
+ PepType_SOTP(type)->cpp_dtor = func;
+}
+
+PyTypeObject *
+introduceWrapperType(PyObject *enclosingObject,
+ const char *typeName,
+ const char *originalName,
+ PyType_Spec *typeSpec,
+ ObjectDestructor cppObjDtor,
+ PyObject *bases,
+ unsigned wrapperFlags)
+{
+ assert(PySequence_Fast_GET_SIZE(bases) > 0);
+ typeSpec->slots[0].pfunc = PySequence_Fast_GET_ITEM(bases, 0);
+
+ auto *type = SbkType_FromSpecBasesMeta(typeSpec, bases, SbkObjectType_TypeF());
+
+ auto sotp = PepType_SOTP(type);
+ if (wrapperFlags & DeleteInMainThread)
+ sotp->delete_in_main_thread = 1;
+ sotp->type_behaviour = (wrapperFlags & Value) != 0
+ ? BEHAVIOUR_VALUETYPE : BEHAVIOUR_OBJECTTYPE;
+
+ setOriginalName(type, originalName);
+ setDestructorFunction(type, cppObjDtor);
+ auto *ob_type = reinterpret_cast<PyObject *>(type);
+
+ if (wrapperFlags & InnerClass) {
+ // PYSIDE-2230: Instead of tp_dict, use the enclosing type.
+ // This stays interface compatible.
+ if (PyType_Check(enclosingObject)) {
+ AutoDecRef tpDict(PepType_GetDict(reinterpret_cast<PyTypeObject *>(enclosingObject)));
+ return PyDict_SetItemString(tpDict, typeName, ob_type) == 0 ? type : nullptr;
+ }
+ assert(PyDict_Check(enclosingObject));
+ return PyDict_SetItemString(enclosingObject, typeName, ob_type) == 0 ? type : nullptr;
+ }
+
+ // PyModule_AddObject steals type's reference.
+ Py_INCREF(ob_type);
+ if (PyModule_AddObject(enclosingObject, typeName, ob_type) != 0) {
+ std::cerr << "Warning: " << __FUNCTION__ << " returns nullptr for "
+ << typeName << '/' << originalName << " due to PyModule_AddObject(enclosingObject="
+ << enclosingObject << ", ob_type=" << ob_type << ") failing\n";
+ return nullptr;
+ }
+ return type;
+}
+
+void setSubTypeInitHook(PyTypeObject *type, SubTypeInitHook func)
+{
+ assert(SbkObjectType_Check(type));
+ PepType_SOTP(type)->subtype_init = func;
+}
+
+void *getTypeUserData(PyTypeObject *type)
+{
+ assert(SbkObjectType_Check(type));
+ return PepType_SOTP(type)->user_data;
+}
+
+void setTypeUserData(PyTypeObject *type, void *userData, DeleteUserDataFunc d_func)
+{
+ assert(SbkObjectType_Check(type));
+ auto *sotp = PepType_SOTP(type);
+ sotp->user_data = userData;
+ sotp->d_func = d_func;
+}
+
+// Try to find the exact type of cptr.
+PyTypeObject *typeForTypeName(const char *typeName)
+{
+ PyTypeObject *result{};
+ if (typeName) {
+ if (PyTypeObject *pyType = Shiboken::Conversions::getPythonTypeObject(typeName))
+ result = pyType;
+ }
+ return result;
+}
+
+bool hasSpecialCastFunction(PyTypeObject *sbkType)
+{
+ const auto *d = PepType_SOTP(sbkType);
+ return d != nullptr && d->mi_specialcast != nullptr;
+}
+
+// Find whether base is a direct single line base class of type
+// (no multiple inheritance), that is, a C++ pointer cast can safely be done.
+static bool isDirectAncestor(PyTypeObject *type, PyTypeObject *base)
+{
+ if (type == base)
+ return true;
+ if (PyTuple_Size(type->tp_bases) == 0)
+ return false;
+ auto *sbkObjectType = SbkObject_TypeF();
+ auto *firstBase = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, 0));
+ return firstBase != sbkObjectType
+ && PyType_IsSubtype(type, sbkObjectType) != 0
+ && isDirectAncestor(firstBase, base);
+}
+
+bool canDowncastTo(PyTypeObject *baseType, PyTypeObject *targetType)
+{
+ return isDirectAncestor(targetType, baseType);
+}
+
+} // namespace ObjectType
+
+
+namespace Object
+{
+
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *>& seen);
+
+bool checkType(PyObject *pyObj)
+{
+ return ObjectType::checkType(Py_TYPE(pyObj));
+}
+
+bool isUserType(PyObject *pyObj)
+{
+ return ObjectType::isUserType(Py_TYPE(pyObj));
+}
+
+Py_hash_t hash(PyObject *pyObj)
+{
+ assert(Shiboken::Object::checkType(pyObj));
+ return reinterpret_cast<Py_hash_t>(pyObj);
+}
+
+static void setSequenceOwnership(PyObject *pyObj, bool owner)
+{
+
+ bool has_length = true;
+
+ if (!pyObj)
+ return;
+
+ if (PySequence_Size(pyObj) < 0) {
+ PyErr_Clear();
+ has_length = false;
+ }
+
+ if (PySequence_Check(pyObj) && has_length) {
+ Py_ssize_t size = PySequence_Size(pyObj);
+ if (size > 0) {
+ const auto objs = splitPyObject(pyObj);
+ if (owner) {
+ for (SbkObject *o : objs)
+ getOwnership(o);
+ } else {
+ for (SbkObject *o : objs)
+ releaseOwnership(o);
+ }
+ }
+ } else if (Object::checkType(pyObj)) {
+ if (owner)
+ getOwnership(reinterpret_cast<SbkObject *>(pyObj));
+ else
+ releaseOwnership(reinterpret_cast<SbkObject *>(pyObj));
+ }
+}
+
+void setValidCpp(SbkObject *pyObj, bool value)
+{
+ pyObj->d->validCppObject = value;
+}
+
+void setHasCppWrapper(SbkObject *pyObj, bool value)
+{
+ pyObj->d->containsCppWrapper = value;
+}
+
+bool hasCppWrapper(SbkObject *pyObj)
+{
+ return pyObj->d->containsCppWrapper;
+}
+
+bool wasCreatedByPython(SbkObject *pyObj)
+{
+ return pyObj->d->cppObjectCreated;
+}
+
+void callCppDestructors(SbkObject *pyObj)
+{
+ auto priv = pyObj->d;
+ if (priv->isQAppSingleton && DestroyQApplication) {
+ // PYSIDE-1470: Allow to destroy the application from Shiboken.
+ DestroyQApplication();
+ return;
+ }
+ PyTypeObject *type = Py_TYPE(pyObj);
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->is_multicpp) {
+ callDestructor(getDestructorEntries(pyObj));
+ } else {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ sotp->cpp_dtor(pyObj->d->cptr[0]);
+ }
+
+ if (priv->validCppObject && priv->containsCppWrapper) {
+ BindingManager::instance().releaseWrapper(pyObj);
+ }
+
+ /* invalidate needs to be called before deleting pointer array because
+ it needs to delete entries for them from the BindingManager hash table;
+ also release wrapper explicitly if object contains C++ wrapper because
+ invalidate doesn't */
+ invalidate(pyObj);
+
+ delete[] priv->cptr;
+ priv->cptr = nullptr;
+ priv->validCppObject = false;
+}
+
+bool hasOwnership(SbkObject *pyObj)
+{
+ return pyObj->d->hasOwnership;
+}
+
+void getOwnership(SbkObject *self)
+{
+ // skip if already have the ownership
+ if (self->d->hasOwnership)
+ return;
+
+ // skip if this object has parent
+ if (self->d->parentInfo && self->d->parentInfo->parent)
+ return;
+
+ // Get back the ownership
+ self->d->hasOwnership = true;
+
+ if (self->d->containsCppWrapper)
+ Py_DECREF(reinterpret_cast<PyObject *>(self)); // Remove extra ref
+ else
+ makeValid(self); // Make the object valid again
+}
+
+void getOwnership(PyObject *pyObj)
+{
+ if (pyObj)
+ setSequenceOwnership(pyObj, true);
+}
+
+void releaseOwnership(SbkObject *self)
+{
+ // skip if the ownership have already moved to c++
+ auto *selfType = Py_TYPE(self);
+ if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(PepType_SOTP(selfType)->converter))
+ return;
+
+ // remove object ownership
+ self->d->hasOwnership = false;
+
+ // If We have control over object life
+ if (self->d->containsCppWrapper)
+ Py_INCREF(reinterpret_cast<PyObject *>(self)); // keep the python object alive until the wrapper destructor call
+ else
+ invalidate(self); // If I do not know when this object will die We need to invalidate this to avoid use after
+}
+
+void releaseOwnership(PyObject *self)
+{
+ setSequenceOwnership(self, false);
+}
+
+/* Needed forward declarations */
+static void recursive_invalidate(PyObject *pyobj, std::set<SbkObject *>& seen);
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *> &seen);
+
+void invalidate(PyObject *pyobj)
+{
+ std::set<SbkObject *> seen;
+ recursive_invalidate(pyobj, seen);
+}
+
+void invalidate(SbkObject *self)
+{
+ std::set<SbkObject *> seen;
+ recursive_invalidate(self, seen);
+}
+
+static void recursive_invalidate(PyObject *pyobj, std::set<SbkObject *> &seen)
+{
+ const auto objs = splitPyObject(pyobj);
+ for (SbkObject *o : objs)
+ recursive_invalidate(o, seen);
+}
+
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *> &seen)
+{
+ // Skip if this object not is a valid object or if it's already been seen
+ if (!self || reinterpret_cast<PyObject *>(self) == Py_None || seen.find(self) != seen.end())
+ return;
+ seen.insert(self);
+
+ if (!self->d->containsCppWrapper) {
+ self->d->validCppObject = false; // Mark object as invalid only if this is not a wrapper class
+ BindingManager::instance().releaseWrapper(self);
+ }
+
+ // If it is a parent invalidate all children.
+ if (self->d->parentInfo) {
+ // Create a copy because this list can be changed during the process
+ ChildrenList copy = self->d->parentInfo->children;
+
+ for (SbkObject *child : copy) {
+ // invalidate the child
+ recursive_invalidate(child, seen);
+
+ // if the parent not is a wrapper class, then remove children from him, because We do not know when this object will be destroyed
+ if (!self->d->validCppObject)
+ removeParent(child, true, true);
+ }
+ }
+
+ // If has ref to other objects invalidate all
+ if (self->d->referredObjects) {
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ recursive_invalidate(it->second, seen);
+ }
+}
+
+void makeValid(SbkObject *self)
+{
+ // Skip if this object not is a valid object
+ if (!self || reinterpret_cast<PyObject *>(self) == Py_None || self->d->validCppObject)
+ return;
+
+ // Mark object as invalid only if this is not a wrapper class
+ self->d->validCppObject = true;
+
+ // If it is a parent make all children valid
+ if (self->d->parentInfo) {
+ for (SbkObject *child : self->d->parentInfo->children)
+ makeValid(child);
+ }
+
+ // If has ref to other objects make all valid again
+ if (self->d->referredObjects) {
+ const RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (const auto &p : refCountMap) {
+ if (Shiboken::Object::checkType(p.second))
+ makeValid(reinterpret_cast<SbkObject *>(p.second));
+ }
+ }
+}
+
+void *cppPointer(SbkObject *pyObj, PyTypeObject *desiredType)
+{
+ PyTypeObject *pyType = Py_TYPE(pyObj);
+ auto *sotp = PepType_SOTP(pyType);
+ int idx = 0;
+ if (sotp->is_multicpp)
+ idx = getTypeIndexOnHierarchy(pyType, desiredType);
+ if (pyObj->d->cptr)
+ return pyObj->d->cptr[idx];
+ return nullptr;
+}
+
+std::vector<void *> cppPointers(SbkObject *pyObj)
+{
+ int n = getNumberOfCppBaseClasses(Py_TYPE(pyObj));
+ std::vector<void *> ptrs(n);
+ for (int i = 0; i < n; ++i)
+ ptrs[i] = pyObj->d->cptr[i];
+ return ptrs;
+}
+
+
+bool setCppPointer(SbkObject *sbkObj, PyTypeObject *desiredType, void *cptr)
+{
+ PyTypeObject *type = Py_TYPE(sbkObj);
+ int idx = 0;
+ if (PepType_SOTP(type)->is_multicpp)
+ idx = getTypeIndexOnHierarchy(type, desiredType);
+
+ const bool alreadyInitialized = sbkObj->d->cptr[idx] != nullptr;
+ if (alreadyInitialized)
+ PyErr_Format(PyExc_RuntimeError, "You can't initialize an %s object in class %s twice!",
+ desiredType->tp_name, type->tp_name);
+ else
+ sbkObj->d->cptr[idx] = cptr;
+
+ sbkObj->d->cppObjectCreated = true;
+ return !alreadyInitialized;
+}
+
+bool isValid(PyObject *pyObj)
+{
+ if (!pyObj || pyObj == Py_None
+ || PyType_Check(pyObj) != 0
+ || Py_TYPE(Py_TYPE(pyObj)) != SbkObjectType_TypeF()) {
+ return true;
+ }
+
+ auto priv = reinterpret_cast<SbkObject *>(pyObj)->d;
+
+ if (!priv->cppObjectCreated && isUserType(pyObj)) {
+ PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ if (!priv->validCppObject) {
+ PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ return true;
+}
+
+bool isValid(SbkObject *pyObj, bool throwPyError)
+{
+ if (!pyObj)
+ return false;
+
+ SbkObjectPrivate *priv = pyObj->d;
+ if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject *>(pyObj))) {
+ if (throwPyError)
+ PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ if (!priv->validCppObject) {
+ if (throwPyError)
+ PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.",
+ (Py_TYPE(pyObj))->tp_name);
+ return false;
+ }
+
+ return true;
+}
+
+bool isValid(PyObject *pyObj, bool throwPyError)
+{
+ if (!pyObj || pyObj == Py_None ||
+ !PyType_IsSubtype(Py_TYPE(pyObj), SbkObject_TypeF())) {
+ return true;
+ }
+ return isValid(reinterpret_cast<SbkObject *>(pyObj), throwPyError);
+}
+
+SbkObject *findColocatedChild(SbkObject *wrapper,
+ const PyTypeObject *instanceType)
+{
+ // Degenerate case, wrapper is the correct wrapper.
+ if (reinterpret_cast<const void *>(Py_TYPE(wrapper)) == reinterpret_cast<const void *>(instanceType))
+ return wrapper;
+
+ if (!(wrapper->d && wrapper->d->cptr))
+ return nullptr;
+
+ ParentInfo *pInfo = wrapper->d->parentInfo;
+ if (!pInfo)
+ return nullptr;
+
+ ChildrenList &children = pInfo->children;
+
+ for (SbkObject *child : children) {
+ if (!(child->d && child->d->cptr))
+ continue;
+ if (child->d->cptr[0] == wrapper->d->cptr[0]) {
+ return reinterpret_cast<const void *>(Py_TYPE(child)) == reinterpret_cast<const void *>(instanceType)
+ ? child : findColocatedChild(child, instanceType);
+ }
+ }
+ return nullptr;
+}
+
+// Legacy, for compatibility only.
+PyObject *newObject(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ bool isExactType,
+ const char *typeName)
+{
+ return isExactType
+ ? newObjectForType(instanceType, cptr, hasOwnership)
+ : newObjectWithHeuristics(instanceType, cptr, hasOwnership, typeName);
+}
+
+static PyObject *newObjectWithHeuristicsHelper(PyTypeObject *instanceType,
+ PyTypeObject *exactType,
+ void *cptr,
+ bool hasOwnership)
+{
+ // Try to find the exact type of cptr. For hierarchies with
+ // non-virtual destructors, typeid() will return the base name.
+ // Try type discovery in these cases.
+ if (exactType == nullptr || exactType == instanceType) {
+ auto resolved = BindingManager::instance().findDerivedType(cptr, instanceType);
+ if (resolved.first != nullptr
+ && Shiboken::ObjectType::canDowncastTo(instanceType, resolved.first)) {
+ exactType = resolved.first;
+ cptr = resolved.second;
+ }
+ }
+
+ return newObjectForType(exactType != nullptr ? exactType : instanceType,
+ cptr, hasOwnership);
+}
+
+PyObject *newObjectForPointer(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ const char *typeName)
+{
+ // Try to find the exact type of cptr.
+ PyTypeObject *exactType = ObjectType::typeForTypeName(typeName);
+ // PYSIDE-868: In case of multiple inheritance, (for example,
+ // a function returning a QPaintDevice * from a QWidget *),
+ // use instance type to avoid pointer offset errors.
+ return exactType != nullptr && !Shiboken::ObjectType::canDowncastTo(instanceType, exactType)
+ ? newObjectForType(instanceType, cptr, hasOwnership)
+ : newObjectWithHeuristicsHelper(instanceType, exactType, cptr, hasOwnership);
+}
+
+
+PyObject *newObjectWithHeuristics(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ const char *typeName)
+{
+ return newObjectWithHeuristicsHelper(instanceType,
+ ObjectType::typeForTypeName(typeName),
+ cptr, hasOwnership);
+}
+
+PyObject *newObjectForType(PyTypeObject *instanceType, void *cptr, bool hasOwnership)
+{
+ bool shouldCreate = true;
+ bool shouldRegister = true;
+ SbkObject *self = nullptr;
+
+ // Some logic to ensure that colocated child field does not overwrite the parent
+ if (BindingManager::instance().hasWrapper(cptr)) {
+ SbkObject *existingWrapper = BindingManager::instance().retrieveWrapper(cptr);
+
+ self = findColocatedChild(existingWrapper, instanceType);
+ if (self) {
+ // Wrapper already registered for cptr.
+ // This should not ideally happen, binding code should know when a wrapper
+ // already exists and retrieve it instead.
+ shouldRegister = shouldCreate = false;
+ } else if (hasOwnership &&
+ (!(Shiboken::Object::hasCppWrapper(existingWrapper) ||
+ Shiboken::Object::hasOwnership(existingWrapper)))) {
+ // Old wrapper is likely junk, since we have ownership and it doesn't.
+ BindingManager::instance().releaseWrapper(existingWrapper);
+ } else {
+ // Old wrapper may be junk caused by some bug in identifying object deletion
+ // but it may not be junk when a colocated field is accessed for an
+ // object which was not created by python (returned from c++ factory function).
+ // Hence we cannot release the wrapper confidently so we do not register.
+ shouldRegister = false;
+ }
+ }
+
+ if (shouldCreate) {
+ self = reinterpret_cast<SbkObject *>(SbkObject_tp_new(instanceType, nullptr, nullptr));
+ self->d->cptr[0] = cptr;
+ self->d->hasOwnership = hasOwnership;
+ self->d->validCppObject = 1;
+ if (shouldRegister) {
+ BindingManager::instance().registerWrapper(self, cptr);
+ }
+ } else {
+ Py_IncRef(reinterpret_cast<PyObject *>(self));
+ }
+ return reinterpret_cast<PyObject *>(self);
+}
+
+void destroy(SbkObject *self, void *cppData)
+{
+ // Skip if this is called with NULL pointer this can happen in derived classes
+ if (!self)
+ return;
+
+ // This can be called in c++ side
+ Shiboken::GilState gil;
+
+ // Remove all references attached to this object
+ clearReferences(self);
+
+ // Remove the object from parent control
+
+ // Verify if this object has parent
+ bool hasParent = (self->d->parentInfo && self->d->parentInfo->parent);
+
+ if (self->d->parentInfo) {
+ // Check for children information and make all invalid if they exists
+ _destroyParentInfo(self, true);
+ // If this object has parent then the pyobject can be invalid now, because we remove the last ref after remove from parent
+ }
+
+ //if !hasParent this object could still alive
+ if (!hasParent && self->d->containsCppWrapper && !self->d->hasOwnership) {
+ // Remove extra ref used by c++ object this will case the pyobject destruction
+ // This can cause the object death
+ Py_DECREF(reinterpret_cast<PyObject *>(self));
+ }
+
+ //Python Object is not destroyed yet
+ if (cppData && Shiboken::BindingManager::instance().hasWrapper(cppData)) {
+ // Remove from BindingManager
+ Shiboken::BindingManager::instance().releaseWrapper(self);
+ self->d->hasOwnership = false;
+
+ // the cpp object instance was deleted
+ delete[] self->d->cptr;
+ self->d->cptr = nullptr;
+ }
+
+ // After this point the object can be death do not use the self pointer bellow
+}
+
+void removeParent(SbkObject *child, bool giveOwnershipBack, bool keepReference)
+{
+ ParentInfo *pInfo = child->d->parentInfo;
+ if (!pInfo || !pInfo->parent) {
+ if (pInfo && pInfo->hasWrapperRef) {
+ pInfo->hasWrapperRef = false;
+ }
+ return;
+ }
+
+ ChildrenList &oldBrothers = pInfo->parent->d->parentInfo->children;
+ // Verify if this child is part of parent list
+ auto iChild = oldBrothers.find(child);
+ if (iChild == oldBrothers.end())
+ return;
+
+ oldBrothers.erase(iChild);
+
+ pInfo->parent = nullptr;
+
+ // This will keep the wrapper reference, will wait for wrapper destruction to remove that
+ if (keepReference &&
+ child->d->containsCppWrapper) {
+ //If have already a extra ref remove this one
+ if (pInfo->hasWrapperRef)
+ Py_DECREF(child);
+ else
+ pInfo->hasWrapperRef = true;
+ return;
+ }
+
+ // Transfer ownership back to Python
+ child->d->hasOwnership = giveOwnershipBack;
+
+ // Remove parent ref
+ Py_DECREF(child);
+}
+
+void setParent(PyObject *parent, PyObject *child)
+{
+ if (!child || child == Py_None || child == parent)
+ return;
+
+ /*
+ * setParent is recursive when the child is a native Python sequence, i.e. objects not binded by Shiboken
+ * like tuple and list.
+ *
+ * This "limitation" exists to fix the following problem: A class multiple inherits QObject and QString,
+ * so if you pass this class to someone that takes the ownership, we CAN'T enter in this if, but hey! QString
+ * follows the sequence protocol.
+ */
+ if (PySequence_Check(child) && !Object::checkType(child)) {
+ Shiboken::AutoDecRef seq(PySequence_Fast(child, nullptr));
+ for (Py_ssize_t i = 0, max = PySequence_Size(seq); i < max; ++i)
+ setParent(parent, PySequence_Fast_GET_ITEM(seq.object(), i));
+ return;
+ }
+
+ bool parentIsNull = !parent || parent == Py_None;
+ auto parent_ = reinterpret_cast<SbkObject *>(parent);
+ auto child_ = reinterpret_cast<SbkObject *>(child);
+
+ if (!parentIsNull) {
+ if (!parent_->d->parentInfo)
+ parent_->d->parentInfo = new ParentInfo;
+
+ // do not re-add a child
+ if (child_->d->parentInfo && (child_->d->parentInfo->parent == parent_))
+ return;
+ }
+
+ ParentInfo *pInfo = child_->d->parentInfo;
+ bool hasAnotherParent = pInfo && pInfo->parent && pInfo->parent != parent_;
+
+ //Avoid destroy child during reparent operation
+ Py_INCREF(child);
+
+ // check if we need to remove this child from the old parent
+ if (parentIsNull || hasAnotherParent)
+ removeParent(child_);
+
+ // Add the child to the new parent
+ pInfo = child_->d->parentInfo;
+ if (!parentIsNull) {
+ if (!pInfo)
+ pInfo = child_->d->parentInfo = new ParentInfo;
+
+ pInfo->parent = parent_;
+ parent_->d->parentInfo->children.insert(child_);
+
+ // Add Parent ref
+ Py_INCREF(child_);
+
+ // Remove ownership
+ child_->d->hasOwnership = false;
+ }
+
+ // Remove previous safe ref
+ Py_DECREF(child);
+}
+
+void deallocData(SbkObject *self, bool cleanup)
+{
+ // Make cleanup if this is not a wrapper otherwise this will be done on wrapper destructor
+ if(cleanup) {
+ removeParent(self);
+
+ if (self->d->parentInfo)
+ _destroyParentInfo(self, true);
+
+ clearReferences(self);
+ }
+
+ if (self->d->cptr) {
+ // Remove from BindingManager
+ Shiboken::BindingManager::instance().releaseWrapper(self);
+ delete[] self->d->cptr;
+ self->d->cptr = nullptr;
+ // delete self->d; PYSIDE-205: wrong!
+ }
+ delete self->d; // PYSIDE-205: always delete d.
+ Py_XDECREF(self->ob_dict);
+ PepExt_TypeCallFree(reinterpret_cast<PyObject *>(self));
+}
+
+void setTypeUserData(SbkObject *wrapper, void *userData, DeleteUserDataFunc d_func)
+{
+ auto *type = Py_TYPE(wrapper);
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->user_data)
+ sotp->d_func(sotp->user_data);
+
+ sotp->d_func = d_func;
+ sotp->user_data = userData;
+}
+
+void *getTypeUserData(SbkObject *wrapper)
+{
+ auto *type = Py_TYPE(wrapper);
+ return PepType_SOTP(type)->user_data;
+}
+
+static inline bool isNone(const PyObject *o)
+{
+ return o == nullptr || o == Py_None;
+}
+
+static void removeRefCountKey(SbkObject *self, const char *key)
+{
+ if (self->d->referredObjects) {
+ const auto iterPair = self->d->referredObjects->equal_range(key);
+ if (iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ self->d->referredObjects->erase(iterPair.first, iterPair.second);
+ }
+ }
+}
+
+void keepReference(SbkObject *self, const char *key, PyObject *referredObject, bool append)
+{
+ if (isNone(referredObject)) {
+ removeRefCountKey(self, key);
+ return;
+ }
+
+ if (!self->d->referredObjects) {
+ self->d->referredObjects =
+ new Shiboken::RefCountMap{RefCountMap::value_type{key, referredObject}};
+ Py_INCREF(referredObject);
+ return;
+ }
+
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ const auto iterPair = refCountMap.equal_range(key);
+ if (std::any_of(iterPair.first, iterPair.second,
+ [referredObject](const RefCountMap::value_type &v) { return v.second == referredObject; })) {
+ return;
+ }
+
+ if (!append && iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ refCountMap.erase(iterPair.first, iterPair.second);
+ }
+
+ refCountMap.insert(RefCountMap::value_type{key, referredObject});
+ Py_INCREF(referredObject);
+}
+
+void removeReference(SbkObject *self, const char *key, PyObject *referredObject)
+{
+ if (!isNone(referredObject))
+ removeRefCountKey(self, key);
+}
+
+void clearReferences(SbkObject *self)
+{
+ if (!self->d->referredObjects)
+ return;
+
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ Py_DECREF(it->second);
+ self->d->referredObjects->clear();
+}
+
+// Helpers for debug / info formatting
+
+static std::vector<PyTypeObject *> getBases(SbkObject *self)
+{
+ return ObjectType::isUserType(Py_TYPE(self))
+ ? getCppBaseClasses(Py_TYPE(self))
+ : std::vector<PyTypeObject *>(1, Py_TYPE(self));
+}
+
+static bool isValueType(SbkObject *self)
+{
+ return PepType_SOTP(Py_TYPE(self))->type_behaviour == BEHAVIOUR_VALUETYPE;
+}
+
+void _debugFormat(std::ostream &s, SbkObject *self)
+{
+ assert(self);
+ auto *d = self->d;
+ if (!d) {
+ s << "[Invalid]";
+ return;
+ }
+ if (d->cptr) {
+ const std::vector<PyTypeObject *> bases = getBases(self);
+ for (size_t i = 0, size = bases.size(); i < size; ++i)
+ s << ", C++: " << bases[i]->tp_name << '/' << self->d->cptr[i];
+ } else {
+ s << " [Deleted]";
+ }
+ if (d->hasOwnership)
+ s << " [hasOwnership]";
+ if (d->containsCppWrapper)
+ s << " [containsCppWrapper]";
+ if (d->validCppObject)
+ s << " [validCppObject]";
+ if (d->cppObjectCreated)
+ s << " [wasCreatedByPython]";
+ s << (isValueType(self) ? " [value]" : " [object]");
+
+ if (d->parentInfo) {
+ if (auto *parent = d->parentInfo->parent)
+ s << ", parent=" << reinterpret_cast<PyObject *>(parent)->ob_type->tp_name
+ << '/' << parent;
+ if (!d->parentInfo->children.empty())
+ s << ", " << d->parentInfo->children.size() << " child(ren)";
+ }
+ if (d->referredObjects && !d->referredObjects->empty())
+ s << ", " << d->referredObjects->size() << " referred object(s)";
+}
+
+std::string info(SbkObject *self)
+{
+ std::ostringstream s;
+
+ if (self->d && self->d->cptr) {
+ const std::vector<PyTypeObject *> bases = getBases(self);
+
+ s << "C++ address....... ";
+ for (size_t i = 0, size = bases.size(); i < size; ++i)
+ s << bases[i]->tp_name << '/' << self->d->cptr[i] << ' ';
+ s << "\n";
+ }
+ else {
+ s << "C++ address....... <<Deleted>>\n";
+ }
+
+ s << "hasOwnership...... " << bool(self->d->hasOwnership) << "\n"
+ "containsCppWrapper " << self->d->containsCppWrapper << "\n"
+ "validCppObject.... " << self->d->validCppObject << "\n"
+ "wasCreatedByPython " << self->d->cppObjectCreated << "\n"
+ "value...... " << isValueType(self) << "\n"
+ "reference count... " << reinterpret_cast<PyObject *>(self)->ob_refcnt << '\n';
+
+ if (self->d->parentInfo && self->d->parentInfo->parent) {
+ s << "parent............ ";
+ Shiboken::AutoDecRef parent(PyObject_Str(reinterpret_cast<PyObject *>(self->d->parentInfo->parent)));
+ s << String::toCString(parent) << "\n";
+ }
+
+ if (self->d->parentInfo && !self->d->parentInfo->children.empty()) {
+ s << "children.......... ";
+ for (SbkObject *sbkChild : self->d->parentInfo->children) {
+ Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(sbkChild)));
+ s << String::toCString(child) << ' ';
+ }
+ s << '\n';
+ }
+
+ if (self->d->referredObjects && !self->d->referredObjects->empty()) {
+ const Shiboken::RefCountMap &map = *self->d->referredObjects;
+ s << "referred objects.. ";
+ std::string lastKey;
+ for (const auto &p : map) {
+ if (p.first != lastKey) {
+ if (!lastKey.empty())
+ s << " ";
+ s << '"' << p.first << "\" => ";
+ lastKey = p.first;
+ }
+ Shiboken::AutoDecRef obj(PyObject_Str(p.second));
+ s << String::toCString(obj) << ' ';
+ }
+ s << '\n';
+ }
+ return s.str();
+}
+
+} // namespace Object
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
new file mode 100644
index 000000000..ec5545aea
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -0,0 +1,519 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BASEWRAPPER_H
+#define BASEWRAPPER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "sbktypefactory.h"
+
+#include <vector>
+#include <string>
+
+extern "C"
+{
+
+struct SbkConverter;
+struct SbkObjectPrivate;
+
+/// Base Python object for all the wrapped C++ classes.
+struct LIBSHIBOKEN_API SbkObject
+{
+ PyObject_HEAD
+ /// Instance dictionary.
+ PyObject *ob_dict;
+ /// List of weak references
+ PyObject *weakreflist;
+ SbkObjectPrivate *d;
+};
+
+
+/// PYSIDE-939: A general replacement for object_dealloc.
+LIBSHIBOKEN_API void Sbk_object_dealloc(PyObject *self);
+
+/// Dealloc the python object \p pyObj and the C++ object represented by it.
+LIBSHIBOKEN_API void SbkDeallocWrapper(PyObject *pyObj);
+LIBSHIBOKEN_API void SbkDeallocQAppWrapper(PyObject *pyObj);
+LIBSHIBOKEN_API void SbkDeallocWrapperWithPrivateDtor(PyObject *self);
+
+/// Function signature for the multiple inheritance information initializers that should be provided by classes with multiple inheritance.
+using MultipleInheritanceInitFunction = int *(*)(const void *);
+
+/**
+ * Special cast function is used to correctly cast an object when it's
+ * part of a multiple inheritance hierarchy.
+ * The implementation of this function is auto generated by the generator and you don't need to care about it.
+ */
+using SpecialCastFunction = void *(*)(void *, PyTypeObject *);
+using TypeDiscoveryFunc = PyTypeObject *(*)(void *, PyTypeObject *);
+using TypeDiscoveryFuncV2 = void *(*)(void *, PyTypeObject *);
+
+// Used in userdata dealloc function
+using DeleteUserDataFunc = void (*)(void *);
+
+using ObjectDestructor = void (*)(void *);
+
+using SubTypeInitHook = void (*)(PyTypeObject *, PyObject *, PyObject *);
+
+/// PYSIDE-1019: Set the function to select the current feature.
+/// Return value is the previous content.
+using SelectableFeatureHook = void (*)(PyTypeObject *);
+using SelectableFeatureCallback = void (*)(bool);
+LIBSHIBOKEN_API SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func);
+LIBSHIBOKEN_API void setSelectableFeatureCallback(SelectableFeatureCallback func);
+
+/// PYSIDE-1626: Enforcing a context switch without further action.
+LIBSHIBOKEN_API void SbkObjectType_UpdateFeature(PyTypeObject *type);
+
+/// PYSIDE-1019: Get access to PySide property strings.
+LIBSHIBOKEN_API const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type);
+LIBSHIBOKEN_API void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings);
+
+/// PYSIDE-1735: Store the enumFlagInfo.
+LIBSHIBOKEN_API void SbkObjectType_SetEnumFlagInfo(PyTypeObject *type, const char **strings);
+
+/// PYSIDE-1470: Set the function to kill a Q*Application.
+using DestroyQAppHook = void(*)();
+LIBSHIBOKEN_API void setDestroyQApplication(DestroyQAppHook func);
+
+/// PYSIDE-535: Use the C API in PyPy instead of `op->ob_dict`, directly (borrowed ref)
+LIBSHIBOKEN_API PyObject *SbkObject_GetDict_NoRef(PyObject *op);
+
+extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void);
+extern LIBSHIBOKEN_API PyTypeObject *SbkObject_TypeF(void);
+
+
+struct SbkObjectTypePrivate;
+/// PyTypeObject extended with C++ multiple inheritance information.
+
+LIBSHIBOKEN_API PyObject *SbkObject_tp_new(PyTypeObject *subtype, PyObject *, PyObject *);
+
+/// The special case of a switchable singleton Q*Application.
+LIBSHIBOKEN_API PyObject *SbkQApp_tp_new(PyTypeObject *subtype, PyObject *, PyObject *);
+
+/// Create a new Q*Application wrapper and monitor it.
+LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
+
+/**
+ * PYSIDE-832: Use object_dealloc instead of nullptr.
+ *
+ * When moving to heaptypes, we were struck by a special default behavior of
+ * PyType_FromSpec that inserts subtype_dealloc when tp_dealloc is
+ * nullptr. But the default before conversion to heaptypes was to assign
+ * object_dealloc. This seems to be a bug in the Limited API.
+ */
+/// PYSIDE-939: Replaced by Sbk_object_dealloc.
+LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *);
+
+/// PYSIDE-74: Fallback used in all types now.
+LIBSHIBOKEN_API PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op);
+
+/// PYSIDE-1970: Be easily able to see what is happening in the running code.
+LIBSHIBOKEN_API void disassembleFrame(const char *marker);
+
+/// PYSIDE-2230: Check if an object is an SbkObject.
+LIBSHIBOKEN_API bool SbkObjectType_Check(PyTypeObject *type);
+
+} // extern "C"
+
+namespace Shiboken
+{
+
+/**
+* Init shiboken library.
+*/
+LIBSHIBOKEN_API void init();
+
+/// PYSIDE-1415: Publish Shiboken objects.
+LIBSHIBOKEN_API void initShibokenSupport(PyObject *module);
+
+/// Delete the class T allocated on \p cptr.
+template<typename T>
+void callCppDestructor(void *cptr)
+{
+ delete reinterpret_cast<T *>(cptr);
+}
+
+/// setErrorAboutWrongArguments now gets overload information from the signature module.
+/// The extra info argument can contain additional data about the error.
+LIBSHIBOKEN_API void setErrorAboutWrongArguments(PyObject *args, const char *funcName,
+ PyObject *info);
+
+/// Return values for the different retun variants.
+/// This is used instead of goto.
+LIBSHIBOKEN_API PyObject *returnWrongArguments(PyObject *args, const char *funcName,
+ PyObject *info);
+
+LIBSHIBOKEN_API int returnWrongArguments_Zero(PyObject *args, const char *funcName,
+ PyObject *info);
+
+LIBSHIBOKEN_API int returnWrongArguments_MinusOne(PyObject *args, const char *funcName,
+ PyObject *info);
+
+/// A simple special version for the end of rich comparison.
+LIBSHIBOKEN_API PyObject *returnFromRichCompare(PyObject *result);
+
+// Return error information object if the argument count is wrong
+LIBSHIBOKEN_API PyObject *checkInvalidArgumentCount(Py_ssize_t numArgs,
+ Py_ssize_t minArgs,
+ Py_ssize_t maxArgs);
+
+namespace ObjectType {
+
+/**
+* Returns true if the object is an instance of a type created by the Shiboken generator.
+*/
+LIBSHIBOKEN_API bool checkType(PyTypeObject *pyObj);
+
+/**
+* Returns true if this object is an instance of an user defined type derived from an Shiboken type.
+*/
+LIBSHIBOKEN_API bool isUserType(PyTypeObject *pyObj);
+
+/**
+* Returns true if the constructor of \p ctorType can be called for a instance of type \p myType.
+* \note This function set a python error when returning false.
+*/
+LIBSHIBOKEN_API bool canCallConstructor(PyTypeObject *myType, PyTypeObject *ctorType);
+
+/**
+ * Tells if the \p type represents an object of a class with multiple inheritance in C++.
+ * When this occurs, the C++ pointer held by the Python wrapper will need to be cast when
+ * passed as a parameter that expects a type of its ancestry.
+ * \returns true if a call to ObjectType::cast() is needed to obtain the correct
+ * C++ pointer for Python objects of type \p type.
+ */
+LIBSHIBOKEN_API bool hasCast(PyTypeObject *type);
+/**
+ * Cast the C++ pointer held by a Python object \p obj of type \p sourceType,
+ * to a C++ pointer of a C++ class indicated by type \p targetType.
+ * \returns The cast C++ pointer.
+ */
+LIBSHIBOKEN_API void *cast(PyTypeObject *sourceType, SbkObject *obj, PyTypeObject *targetType);
+/// Set the C++ cast function for \p type.
+LIBSHIBOKEN_API void setCastFunction(PyTypeObject *type, SpecialCastFunction func);
+
+LIBSHIBOKEN_API void setOriginalName(PyTypeObject *self, const char *name);
+LIBSHIBOKEN_API const char *getOriginalName(PyTypeObject *self);
+
+LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(PyTypeObject *self, TypeDiscoveryFuncV2 func);
+LIBSHIBOKEN_API void copyMultipleInheritance(PyTypeObject *self, PyTypeObject *other);
+LIBSHIBOKEN_API void setMultipleInheritanceFunction(PyTypeObject *self, MultipleInheritanceInitFunction func);
+LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *type);
+
+LIBSHIBOKEN_API void setDestructorFunction(PyTypeObject *self, ObjectDestructor func);
+
+enum WrapperFlags
+{
+ InnerClass = 0x1,
+ DeleteInMainThread = 0x2,
+ Value = 0x4
+};
+
+/**
+ * Initializes a Shiboken wrapper type and adds it to the module,
+ * or to the enclosing class if the type is an inner class.
+ * This function also calls setDestructorFunction.
+ * \param enclosingObject The module or enclosing class to where the new \p type will be added.
+ * \param typeName Name by which the type will be known in Python.
+ * \param originalName Original C++ name of the type.
+ * \param type The new type to be initialized and added to the module.
+ * \param cppObjDtor Memory deallocation function for the C++ object held by \p type.
+ * Should not be used if the underlying C++ class has a private destructor.
+ * \param baseType Base type from whom the new \p type inherits.
+ * \param baseTypes Other base types from whom the new \p type inherits.
+ * \param isInnerClass Tells if the new \p type is an inner class (the default is that it isn't).
+ * If false then the \p enclosingObject is a module, otherwise it is another
+ * wrapper type.
+ * \returns true if the initialization went fine, false otherwise.
+ */
+LIBSHIBOKEN_API PyTypeObject *introduceWrapperType(PyObject *enclosingObject,
+ const char *typeName,
+ const char *originalName,
+ PyType_Spec *typeSpec,
+ ObjectDestructor cppObjDtor,
+ PyObject *bases,
+ unsigned wrapperFlags = 0);
+
+/**
+ * Set the subtype init hook for a type.
+ *
+ * This hook will be invoked every time the user creates a sub-type inherited from a Shiboken based type.
+ * The hook gets 3 params, they are: The new type being created, args and kwds. The last two are the very
+ * same got from tp_new.
+ */
+LIBSHIBOKEN_API void setSubTypeInitHook(PyTypeObject *self, SubTypeInitHook func);
+
+/**
+ * Get the user data previously set by Shiboken::Object::setTypeUserData
+ */
+LIBSHIBOKEN_API void *getTypeUserData(PyTypeObject *self);
+LIBSHIBOKEN_API void setTypeUserData(PyTypeObject *self, void *userData, DeleteUserDataFunc d_func);
+
+/**
+ * Return an instance of PyTypeObject for a C++ type name as determined by
+ * typeinfo().name().
+ * \param typeName Type name
+ * \since 5.12
+ */
+LIBSHIBOKEN_API PyTypeObject *typeForTypeName(const char *typeName);
+
+/**
+ * Returns whether PyTypeObject has a special cast function (multiple inheritance)
+ * \param sbkType Sbk type
+ * \since 5.12
+ */
+LIBSHIBOKEN_API bool hasSpecialCastFunction(PyTypeObject *sbkType);
+
+/// Returns whether a C++ pointer of \p baseType can be safely downcast
+/// to \p targetType (base is a direct, single line base class of targetType).
+/// (is a direct, single-line inheritance)
+/// \param baseType Python type of base class
+/// \param targetType Python type of derived class
+/// \since 6.8
+LIBSHIBOKEN_API bool canDowncastTo(PyTypeObject *baseType, PyTypeObject *targetType);
+}
+
+namespace Object {
+
+/**
+ * Returns a string with information about the internal state of the instance object, useful for debug purposes.
+ */
+LIBSHIBOKEN_API std::string info(SbkObject *self);
+
+/**
+* Returns true if the object is an instance of a type created by the Shiboken generator.
+*/
+LIBSHIBOKEN_API bool checkType(PyObject *pyObj);
+
+/**
+ * Returns true if this object type is an instance of an user defined type derived from an Shiboken type.
+ * \see Shiboken::ObjectType::isUserType
+ */
+LIBSHIBOKEN_API bool isUserType(PyObject *pyObj);
+
+/**
+ * Generic function used to make ObjectType hashable, the C++ pointer is used as hash value.
+ */
+LIBSHIBOKEN_API Py_hash_t hash(PyObject *pyObj);
+
+/**
+ * Find a child of given wrapper having same address having the specified type.
+ */
+LIBSHIBOKEN_API SbkObject *findColocatedChild(SbkObject *wrapper,
+ const PyTypeObject *instanceType);
+
+/**
+ * Bind a C++ object to Python. Forwards to
+ * newObjectWithHeuristics(), newObjectForType() depending on \p isExactType.
+ * \param instanceType equivalent Python type for the C++ object.
+ * \param hasOwnership if true, Python will try to delete the underlying C++ object when there's no more refs.
+ * \param isExactType if false, Shiboken will use some heuristics to detect the correct Python type of this C++
+ * object, in any case you must provide \p instanceType, it'll be used as search starting point
+ * and as fallback.
+ * \param typeName If non-null, this will be used as helper to find the correct Python type for this object.
+ */
+LIBSHIBOKEN_API PyObject *newObject(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ bool isExactType = false,
+ const char *typeName = nullptr);
+
+/// Bind a C++ object to Python for polymorphic pointers. Calls
+/// newObjectWithHeuristics() with an additional check for multiple
+/// inheritance, in which case it will fall back to instanceType.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying C++ object
+/// when there's no more refs.
+/// \param typeName If non-null, this will be used as helper to find the correct
+/// Python type for this object (obtained by typeid().name().
+LIBSHIBOKEN_API PyObject *newObjectForPointer(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ const char *typeName = nullptr);
+
+/// Bind a C++ object to Python using some heuristics to detect the correct
+/// Python type of this C++ object. In any case \p instanceType must be provided;
+/// it'll be used as search starting point and as fallback.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying C++ object
+/// C++ object when there are no more references.
+/// when there's no more refs.
+/// \param typeName If non-null, this will be used as helper to find the correct
+/// Python type for this object (obtained by typeid().name().
+LIBSHIBOKEN_API PyObject *newObjectWithHeuristics(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ const char *typeName = nullptr);
+
+/// Bind a C++ object to Python using the given type.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying
+/// C++ object when there are no more references.
+LIBSHIBOKEN_API PyObject *newObjectForType(PyTypeObject *instanceType,
+ void *cptr, bool hasOwnership = true);
+
+/**
+ * Changes the valid flag of a PyObject, invalid objects will raise an exception when someone tries to access it.
+ */
+LIBSHIBOKEN_API void setValidCpp(SbkObject *pyObj, bool value);
+/**
+ * Tells shiboken the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls.
+ */
+LIBSHIBOKEN_API void setHasCppWrapper(SbkObject *pyObj, bool value);
+/**
+ * Return true if the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls.
+ */
+LIBSHIBOKEN_API bool hasCppWrapper(SbkObject *pyObj);
+
+/**
+ * Return true if the Python object was created by Python, false otherwise.
+ * \note This function was added to libshiboken only to be used by shiboken.wasCreatedByPython()
+ */
+LIBSHIBOKEN_API bool wasCreatedByPython(SbkObject *pyObj);
+
+/**
+ * Call the C++ object destructor and invalidates the Python object.
+ * \note This function was added to libshiboken only to be used by shiboken.delete()
+ */
+LIBSHIBOKEN_API void callCppDestructors(SbkObject *pyObj);
+
+/**
+ * Return true if the Python is responsible for deleting the underlying C++ object.
+ */
+LIBSHIBOKEN_API bool hasOwnership(SbkObject *pyObj);
+
+/**
+ * Sets python as responsible to delete the underlying C++ object.
+ * \note You this overload only when the PyObject can be a sequence and you want to
+ * call this function for every item in the sequence.
+ * \see getOwnership(SbkObject *)
+ */
+LIBSHIBOKEN_API void getOwnership(PyObject *pyObj);
+
+/**
+ * Sets python as responsible to delete the underlying C++ object.
+ */
+LIBSHIBOKEN_API void getOwnership(SbkObject *pyObj);
+
+/**
+ * Release the ownership, so Python will not delete the underlying C++ object.
+ * \note You this overload only when the PyObject can be a sequence and you want to
+ * call this function for every item in the sequence.
+ * \see releaseOwnership(SbkObject *)
+ */
+LIBSHIBOKEN_API void releaseOwnership(PyObject *pyObj);
+/**
+ * Release the ownership, so Python will not delete the underlying C++ object.
+ */
+LIBSHIBOKEN_API void releaseOwnership(SbkObject *pyObj);
+
+/**
+ * Get the C++ pointer of type \p desiredType from a Python object.
+ */
+LIBSHIBOKEN_API void *cppPointer(SbkObject *pyObj, PyTypeObject *desiredType);
+
+/**
+ * Return a list with all C++ pointers held from a Python object.
+ * \note This function was added to libshiboken only to be used by shiboken.getCppPointer()
+ */
+LIBSHIBOKEN_API std::vector<void *>cppPointers(SbkObject *pyObj);
+
+/**
+ * Set the C++ pointer of type \p desiredType of a Python object.
+ */
+LIBSHIBOKEN_API bool setCppPointer(SbkObject *sbkObj, PyTypeObject *desiredType, void *cptr);
+
+/**
+ * Returns false and sets a Python RuntimeError if the Python wrapper is not marked as valid.
+ */
+LIBSHIBOKEN_API bool isValid(PyObject *pyObj);
+
+/**
+ * Returns false if the Python wrapper is not marked as valid.
+ * \param pyObj the object.
+ * \param throwPyError sets a Python RuntimeError when the object isn't valid.
+ */
+LIBSHIBOKEN_API bool isValid(SbkObject *pyObj, bool throwPyError = true);
+
+/**
+ * Returns false if the Python wrapper is not marked as valid.
+ * \param pyObj the object.
+ * \param throwPyError sets a Python RuntimeError when the object isn't valid.
+ */
+LIBSHIBOKEN_API bool isValid(PyObject *pyObj, bool throwPyError);
+
+/**
+* Set the parent of \p child to \p parent.
+* When an object dies, all their children, grandchildren, etc, are tagged as invalid.
+* \param parent the parent object, if null, the child will have no parents.
+* \param child the child.
+*/
+LIBSHIBOKEN_API void setParent(PyObject *parent, PyObject *child);
+
+/**
+* Remove this child from their parent, if any.
+* \param child the child.
+*/
+LIBSHIBOKEN_API void removeParent(SbkObject *child, bool giveOwnershipBack = true, bool keepReferenc = false);
+
+/**
+ * Mark the object as invalid
+ */
+LIBSHIBOKEN_API void invalidate(SbkObject *self);
+
+/**
+ * Help function can be used to invalidate a sequence of object
+ **/
+LIBSHIBOKEN_API void invalidate(PyObject *pyobj);
+
+/**
+ * Make the object valid again
+ */
+LIBSHIBOKEN_API void makeValid(SbkObject *self);
+
+/**
+ * Destroy any data in Shiboken structure and c++ pointer if the pyboject has the ownership
+ */
+LIBSHIBOKEN_API void destroy(SbkObject *self, void *cppData);
+
+/**
+ * Set user data on type of \p wrapper.
+ * \param wrapper instance object, the user data will be set on his type
+ * \param userData the user data
+ * \param d_func a function used to delete the user data
+ */
+LIBSHIBOKEN_API void setTypeUserData(SbkObject *wrapper, void *userData, DeleteUserDataFunc d_func);
+/**
+ * Get the user data previously set by Shiboken::Object::setTypeUserData
+ */
+LIBSHIBOKEN_API void *getTypeUserData(SbkObject *wrapper);
+
+/**
+ * Increments the reference count of the referred Python object.
+ * A previous Python object in the same position identified by the 'key' parameter
+ * will have its reference counter decremented automatically when replaced.
+ * All the kept references should be decremented when the Python wrapper indicated by
+ * 'self' dies.
+ * No checking is done for any of the passed arguments, since it is meant to be used
+ * by generated code it is supposed that the generator is correct.
+ * \param self the wrapper instance that keeps references to other objects.
+ * \param key a key that identifies the C++ method signature and argument where the referred Object came from.
+ * \param referredObject the object whose reference is used by the self object.
+ */
+LIBSHIBOKEN_API void keepReference(SbkObject *self, const char *key, PyObject *referredObject, bool append = false);
+
+/**
+ * Removes any reference previously added by keepReference function
+ * \param self the wrapper instance that keeps references to other objects.
+ * \param key a key that identifies the C++ method signature and argument from where the referred Object came.
+ * \param referredObject the object whose reference is used by the self object.
+ */
+LIBSHIBOKEN_API void removeReference(SbkObject *self, const char *key, PyObject *referredObject);
+
+} // namespace Object
+
+} // namespace Shiboken
+
+#endif // BASEWRAPPER_H
diff --git a/sources/shiboken6/libshiboken/basewrapper_p.h b/sources/shiboken6/libshiboken/basewrapper_p.h
new file mode 100644
index 000000000..fb9140793
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper_p.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BASEWRAPPER_P_H
+#define BASEWRAPPER_P_H
+
+#include "sbkpython.h"
+#include "basewrapper.h"
+
+#include <unordered_map>
+#include <set>
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+struct SbkObject;
+struct SbkConverter;
+
+namespace Shiboken
+{
+/**
+ * This mapping associates a method and argument of an wrapper object with the wrapper of
+ * said argument when it needs the binding to help manage its reference count.
+ */
+using RefCountMap = std::unordered_multimap<std::string, PyObject *> ;
+
+/// Linked list of SbkBaseWrapper pointers
+using ChildrenList = std::set<SbkObject *>;
+
+/// Structure used to store information about object parent and children.
+struct ParentInfo
+{
+ /// Pointer to parent object.
+ SbkObject *parent = nullptr;
+ /// List of object children.
+ ChildrenList children;
+ /// has internal ref
+ bool hasWrapperRef = false;
+};
+
+} // namespace Shiboken
+
+extern "C"
+{
+
+/**
+ * \internal
+ * Private data for SbkBaseWrapper
+ */
+struct SbkObjectPrivate
+{
+ SbkObjectPrivate() noexcept = default;
+ SbkObjectPrivate(const SbkObjectPrivate &) = delete;
+ SbkObjectPrivate(SbkObjectPrivate &&o) = delete;
+ SbkObjectPrivate &operator=(const SbkObjectPrivate &) = delete;
+ SbkObjectPrivate &operator=(SbkObjectPrivate &&o) = delete;
+
+ /// Pointer to the C++ class.
+ void ** cptr;
+ /// True when Python is responsible for freeing the used memory.
+ unsigned int hasOwnership : 1;
+ /// This is true when the C++ class of the wrapped object has a virtual destructor AND was created by Python.
+ unsigned int containsCppWrapper : 1;
+ /// Marked as false when the object is lost to C++ and the binding can not know if it was deleted or not.
+ unsigned int validCppObject : 1;
+ /// Marked as true when the object constructor was called
+ unsigned int cppObjectCreated : 1;
+ /// PYSIDE-1470: Marked as true if this is the Q*Application singleton.
+ /// This bit allows app deletion from shiboken?.delete() .
+ unsigned int isQAppSingleton : 1;
+ /// Information about the object parents and children, may be null.
+ Shiboken::ParentInfo *parentInfo;
+ /// Manage reference count of objects that are referred to but not owned from.
+ Shiboken::RefCountMap *referredObjects;
+
+ ~SbkObjectPrivate()
+ {
+ delete parentInfo;
+ parentInfo = nullptr;
+ delete referredObjects;
+ referredObjects = nullptr;
+ }
+};
+
+// TODO-CONVERTERS: to be deprecated/removed
+/// The type behaviour was not defined yet
+#define BEHAVIOUR_UNDEFINED 0
+/// The type is a value type
+#define BEHAVIOUR_VALUETYPE 1
+/// The type is an object type
+#define BEHAVIOUR_OBJECTTYPE 2
+
+struct SbkObjectTypePrivate
+{
+ SbkConverter *converter;
+ int *mi_offsets;
+ MultipleInheritanceInitFunction mi_init;
+
+ /// Special cast function, null if this class doesn't have multiple inheritance.
+ SpecialCastFunction mi_specialcast;
+ TypeDiscoveryFuncV2 type_discovery;
+ /// Pointer to a function responsible for deletion of the C++ instance calling the proper destructor.
+ ObjectDestructor cpp_dtor;
+ /// C++ name
+ char *original_name;
+ /// Type user data
+ void *user_data;
+ DeleteUserDataFunc d_func;
+ void (*subtype_init)(PyTypeObject *, PyObject *, PyObject *);
+ const char **propertyStrings;
+ const char **enumFlagInfo;
+ PyObject *enumFlagsDict;
+ PyObject *enumTypeDict;
+
+ /// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes.
+ unsigned int is_multicpp : 1;
+ /// True if this type was defined by the user (a class written in Python inheriting
+ /// a class provided by a Shiboken binding).
+ unsigned int is_user_type : 1;
+ /// Tells is the type is a value type or an object-type, see BEHAVIOUR_ *constants.
+ unsigned int type_behaviour : 2;
+ unsigned int delete_in_main_thread : 1;
+};
+
+
+} // extern "C"
+
+namespace Shiboken
+{
+
+/**
+ * \internal
+ * Data required to invoke a C++ destructor
+ */
+struct DestructorEntry
+{
+ ObjectDestructor destructor;
+ void *cppInstance;
+};
+
+/**
+ * Utility function used to transform a PyObject that implements sequence protocol into a std::list.
+ **/
+std::vector<SbkObject *> splitPyObject(PyObject *pyObj);
+
+int getNumberOfCppBaseClasses(PyTypeObject *baseType);
+
+namespace Object
+{
+/**
+* Decrements the reference counters of every object referred by self.
+* \param self the wrapper instance that keeps references to other objects.
+*/
+void clearReferences(SbkObject *self);
+
+/**
+ * Destroy internal data
+ **/
+void deallocData(SbkObject *self, bool doCleanup);
+
+
+void _debugFormat(std::ostream &str, SbkObject *self);
+} // namespace Object
+
+} // namespace Shiboken
+
+#endif
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
new file mode 100644
index 000000000..83c927ae5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -0,0 +1,549 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "autodecref.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+#include "helper.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkfeature_base.h"
+#include "debugfreehook.h"
+
+#include <cstddef>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <mutex>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+
+// GraphNode for the dependency graph. It keeps a pointer to
+// the TypeInitStruct to be able to lazily create the type and hashes
+// by the full type name.
+struct GraphNode
+{
+ explicit GraphNode(Shiboken::Module::TypeInitStruct *i) : name(i->fullName), initStruct(i) {}
+ explicit GraphNode(const char *n) : name(n), initStruct(nullptr) {} // Only for searching
+
+ std::string_view name;
+ Shiboken::Module::TypeInitStruct *initStruct;
+
+ friend bool operator==(const GraphNode &n1, const GraphNode &n2) { return n1.name == n2.name; }
+ friend bool operator!=(const GraphNode &n1, const GraphNode &n2) { return n1.name != n2.name; }
+};
+
+template <>
+struct std::hash<GraphNode> {
+ size_t operator()(const GraphNode &n) const noexcept
+ {
+ return std::hash<std::string_view>{}(n.name);
+ }
+};
+
+namespace Shiboken
+{
+
+using WrapperMap = std::unordered_map<const void *, SbkObject *>;
+
+template <class NodeType>
+class BaseGraph
+{
+public:
+ using NodeList = std::vector<NodeType>;
+ using NodeSet = std::unordered_set<NodeType>;
+
+ using Edges = std::unordered_map<NodeType, NodeList>;
+
+ Edges m_edges;
+
+ BaseGraph() = default;
+
+ void addEdge(NodeType from, NodeType to)
+ {
+ m_edges[from].push_back(to);
+ }
+
+ NodeSet nodeSet() const
+ {
+ NodeSet result;
+ for (const auto &p : m_edges) {
+ result.insert(p.first);
+ for (const auto node2 : p.second)
+ result.insert(node2);
+ }
+ return result;
+ }
+};
+
+class Graph : public BaseGraph<GraphNode>
+{
+public:
+ using TypeCptrPair = BindingManager::TypeCptrPair;
+
+ TypeCptrPair identifyType(void *cptr, PyTypeObject *type, PyTypeObject *baseType) const
+ {
+ return identifyType(cptr, GraphNode(type->tp_name), type, baseType);
+ }
+
+ bool dumpTypeGraph(const char *fileName) const;
+
+private:
+ TypeCptrPair identifyType(void *cptr, const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const;
+};
+
+Graph::TypeCptrPair Graph::identifyType(void *cptr,
+ const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const
+{
+ assert(typeNode.initStruct != nullptr || type != nullptr);
+ auto edgesIt = m_edges.find(typeNode);
+ if (edgesIt != m_edges.end()) {
+ const NodeList &adjNodes = edgesIt->second;
+ for (const auto &node : adjNodes) {
+ auto newType = identifyType(cptr, node, nullptr, baseType);
+ if (newType.first != nullptr)
+ return newType;
+ }
+ }
+
+ if (type == nullptr) {
+ if (typeNode.initStruct->type == nullptr) // Layzily create type
+ type = Shiboken::Module::get(*typeNode.initStruct);
+ else
+ type = typeNode.initStruct->type;
+ }
+
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->type_discovery != nullptr) {
+ if (void *derivedCPtr = sotp->type_discovery(cptr, baseType))
+ return {type, derivedCPtr};
+ }
+ return {nullptr, nullptr};
+}
+
+static void formatDotNode(std::string_view name, std::ostream &file)
+{
+ auto lastDot = name.rfind('.');
+ file << " \"" << name << "\" [ label=";
+ if (lastDot != std::string::npos) {
+ file << '"' << name.substr(lastDot + 1) << "\" tooltip=\""
+ << name.substr(0, lastDot) << '"';
+ } else {
+ file << '"' << name << '"';
+ }
+ file << " ]\n";
+}
+
+bool Graph::dumpTypeGraph(const char *fileName) const
+{
+ std::ofstream file(fileName);
+ if (!file.good())
+ return false;
+
+ file << "digraph D {\n";
+
+ // Define nodes with short names
+ for (const auto &node : nodeSet())
+ formatDotNode(node.name, file);
+
+ // Write edges
+ for (const auto &p : m_edges) {
+ const auto &node1 = p.first;
+ const NodeList &nodeList = p.second;
+ for (const auto &node2 : nodeList)
+ file << " \"" << node2.name << "\" -> \"" << node1.name << "\"\n";
+ }
+ file << "}\n";
+ return true;
+}
+
+struct BindingManager::BindingManagerPrivate {
+ using DestructorEntries = std::vector<DestructorEntry>;
+
+ WrapperMap wrapperMapper;
+ // Guard wrapperMapper mainly for QML which calls into the generated
+ // QObject::metaObject() and elsewhere from threads without GIL, causing
+ // crashes for example in retrieveWrapper(). std::shared_mutex was rejected due to:
+ // https://stackoverflow.com/questions/50972345/when-is-stdshared-timed-mutex-slower-than-stdmutex-and-when-not-to-use-it
+ std::recursive_mutex wrapperMapLock;
+ Graph classHierarchy;
+ DestructorEntries deleteInMainThread;
+
+ bool releaseWrapper(void *cptr, SbkObject *wrapper, const int *bases = nullptr);
+ bool releaseWrapperHelper(void *cptr, SbkObject *wrapper);
+
+ void assignWrapper(SbkObject *wrapper, const void *cptr, const int *bases = nullptr);
+ void assignWrapperHelper(SbkObject *wrapper, const void *cptr);
+};
+
+inline bool BindingManager::BindingManagerPrivate::releaseWrapperHelper(void *cptr, SbkObject *wrapper)
+{
+ // The wrapper argument is checked to ensure that the correct wrapper is released.
+ // Returns true if the correct wrapper is found and released.
+ // If wrapper argument is NULL, no such check is performed.
+ auto iter = wrapperMapper.find(cptr);
+ if (iter != wrapperMapper.end() && (wrapper == nullptr || iter->second == wrapper)) {
+ wrapperMapper.erase(iter);
+ return true;
+ }
+ return false;
+}
+
+bool BindingManager::BindingManagerPrivate::releaseWrapper(void *cptr, SbkObject *wrapper,
+ const int *bases)
+{
+ assert(cptr);
+ std::lock_guard<std::recursive_mutex> guard(wrapperMapLock);
+ const bool result = releaseWrapperHelper(cptr, wrapper);
+ if (bases != nullptr) {
+ auto *base = static_cast<uint8_t *>(cptr);
+ for (const auto *offset = bases; *offset != -1; ++offset)
+ releaseWrapperHelper(base + *offset, wrapper);
+ }
+ return result;
+}
+
+inline void BindingManager::BindingManagerPrivate::assignWrapperHelper(SbkObject *wrapper,
+ const void *cptr)
+{
+ auto iter = wrapperMapper.find(cptr);
+ if (iter == wrapperMapper.end())
+ wrapperMapper.insert(std::make_pair(cptr, wrapper));
+}
+
+void BindingManager::BindingManagerPrivate::assignWrapper(SbkObject *wrapper, const void *cptr,
+ const int *bases)
+{
+ assert(cptr);
+ std::lock_guard<std::recursive_mutex> guard(wrapperMapLock);
+ assignWrapperHelper(wrapper, cptr);
+ if (bases != nullptr) {
+ const auto *base = static_cast<const uint8_t *>(cptr);
+ for (const auto *offset = bases; *offset != -1; ++offset)
+ assignWrapperHelper(wrapper, base + *offset);
+ }
+}
+
+BindingManager::BindingManager()
+{
+ m_d = new BindingManager::BindingManagerPrivate;
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+ debugInstallFreeHook();
+#endif
+}
+
+BindingManager::~BindingManager()
+{
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+ debugRemoveFreeHook();
+#endif
+#ifndef NDEBUG
+ if (Shiboken::pyVerbose() > 0)
+ dumpWrapperMap();
+#endif
+ /* Cleanup hanging references. We just invalidate them as when
+ * the BindingManager is being destroyed the interpreter is alredy
+ * shutting down. */
+ if (Py_IsInitialized()) { // ensure the interpreter is still valid
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ while (!m_d->wrapperMapper.empty()) {
+ Object::destroy(m_d->wrapperMapper.begin()->second, const_cast<void *>(m_d->wrapperMapper.begin()->first));
+ }
+ assert(m_d->wrapperMapper.empty());
+ }
+ delete m_d;
+}
+
+BindingManager &BindingManager::instance() {
+ static BindingManager singleton;
+ return singleton;
+}
+
+bool BindingManager::hasWrapper(const void *cptr)
+{
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ return m_d->wrapperMapper.find(cptr) != m_d->wrapperMapper.end();
+}
+
+void BindingManager::registerWrapper(SbkObject *pyObj, void *cptr)
+{
+ auto *instanceType = Py_TYPE(pyObj);
+ auto *d = PepType_SOTP(instanceType);
+
+ if (!d)
+ return;
+
+ if (d->mi_init && !d->mi_offsets)
+ d->mi_offsets = d->mi_init(cptr);
+ m_d->assignWrapper(pyObj, cptr, d->mi_offsets);
+}
+
+void BindingManager::releaseWrapper(SbkObject *sbkObj)
+{
+ auto *sbkType = Py_TYPE(sbkObj);
+ auto *d = PepType_SOTP(sbkType);
+ int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1);
+
+ void ** cptrs = reinterpret_cast<SbkObject *>(sbkObj)->d->cptr;
+ const int *mi_offsets = d != nullptr ? d->mi_offsets : nullptr;
+ for (int i = 0; i < numBases; ++i) {
+ if (cptrs[i] != nullptr)
+ m_d->releaseWrapper(cptrs[i], sbkObj, mi_offsets);
+ }
+ sbkObj->d->validCppObject = false;
+}
+
+void BindingManager::runDeletionInMainThread()
+{
+ for (const DestructorEntry &e : m_d->deleteInMainThread)
+ e.destructor(e.cppInstance);
+ m_d->deleteInMainThread.clear();
+}
+
+void BindingManager::addToDeletionInMainThread(const DestructorEntry &e)
+{
+ m_d->deleteInMainThread.push_back(e);
+}
+
+SbkObject *BindingManager::retrieveWrapper(const void *cptr)
+{
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ auto iter = m_d->wrapperMapper.find(cptr);
+ if (iter == m_d->wrapperMapper.end())
+ return nullptr;
+ return iter->second;
+}
+
+PyObject *BindingManager::getOverride(const void *cptr,
+ PyObject *nameCache[],
+ const char *methodName)
+{
+ SbkObject *wrapper = retrieveWrapper(cptr);
+ // The refcount can be 0 if the object is dieing and someone called
+ // a virtual method from the destructor
+ if (!wrapper || Py_REFCNT(reinterpret_cast<const PyObject *>(wrapper)) == 0)
+ return nullptr;
+
+ // PYSIDE-1626: Touch the type to initiate switching early.
+ SbkObjectType_UpdateFeature(Py_TYPE(wrapper));
+
+ int flag = currentSelectId(Py_TYPE(wrapper));
+ int propFlag = isdigit(methodName[0]) ? methodName[0] - '0' : 0;
+ bool is_snake = flag & 0x01;
+ PyObject *pyMethodName = nameCache[is_snake]; // borrowed
+ if (pyMethodName == nullptr) {
+ if (propFlag)
+ methodName += 2; // skip the propFlag and ':'
+ pyMethodName = Shiboken::String::getSnakeCaseName(methodName, is_snake);
+ nameCache[is_snake] = pyMethodName;
+ }
+
+ auto *obWrapper = reinterpret_cast<PyObject *>(wrapper);
+ auto *wrapper_dict = SbkObject_GetDict_NoRef(obWrapper);
+ if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
+ // Note: This special case was implemented for duck-punching, which happens
+ // in the instance dict. It does not work with properties.
+ Py_INCREF(method);
+ return method;
+ }
+
+ PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName);
+
+ PyObject *function = nullptr;
+
+ // PYSIDE-1523: PyMethod_Check is not accepting compiled methods, we do this rather
+ // crude check for them.
+ if (method) {
+ // PYSIDE-535: This macro is redefined in a compatible way in pep384
+ if (PyMethod_Check(method)) {
+ if (PyMethod_GET_SELF(method) == reinterpret_cast<PyObject *>(wrapper)) {
+ function = PyMethod_GET_FUNCTION(method);
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ } else if (PyObject_HasAttr(method, PyName::im_self())
+ && PyObject_HasAttr(method, PyName::im_func())
+ && PyObject_HasAttr(method, Shiboken::PyMagicName::code())) {
+ PyObject *im_self = PyObject_GetAttr(method, PyName::im_self());
+ // Not retaining a reference inline with what PyMethod_GET_SELF does.
+ Py_DECREF(im_self);
+
+ if (im_self == reinterpret_cast<PyObject *>(wrapper)) {
+ function = PyObject_GetAttr(method, PyName::im_func());
+ // Not retaining a reference inline with what PyMethod_GET_FUNCTION does.
+ Py_DECREF(function);
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ }
+
+ if (method != nullptr) {
+ PyObject *defaultMethod{};
+ PyObject *mro = Py_TYPE(wrapper)->tp_mro;
+
+ int size = PyTuple_GET_SIZE(mro);
+ bool defaultFound = false;
+ // The first class in the mro (index 0) is the class being checked and it should not be tested.
+ // The last class in the mro (size - 1) is the base Python object class which should not be tested also.
+ for (int idx = 1; idx < size - 1; ++idx) {
+ auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ AutoDecRef tpDict(PepType_GetDict(parent));
+ auto *parentDict = tpDict.object();
+ if (parentDict) {
+ defaultMethod = PyDict_GetItem(parentDict, pyMethodName);
+ if (defaultMethod) {
+ defaultFound = true;
+ if (function != defaultMethod)
+ return method;
+ }
+ }
+ }
+ // PYSIDE-2255: If no default method was found, use the method.
+ if (!defaultFound)
+ return method;
+ Py_DECREF(method);
+ }
+
+ return nullptr;
+}
+
+void BindingManager::addClassInheritance(Module::TypeInitStruct *parent,
+ Module::TypeInitStruct *child)
+{
+ m_d->classHierarchy.addEdge(GraphNode(parent), GraphNode(child));
+}
+
+BindingManager::TypeCptrPair BindingManager::findDerivedType(void *cptr, PyTypeObject *type) const
+{
+ return m_d->classHierarchy.identifyType(cptr, type, type);
+}
+
+// FIXME PYSIDE7: remove, just for compatibility
+PyTypeObject *BindingManager::resolveType(void **cptr, PyTypeObject *type)
+{
+ auto result = findDerivedType(*cptr, type);
+ if (result.second != nullptr)
+ *cptr = result.second;
+ return result.first != nullptr ? result.first : type;
+}
+
+std::set<PyObject *> BindingManager::getAllPyObjects()
+{
+ std::set<PyObject *> pyObjects;
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ const WrapperMap &wrappersMap = m_d->wrapperMapper;
+ auto it = wrappersMap.begin();
+ for (; it != wrappersMap.end(); ++it)
+ pyObjects.insert(reinterpret_cast<PyObject *>(it->second));
+
+ return pyObjects;
+}
+
+void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data)
+{
+ WrapperMap copy = m_d->wrapperMapper;
+ for (const auto &p : copy) {
+ if (hasWrapper(p.first))
+ visitor(p.second, data);
+ }
+}
+
+bool BindingManager::dumpTypeGraph(const char *fileName) const
+{
+ return m_d->classHierarchy.dumpTypeGraph(fileName);
+}
+
+void BindingManager::dumpWrapperMap()
+{
+ const auto &wrapperMap = m_d->wrapperMapper;
+ std::cerr << "-------------------------------\n"
+ << "WrapperMap size: " << wrapperMap.size() << " Types: "
+ << m_d->classHierarchy.nodeSet().size() << '\n';
+ for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+ const SbkObject *sbkObj = it->second;
+ std::cerr << "key: " << it->first << ", value: "
+ << static_cast<const void *>(sbkObj) << " ("
+ << (Py_TYPE(sbkObj))->tp_name << ", refcnt: "
+ << Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)) << ")\n";
+ }
+ std::cerr << "-------------------------------\n";
+}
+
+static bool isPythonType(PyTypeObject *type)
+{
+ // This is a type which should be called by multiple inheritance.
+ // It is either a pure Python type or a derived PySide type.
+ return !ObjectType::checkType(type) || ObjectType::isUserType(type);
+}
+
+bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
+ const char *fullName)
+{
+ using Shiboken::AutoDecRef;
+
+ static PyObject *const _init = String::createStaticString("__init__");
+ static PyObject *objectInit =
+ PyObject_GetAttr(reinterpret_cast<PyObject *>(&PyBaseObject_Type), _init);
+
+ // A native C++ self cannot have multiple inheritance.
+ if (!Object::isUserType(self))
+ return false;
+
+ auto *startType = Py_TYPE(self);
+ auto *mro = startType->tp_mro;
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ auto classNameLen = std::strrchr(fullName, '.') - fullName;
+ /* No need to check the last one: it's gonna be skipped anyway. */
+ for (idx = 0; idx + 1 < n; ++idx) {
+ auto *lookType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ const char *lookName = lookType->tp_name;
+ auto lookLen = long(std::strlen(lookName));
+ if (std::strncmp(lookName, fullName, classNameLen) == 0 && lookLen == classNameLen)
+ break;
+ }
+ // We are now at the first non-Python class `QObject`.
+ // mro: ('C', 'A', 'QObject', 'Object', 'B', 'object')
+ // We want to catch class `B` and call its `__init__`.
+ for (idx += 1; idx + 1 < n; ++idx) {
+ auto *t = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (isPythonType(t))
+ break;
+ }
+ if (idx >= n)
+ return false;
+
+ auto *obSubType = PyTuple_GET_ITEM(mro, idx);
+ auto *subType = reinterpret_cast<PyTypeObject *>(obSubType);
+ if (subType == &PyBaseObject_Type)
+ return false;
+ AutoDecRef func(PyObject_GetAttr(obSubType, _init));
+ // PYSIDE-2654: If this has no implementation then we get object.__init__
+ // but that is the same case like above.
+ if (func == objectInit)
+ return false;
+ // PYSIDE-2294: We need to explicitly ignore positional args in a mixin class.
+ SBK_UNUSED(args);
+ AutoDecRef newArgs(PyTuple_New(1));
+ auto *newArgsOb = newArgs.object();
+ Py_INCREF(self);
+ PyTuple_SET_ITEM(newArgsOb, 0, self);
+ // Note: This can fail, so please always check the error status.
+ AutoDecRef result(PyObject_Call(func, newArgs, kwds));
+ return true;
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/bindingmanager.h b/sources/shiboken6/libshiboken/bindingmanager.h
new file mode 100644
index 000000000..54c4e486a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bindingmanager.h
@@ -0,0 +1,93 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BINDINGMANAGER_H
+#define BINDINGMANAGER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+#include <set>
+#include <utility>
+
+struct SbkObject;
+
+namespace Shiboken
+{
+
+namespace Module {
+struct TypeInitStruct;
+}
+
+struct DestructorEntry;
+
+using ObjectVisitor = void (*)(SbkObject *, void *);
+
+class LIBSHIBOKEN_API BindingManager
+{
+public:
+ BindingManager(const BindingManager &) = delete;
+ BindingManager(BindingManager &&) = delete;
+ BindingManager &operator=(const BindingManager &) = delete;
+ BindingManager &operator=(BindingManager &&) = delete;
+
+ static BindingManager &instance();
+
+ bool hasWrapper(const void *cptr);
+
+ void registerWrapper(SbkObject *pyObj, void *cptr);
+ void releaseWrapper(SbkObject *wrapper);
+
+ void runDeletionInMainThread();
+ void addToDeletionInMainThread(const DestructorEntry &);
+
+ SbkObject *retrieveWrapper(const void *cptr);
+ PyObject *getOverride(const void *cptr, PyObject *nameCache[], const char *methodName);
+
+ void addClassInheritance(Module::TypeInitStruct *parent, Module::TypeInitStruct *child);
+ /// Try to find the correct type of cptr via type discovery knowing that it's at least
+ /// of type \p type. If a derived class is found, it returns a cptr cast to the type
+ /// (which may be different in case of multiple inheritance.
+ /// \param cptr a pointer to the instance of type \p type
+ /// \param type type of cptr
+ using TypeCptrPair = std::pair<PyTypeObject *, void *>;
+ TypeCptrPair findDerivedType(void *cptr, PyTypeObject *type) const;
+
+ /**
+ * Try to find the correct type of *cptr knowing that it's at least of type \p type.
+ * In case of multiple inheritance this function may change the contents of cptr.
+ * \param cptr a pointer to a pointer to the instance of type \p type
+ * \param type type of *cptr
+ * \warning This function is slow, use it only as last resort.
+ */
+ [[deprecated]] PyTypeObject *resolveType(void **cptr, PyTypeObject *type);
+
+ std::set<PyObject *> getAllPyObjects();
+
+ /**
+ * Calls the function \p visitor for each object registered on binding manager.
+ * \note As various C++ pointers can point to the same PyObject due to multiple inheritance
+ * a PyObject can be called more than one time for each PyObject.
+ * \param visitor function called for each object.
+ * \param data user data passed as second argument to the visitor function.
+ */
+ void visitAllPyObjects(ObjectVisitor visitor, void *data);
+
+ bool dumpTypeGraph(const char *fileName) const;
+ void dumpWrapperMap();
+
+private:
+ ~BindingManager();
+ BindingManager();
+
+ struct BindingManagerPrivate;
+ BindingManagerPrivate *m_d;
+};
+
+LIBSHIBOKEN_API bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
+ const char *fullName);
+
+} // namespace Shiboken
+
+#endif // BINDINGMANAGER_H
+
diff --git a/sources/shiboken6/libshiboken/bufferprocs_py37.cpp b/sources/shiboken6/libshiboken/bufferprocs_py37.cpp
new file mode 100644
index 000000000..4ccf970e5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bufferprocs_py37.cpp
@@ -0,0 +1,360 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*****************************************************************************
+ *
+ * Copied from abstract.c
+ *
+ * Py_buffer has been replaced by Pep_buffer
+ *
+ */
+
+#ifdef Py_LIMITED_API
+
+#include "sbkpython.h"
+/* Buffer C-API for Python 3.0 */
+
+int
+PyObject_GetBuffer(PyObject *obj, Pep_buffer *view, int flags)
+{
+ PyBufferProcs *pb = PepType_AS_BUFFER(Py_TYPE(obj));
+
+ if (pb == NULL || pb->bf_getbuffer == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "a bytes-like object is required, not '%.100s'",
+ Py_TYPE(obj)->tp_name);
+ return -1;
+ }
+ return (*pb->bf_getbuffer)(obj, view, flags);
+}
+
+static int
+_IsFortranContiguous(const Pep_buffer *view)
+{
+ Py_ssize_t sd, dim;
+ int i;
+
+ /* 1) len = product(shape) * itemsize
+ 2) itemsize > 0
+ 3) len = 0 <==> exists i: shape[i] = 0 */
+ if (view->len == 0) return 1;
+ if (view->strides == NULL) { /* C-contiguous by definition */
+ /* Trivially F-contiguous */
+ if (view->ndim <= 1) return 1;
+
+ /* ndim > 1 implies shape != NULL */
+ assert(view->shape != NULL);
+
+ /* Effectively 1-d */
+ sd = 0;
+ for (i=0; i<view->ndim; i++) {
+ if (view->shape[i] > 1) sd += 1;
+ }
+ return sd <= 1;
+ }
+
+ /* strides != NULL implies both of these */
+ assert(view->ndim > 0);
+ assert(view->shape != NULL);
+
+ sd = view->itemsize;
+ for (i=0; i<view->ndim; i++) {
+ dim = view->shape[i];
+ if (dim > 1 && view->strides[i] != sd) {
+ return 0;
+ }
+ sd *= dim;
+ }
+ return 1;
+}
+
+static int
+_IsCContiguous(const Pep_buffer *view)
+{
+ Py_ssize_t sd, dim;
+ int i;
+
+ /* 1) len = product(shape) * itemsize
+ 2) itemsize > 0
+ 3) len = 0 <==> exists i: shape[i] = 0 */
+ if (view->len == 0) return 1;
+ if (view->strides == NULL) return 1; /* C-contiguous by definition */
+
+ /* strides != NULL implies both of these */
+ assert(view->ndim > 0);
+ assert(view->shape != NULL);
+
+ sd = view->itemsize;
+ for (i=view->ndim-1; i>=0; i--) {
+ dim = view->shape[i];
+ if (dim > 1 && view->strides[i] != sd) {
+ return 0;
+ }
+ sd *= dim;
+ }
+ return 1;
+}
+
+int
+PyBuffer_IsContiguous(const Pep_buffer *view, char order)
+{
+
+ if (view->suboffsets != NULL) return 0;
+
+ if (order == 'C')
+ return _IsCContiguous(view);
+ else if (order == 'F')
+ return _IsFortranContiguous(view);
+ else if (order == 'A')
+ return (_IsCContiguous(view) || _IsFortranContiguous(view));
+ return 0;
+}
+
+
+void *
+PyBuffer_GetPointer(Pep_buffer *view, Py_ssize_t *indices)
+{
+ int i;
+ auto pointer = reinterpret_cast<char *>(view->buf);
+ for (i = 0; i < view->ndim; i++) {
+ pointer += view->strides[i]*indices[i];
+ if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
+ pointer = *reinterpret_cast<char **>(pointer) + view->suboffsets[i];
+ }
+ }
+ return pointer;
+}
+
+
+void
+_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
+{
+ int k;
+
+ for (k=0; k<nd; k++) {
+ if (index[k] < shape[k]-1) {
+ index[k]++;
+ break;
+ }
+ else {
+ index[k] = 0;
+ }
+ }
+}
+
+void
+_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
+{
+ int k;
+
+ for (k=nd-1; k>=0; k--) {
+ if (index[k] < shape[k]-1) {
+ index[k]++;
+ break;
+ }
+ else {
+ index[k] = 0;
+ }
+ }
+}
+
+int
+PyBuffer_FromContiguous(Pep_buffer *view, void *buf, Py_ssize_t len, char fort)
+{
+ int k;
+ void (*addone)(int, Py_ssize_t *, const Py_ssize_t *);
+ Py_ssize_t *indices, elements;
+ char *src, *ptr;
+
+ if (len > view->len) {
+ len = view->len;
+ }
+
+ if (PyBuffer_IsContiguous(view, fort)) {
+ /* simplest copy is all that is needed */
+ memcpy(view->buf, buf, len);
+ return 0;
+ }
+
+ /* Otherwise a more elaborate scheme is needed */
+
+ /* view->ndim <= 64 */
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
+ if (indices == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ for (k=0; k<view->ndim; k++) {
+ indices[k] = 0;
+ }
+
+ if (fort == 'F') {
+ addone = _Py_add_one_to_index_F;
+ }
+ else {
+ addone = _Py_add_one_to_index_C;
+ }
+ src = (char *)buf; // patched by CT
+ /* XXX : This is not going to be the fastest code in the world
+ several optimizations are possible.
+ */
+ elements = len / view->itemsize;
+ while (elements--) {
+ ptr = (char *)PyBuffer_GetPointer(view, indices); // patched by CT
+ memcpy(ptr, src, view->itemsize);
+ src += view->itemsize;
+ addone(view->ndim, indices, view->shape);
+ }
+
+ PyMem_Free(indices);
+ return 0;
+}
+
+int PyObject_CopyData(PyObject *dest, PyObject *src)
+{
+ Pep_buffer view_dest, view_src;
+ int k;
+ Py_ssize_t *indices, elements;
+ char *dptr, *sptr;
+
+ if (!PyObject_CheckBuffer(dest) ||
+ !PyObject_CheckBuffer(src)) {
+ PyErr_SetString(PyExc_TypeError,
+ "both destination and source must be "\
+ "bytes-like objects");
+ return -1;
+ }
+
+ if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1;
+ if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) {
+ PyBuffer_Release(&view_dest);
+ return -1;
+ }
+
+ if (view_dest.len < view_src.len) {
+ PyErr_SetString(PyExc_BufferError,
+ "destination is too small to receive data from source");
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return -1;
+ }
+
+ if ((PyBuffer_IsContiguous(&view_dest, 'C') &&
+ PyBuffer_IsContiguous(&view_src, 'C')) ||
+ (PyBuffer_IsContiguous(&view_dest, 'F') &&
+ PyBuffer_IsContiguous(&view_src, 'F'))) {
+ /* simplest copy is all that is needed */
+ memcpy(view_dest.buf, view_src.buf, view_src.len);
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return 0;
+ }
+
+ /* Otherwise a more elaborate copy scheme is needed */
+
+ /* XXX(nnorwitz): need to check for overflow! */
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim);
+ if (indices == NULL) {
+ PyErr_NoMemory();
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return -1;
+ }
+ for (k=0; k<view_src.ndim;k++) {
+ indices[k] = 0;
+ }
+ elements = 1;
+ for (k=0; k<view_src.ndim; k++) {
+ /* XXX(nnorwitz): can this overflow? */
+ elements *= view_src.shape[k];
+ }
+ while (elements--) {
+ _Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape);
+ dptr = (char *)PyBuffer_GetPointer(&view_dest, indices); // patched by CT
+ sptr = (char *)PyBuffer_GetPointer(&view_src, indices); // patched by CT
+ memcpy(dptr, sptr, view_src.itemsize);
+ }
+ PyMem_Free(indices);
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return 0;
+}
+
+void
+PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape,
+ Py_ssize_t *strides, int itemsize,
+ char fort)
+{
+ int k;
+ Py_ssize_t sd;
+
+ sd = itemsize;
+ if (fort == 'F') {
+ for (k=0; k<nd; k++) {
+ strides[k] = sd;
+ sd *= shape[k];
+ }
+ }
+ else {
+ for (k=nd-1; k>=0; k--) {
+ strides[k] = sd;
+ sd *= shape[k];
+ }
+ }
+ return;
+}
+
+int
+PyBuffer_FillInfo(Pep_buffer *view, PyObject *obj, void *buf, Py_ssize_t len,
+ int readonly, int flags)
+{
+ if (view == NULL) {
+ PyErr_SetString(PyExc_BufferError,
+ "PyBuffer_FillInfo: view==NULL argument is obsolete");
+ return -1;
+ }
+
+ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
+ (readonly == 1)) {
+ PyErr_SetString(PyExc_BufferError,
+ "Object is not writable.");
+ return -1;
+ }
+
+ view->obj = obj;
+ if (obj)
+ Py_INCREF(obj);
+ view->buf = buf;
+ view->len = len;
+ view->readonly = readonly;
+ view->itemsize = 1;
+ view->format = NULL;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+ view->format = (char *)"B"; // patched by CT
+ view->ndim = 1;
+ view->shape = NULL;
+ if ((flags & PyBUF_ND) == PyBUF_ND)
+ view->shape = &(view->len);
+ view->strides = NULL;
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
+ view->strides = &(view->itemsize);
+ view->suboffsets = NULL;
+ view->internal = NULL;
+ return 0;
+}
+
+void
+PyBuffer_Release(Pep_buffer *view)
+{
+ PyObject *obj = view->obj;
+ PyBufferProcs *pb;
+ if (obj == NULL)
+ return;
+ pb = PepType_AS_BUFFER(Py_TYPE(obj));
+ if (pb && pb->bf_releasebuffer)
+ pb->bf_releasebuffer(obj, view);
+ view->obj = NULL;
+ Py_DECREF(obj);
+}
+
+#endif // Py_LIMITED_API
diff --git a/sources/shiboken6/libshiboken/bufferprocs_py37.h b/sources/shiboken6/libshiboken/bufferprocs_py37.h
new file mode 100644
index 000000000..e16194e50
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bufferprocs_py37.h
@@ -0,0 +1,109 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+*/
+
+#ifndef BUFFER_REENABLE_H
+#define BUFFER_REENABLE_H
+
+/* buffer interface */
+// This has been renamed to Pep_buffer and will be used.
+typedef struct bufferinfo {
+ void *buf;
+ PyObject *obj; /* owned reference */
+ Py_ssize_t len;
+ Py_ssize_t itemsize; /* This is Py_ssize_t so it can be
+ pointed to by strides in simple case.*/
+ int readonly;
+ int ndim;
+ char *format;
+ Py_ssize_t *shape;
+ Py_ssize_t *strides;
+ Py_ssize_t *suboffsets;
+ void *internal;
+} Pep_buffer;
+
+using getbufferproc =int (*)(PyObject *, Pep_buffer *, int);
+using releasebufferproc = void (*)(PyObject *, Pep_buffer *);
+
+/* Maximum number of dimensions */
+#define PyBUF_MAX_NDIM 64
+
+/* Flags for getting buffers */
+#define PyBUF_SIMPLE 0
+#define PyBUF_WRITABLE 0x0001
+/* we used to include an E, backwards compatible alias */
+#define PyBUF_WRITEABLE PyBUF_WRITABLE
+#define PyBUF_FORMAT 0x0004
+#define PyBUF_ND 0x0008
+#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
+#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
+#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
+#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
+#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
+
+#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE)
+#define PyBUF_CONTIG_RO (PyBUF_ND)
+
+#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE)
+#define PyBUF_STRIDED_RO (PyBUF_STRIDES)
+
+#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT)
+#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT)
+
+#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
+#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT)
+
+
+#define PyBUF_READ 0x100
+#define PyBUF_WRITE 0x200
+
+/* End buffer interface */
+LIBSHIBOKEN_API PyObject *PyMemoryView_FromBuffer(Pep_buffer *info);
+#define Py_buffer Pep_buffer
+
+#endif // BUFFER_REENABLE_H
diff --git a/sources/shiboken6/libshiboken/debugfreehook.cpp b/sources/shiboken6/libshiboken/debugfreehook.cpp
new file mode 100644
index 000000000..13df6bd6c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/debugfreehook.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "debugfreehook.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+
+#if defined(_WIN32) && defined(_DEBUG)
+# include <sbkwindows.h>
+# include <crtdbg.h>
+#endif
+
+#ifdef __GLIBC__
+#include <malloc.h>
+#endif
+
+#ifdef __APPLE__
+#include <malloc/malloc.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#endif
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+extern "C" {
+
+static int testPointerBeingFreed(void *ptr)
+{
+ // It is an error for a deleted pointer address to still be registered
+ // in the BindingManager
+ if (Shiboken::BindingManager::instance().hasWrapper(ptr)) {
+ Shiboken::GilState state;
+
+ SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(ptr);
+
+ fprintf(stderr, "SbkObject still in binding map when deleted: ");
+ PyObject_Print(reinterpret_cast<PyObject *>(wrapper), stderr, 0);
+ fprintf(stderr, "\n");
+
+#ifdef _WIN32
+ DebugBreak();
+#else
+ assert(0);
+#endif
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#if defined(_WIN32) && defined(_DEBUG)
+static _CRT_ALLOC_HOOK lastCrtAllocHook;
+static int DebugAllocHook(int nAllocType, void *pvData,
+ size_t nSize, int nBlockUse, long lRequest,
+ const unsigned char * szFileName, int nLine)
+{
+ // It is an error for a deleted pointer address to still be registered
+ // in the BindingManager
+ if ( nAllocType == _HOOK_FREE) {
+ if ( !testPointerBeingFreed(pvData) ) {
+ return 0;
+ }
+ }
+
+ if ( lastCrtAllocHook != NULL ) {
+ return lastCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest,
+ szFileName, nLine);
+ }
+
+ return 1;
+}
+#endif // _WIN32 && _DEBUG
+
+#ifdef __GLIBC__
+static void (*lastFreeHook)(void *ptr, const void *caller);
+static void DebugFreeHook(void *ptr, const void *caller)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastFreeHook != NULL )
+ lastFreeHook(ptr, caller);
+}
+#endif // __GLIBC__
+
+#ifdef __APPLE__
+static malloc_zone_t lastMallocZone;
+static void DebugFreeHook(malloc_zone_t *zone, void *ptr)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastMallocZone.free != NULL )
+ lastMallocZone.free(zone, ptr);
+}
+static void DebugFreeDefiniteSizeHook(malloc_zone_t *zone, void *ptr, size_t size)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastMallocZone.free_definite_size != NULL )
+ lastMallocZone.free_definite_size(zone, ptr, size);
+}
+#endif __APPLE__
+
+void debugInstallFreeHook(void)
+{
+#if defined(_WIN32) && defined(_DEBUG)
+ lastCrtAllocHook = _CrtSetAllocHook(DebugAllocHook);
+#endif
+
+#ifdef __GLIBC__
+ // __free_hook is not thread safe so it marked as deprecated. Use here
+ // is hopefully safe and should catch errors in a single threaded program
+ // and only miss some in a multithreaded program
+ lastFreeHook = __free_hook;
+ __free_hook = DebugFreeHook;
+#endif
+
+#ifdef __APPLE__
+ malloc_zone_t *zone = malloc_default_zone();
+ assert(zone != NULL);
+ //remove the write protection from the zone struct
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+ lastMallocZone = *zone;
+ zone->free = DebugFreeHook;
+ zone->free_definite_size = DebugFreeDefiniteSizeHook;
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ);
+ }
+#endif
+}
+
+void debugRemoveFreeHook(void)
+{
+#if defined(_WIN32) && defined(_DEBUG)
+ _CrtSetAllocHook(lastCrtAllocHook);
+#endif
+
+#ifdef __GLIBC__
+ __free_hook = lastFreeHook;
+#endif
+
+#ifdef __APPLE__
+ malloc_zone_t *zone = malloc_default_zone();
+ assert(zone != NULL);
+ //remove the write protection from the zone struct
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+ zone->free = lastMallocZone.free;
+ zone->free_definite_size = lastMallocZone.free_definite_size;
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ);
+ }
+#endif
+}
+
+} // extern "C"
+#endif // SHIBOKEN_INSTALL_DEBUG_FREE_HOOK
diff --git a/sources/shiboken6/libshiboken/debugfreehook.h b/sources/shiboken6/libshiboken/debugfreehook.h
new file mode 100644
index 000000000..c19e36ab2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/debugfreehook.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef DEBUGFREEHOOK_H
+#define DEBUGFREEHOOK_H
+
+// These functions enable C library runtime hooks to try to catch cases where
+// C++ object addresses remain in hash table of valid wrappers when the address
+// is passed to free. The hooks are probably not thread safe and thus
+// should only be enabled in single threaded environments
+
+// To enable the hook, uncomment the following define.
+//#define SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+extern "C" {
+
+void debugInstallFreeHook(void);
+void debugRemoveFreeHook(void);
+
+} // extern "C"
+
+#endif // SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+
+#endif // DEBUGFREEHOOK_H
diff --git a/sources/shiboken6/libshiboken/embed/embedding_generator.py b/sources/shiboken6/libshiboken/embed/embedding_generator.py
new file mode 100644
index 000000000..a058fd372
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/embedding_generator.py
@@ -0,0 +1,220 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+embedding_generator.py
+
+This file takes the content of the two supported directories and inserts
+it into a zip file. The zip file is then converted into a C++ source
+file that can easily be unpacked again with Python (see signature.cpp,
+constant 'PySide_PythonCode').
+
+Note that this _is_ a zipfile, but since it is embedded into the shiboken
+binary, we cannot use the zipimport module from Python.
+But a similar solution is possible that allows for normal imports.
+
+See signature_bootstrap.py for details.
+"""
+
+import sys
+import os
+import subprocess
+import textwrap
+import tempfile
+import argparse
+import marshal
+import traceback
+from pathlib import Path
+
+# work_dir is set to the source for testing, only.
+# It can be overridden in the command line.
+work_dir = Path(__file__).parent.resolve()
+embed_dir = work_dir
+cur_dir = Path.cwd()
+source_dir = work_dir.parents[2]
+assert source_dir.name == "sources"
+build_script_dir = work_dir.parents[3]
+assert (build_script_dir / "build_scripts").exists()
+
+sys.path.insert(0, os.fspath(build_script_dir))
+
+from build_scripts import utils
+
+
+def runpy(cmd, **kw):
+ subprocess.call([sys.executable, '-E'] + cmd.split(), **kw)
+
+
+def create_zipfile(use_pyc, quiet):
+ """
+ Collect all Python files, compile them, create a zip file
+ and make a chunked base64 encoded file from it.
+ """
+ zip_name = "signature.zip"
+ inc_name = "signature_inc.h"
+ flag = '-b'
+ os.chdir(work_dir)
+
+ # Remove all left-over py[co] and other files first, in case we use '--reuse-build'.
+ # Note that we could improve that with the PyZipfile function to use .pyc files
+ # in different folders, but that makes only sense when COIN allows us to have
+ # multiple Python versions in parallel.
+ for root, dirs, files in os.walk(work_dir):
+ for name in files:
+ fpath = Path(root) / name
+ ew = name.endswith
+ if ew(".pyc") or ew(".pyo") or ew(".zip") or ew(".inc"):
+ os.remove(fpath)
+ # We copy every Python file into this dir, but only for the right version.
+ # For testing in the source dir, we need to filter.
+ ignore = []
+ utils.copydir(source_dir / "shiboken6" / "shibokenmodule" / "files.dir" / "shibokensupport",
+ work_dir / "shibokensupport",
+ ignore=ignore, file_filter_function=lambda name, n2: name.endswith(".py"))
+ if embed_dir != work_dir:
+ utils.copyfile(embed_dir / "signature_bootstrap.py", work_dir)
+
+ if not use_pyc:
+ pass # We cannot compile, unless we have folders per Python version
+ else:
+ files = ' '.join(fn for fn in os.listdir('.'))
+ runpy(f'-m compileall -q {flag} {files}')
+ files = ' '.join(fn for fn in os.listdir('.') if not fn == zip_name)
+ runpy(f'-m zipfile -c {zip_name} {files}')
+ tmp = tempfile.TemporaryFile(mode="w+")
+ runpy(f'-m base64 {zip_name}', stdout=tmp)
+ # now generate the include file
+ tmp.seek(0)
+ with open(inc_name, "w") as inc:
+ _embed_file(tmp, inc)
+ tmp.close()
+
+ # also generate a simple embeddable .pyc file for signature_bootstrap.pyc
+ boot_name = "signature_bootstrap.py" if not use_pyc else "signature_bootstrap.pyc"
+ with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc:
+ _embed_bytefile(ldr, inc, not use_pyc)
+ os.chdir(cur_dir)
+ if quiet:
+ return
+
+ # have a look at our populated folder unless quiet option
+ def tree(directory):
+ print(f'+ {directory}')
+ for path in sorted(directory.rglob('*')):
+ depth = len(path.relative_to(directory).parts)
+ spacer = ' ' * depth
+ print(f'{spacer}+ {path.name}')
+
+ print("++++ Current contents of")
+ tree(work_dir)
+ print("++++")
+
+
+def _embed_file(fin, fout):
+ """
+ Format a text file for embedding in a C++ source file.
+ """
+ # MSVC has a 64k string limitation. In C, it would be easy to create an
+ # array of 64 byte strings and use them as one big array. In C++ this does
+ # not work, since C++ insists in having the terminating nullbyte.
+ # Therefore, we split the string after an arbitrary number of lines
+ # (chunked file).
+ limit = 50
+ text = fin.readlines()
+ print(textwrap.dedent("""
+ // This is a ZIP archive of all Python files in the directory
+ // "shiboken6/shibokenmodule/files.dir/shibokensupport/signature"
+ // There is also a toplevel file "signature_bootstrap.py[c]" that will be
+ // directly executed from C++ as a bootstrap loader.
+ """).strip(), file=fout)
+ block, blocks = 0, len(text) // limit + 1
+ for idx, line in enumerate(text):
+ if idx % limit == 0:
+ if block:
+ fout.write(')"\n')
+ comma = "," if block else ""
+ block += 1
+ fout.write(f'\n{comma} // Block {block} of {blocks}\nR"(')
+ else:
+ fout.write('\n')
+ fout.write(line.strip())
+ fout.write(')"\n\n/* Sentinel */, ""\n')
+
+
+def _embed_bytefile(fin, fout, is_text):
+ """
+ Format a binary file for embedding in a C++ source file.
+ This version works directly with a single .pyc file.
+ """
+ fname = fin.name
+ remark = ("No .pyc file because '--LIMITED-API=yes'" if is_text else
+ "The .pyc header is stripped away")
+ print(textwrap.dedent(f"""
+ /*
+ * This is the file "{fname}" as a simple byte array.
+ * It can be directly embedded without any further processing.
+ * {remark}.
+ */
+ """), file=fout)
+ headsize = ( 0 if is_text else
+ 16 if sys.version_info >= (3, 7) else 12 if sys.version_info >= (3, 3) else 8)
+ binstr = fin.read()[headsize:]
+ if is_text:
+ try:
+ compile(binstr, fin.name, "exec")
+ except SyntaxError as e:
+ print(e)
+ traceback.print_exc(file=sys.stdout)
+ print(textwrap.dedent(f"""
+ *************************************************************************
+ ***
+ *** Could not compile the boot loader '{fname}'!
+ ***
+ *************************************************************************
+ """))
+ raise SystemError
+ else:
+ try:
+ marshal.loads(binstr)
+ except ValueError as e:
+ print(e)
+ traceback.print_exc(file=sys.stdout)
+ version = sys.version_info[:3]
+ print(textwrap.dedent(f"""
+ *************************************************************************
+ ***
+ *** This Python version {version} seems to have a new .pyc header size.
+ *** Please correct the 'headsize' constant ({headsize}).
+ ***
+ *************************************************************************
+ """))
+ raise SystemError
+
+ print(file=fout)
+ use_ord = sys.version_info[0] == 2
+ for i in range(0, len(binstr), 16):
+ for c in bytes(binstr[i : i + 16]):
+ ord_c = ord(c) if use_ord else c
+ print(f"{ord_c:#4},", file=fout, end="")
+ print(file=fout)
+ print("/* End Of File */", file=fout)
+
+
+def str2bool(v):
+ if v.lower() in ('yes', 'true', 't', 'y', '1'):
+ return True
+ elif v.lower() in ('no', 'false', 'f', 'n', '0'):
+ return False
+ else:
+ raise argparse.ArgumentTypeError('Boolean value expected.')
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--cmake-dir', nargs="?")
+ parser.add_argument('--use-pyc', type=str2bool)
+ parser.add_argument('--quiet', action='store_true')
+ args = parser.parse_args()
+ if args.cmake_dir:
+ work_dir = Path(args.cmake_dir).resolve()
+ create_zipfile(args.use_pyc, args.quiet)
diff --git a/sources/shiboken6/libshiboken/embed/module_collector.py b/sources/shiboken6/libshiboken/embed/module_collector.py
new file mode 100644
index 000000000..a58ce6e4f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/module_collector.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+module_collector.py
+
+Collect a number of modules listed on the command line.
+
+The purpose of this script is to generate the scripts needed for
+a complete isolation of the signature extension.
+
+Usage:
+
+Run this script in one of the used python versions.
+It will create an executable archive of the files on the command line.
+"""
+
+import sys
+import os
+import argparse
+import pickle
+from textwrap import dedent
+from pathlib import path
+
+
+def source_archive(module, modname):
+ fname = Path(module.__file__).stem + ".py"
+ with open(fname) as source:
+ text = source.read()
+ encoded = text.replace("'''", "(triple_single)")
+ # modname = module.__name__
+ # Do not use: Some modules rename themselves!
+ version = ".".join(map(str, sys.version_info[:3]))
+ shortname = fname.stem
+ preamble = dedent(fr"""
+ # BEGIN SOURCE ARCHIVE Python {version} module {modname}
+
+ sources = {{}} if "sources" not in globals() else sources
+ sources["{modname}"] = '''\
+ {encoded}'''.replace("(triple_single)", "'''")
+
+ # END SOURCE ARCHIVE Python {version} module {modname}
+ """)
+ return preamble
+
+
+def read_all(modules):
+ collected = ""
+ for modname in modules:
+ mod = __import__(modname)
+ collected += source_archive(mod, modname)
+ return collected
+
+
+def license_header():
+ license = Path(__file__).parent / "qt_python_license.txt"
+ with license.open() as f:
+ return f.read()
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('modules', nargs="+")
+ args = parser.parse_args()
+ print("modules:", args.modules)
+ ret = license_header() + read_all(args.modules)
+ ma_mi = "_".join(map(str, sys.version_info[:2]))
+ outpath = Path(__file__).parents[2] / Path("shibokenmodule",
+ "files.dir", "shibokensupport", f"python_minilib_{ma_mi}.py")
+ with outpath.open("w") as f:
+ f.write(ret)
diff --git a/sources/shiboken6/libshiboken/embed/qt_python_license.txt b/sources/shiboken6/libshiboken/embed/qt_python_license.txt
new file mode 100644
index 000000000..e5fdfdf4d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/qt_python_license.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+##
+## PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+##
+## 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+## the Individual or Organization ("Licensee") accessing and otherwise using Python
+## 3.7.0 software in source or binary form and its associated documentation.
+##
+## 2. Subject to the terms and conditions of this License Agreement, PSF hereby
+## grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+## analyze, test, perform and/or display publicly, prepare derivative works,
+## distribute, and otherwise use Python 3.7.0 alone or in any derivative
+## version, provided, however, that PSF's License Agreement and PSF's notice of
+## copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+## Reserved" are retained in Python 3.7.0 alone or in any derivative version
+## prepared by Licensee.
+##
+## 3. In the event Licensee prepares a derivative work that is based on or
+## incorporates Python 3.7.0 or any part thereof, and wants to make the
+## derivative work available to others as provided herein, then Licensee hereby
+## agrees to include in any such work a brief summary of the changes made to Python
+## 3.7.0.
+##
+## 4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+## PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+## EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+## WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+## USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+##
+## 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+## FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+## MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+## THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+##
+## 6. This License Agreement will automatically terminate upon a material breach of
+## its terms and conditions.
+##
+## 7. Nothing in this License Agreement shall be deemed to create any relationship
+## of agency, partnership, or joint venture between PSF and Licensee. This License
+## Agreement does not grant permission to use PSF trademarks or trade name in a
+## trademark sense to endorse or promote products or services of Licensee, or any
+## third party.
+##
+## 8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+## to be bound by the terms and conditions of this License Agreement.
+##
diff --git a/sources/shiboken6/libshiboken/embed/signature_bootstrap.py b/sources/shiboken6/libshiboken/embed/signature_bootstrap.py
new file mode 100644
index 000000000..37f95cd35
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/signature_bootstrap.py
@@ -0,0 +1,204 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+signature_bootstrap.py
+----------------------
+
+This file was originally directly embedded into the C source.
+After it grew more and more, I now prefer to have it as Python file.
+
+Meanwhile, there is also no more a stub loader necessary:
+Because we meanwhile have embedding support, we could also load this file
+directly from a .pyc file.
+
+This file replaces the hard to read Python stub in 'signature.cpp', and we
+could distinguish better between bootstrap related functions and loader
+functions.
+It is embedded into 'signature.cpp' as "embed/signature_bootstrap.inc".
+
+# PYSIDE-1436: Python 3.10 had a problem with EmbeddableZipImporter because the
+imports were in the functions. Moved them outside into the globals.
+"""
+
+recursion_trap = 0
+
+import base64
+import importlib
+import io
+import os
+import sys
+import traceback
+import zipfile
+
+from contextlib import contextmanager
+from importlib.machinery import ModuleSpec
+from pathlib import Path
+
+
+def bootstrap():
+
+ global recursion_trap
+ if recursion_trap:
+ # we are probably called from outside, already
+ print("Recursion occurred in Bootstrap. Did you start by hand? Then it's ok.")
+ print("But you should trigger start by '_init_pyside_extension()', only!")
+ recursion_trap += 1
+
+ @contextmanager
+ def ensure_shibokensupport(target, support_path):
+ # Make sure that we always have the shibokensupport containing package first.
+ # Also remove any prior loaded module of this name, just in case.
+ # PYSIDE-1621: support_path can also be a finder instance.
+ target.insert(0, support_path)
+
+ sbks = "shibokensupport"
+ if sbks in sys.modules:
+ del sys.modules[sbks]
+ prefix = sbks + "."
+ for key in list(key for key in sys.modules if key.startswith(prefix)):
+ del sys.modules[key]
+ try:
+ import shibokensupport
+ yield
+ except Exception as e:
+ f = sys.stderr
+ print("Problem importing shibokensupport:", file=f)
+ print(f"{e.__class__.__name__}: {e}", file=f)
+ traceback.print_exc()
+ print("sys.path:", file=f)
+ for p in sys.path:
+ print(" " + p, file=f)
+ f.flush()
+ sys.exit(-1)
+ target.remove(support_path)
+
+ # Here we decide if we re-incarnate the embedded files or use embedding.
+ incarnated = find_incarnated_files()
+ if incarnated:
+ target, support_path = sys.path, os.fspath(incarnated)
+ else:
+ target, support_path = prepare_zipfile()
+ with ensure_shibokensupport(target, support_path):
+ from shibokensupport.signature import loader
+ return loader
+
+# Newer functionality:
+# This function checks if the support directory exist and returns it.
+# If does not exist, we try to create it and return it.
+# Otherwise, we return None.
+
+def find_incarnated_files():
+ import shiboken6 as root
+ files_dir = Path(root.__file__).resolve().parent / "files.dir"
+ handle_embedding_switch(files_dir)
+ if files_dir.exists():
+ sys.path.insert(0, os.fspath(files_dir))
+ # Note: To avoid recursion problems, we need to preload the loader.
+ # But that has the side-effect that we need to delay the feature
+ # initialization until all function pointers are set.
+ # See `post_init_func` in signature_globals.cpp .
+ import shibokensupport.signature.loader
+ del sys.path[0]
+ return files_dir
+ return None
+
+
+def handle_embedding_switch(files_dir):
+ """
+ This handles the optional environment variable `SBK_EMBED`
+ if not set : do nothing
+ if set to 0, false, no : de-virtualize the Python files
+ if set to 1, true, yes : virtualize again (delete "files.dir")
+ """
+ env_name = "SBK_EMBED"
+ env_var = os.environ.get(env_name)
+ if not env_var:
+ return
+ if env_var.lower() in ("1", "t", "true", "y", "yes"):
+ import shutil
+ shutil.rmtree(files_dir, ignore_errors=True)
+ elif env_var.lower() in ("0", "f", "false", "n", "no"):
+ reincarnate_files(files_dir)
+
+
+def reincarnate_files(files_dir):
+ target, zip = prepare_zipfile()
+ names = (_ for _ in zip.zfile.namelist() if _.endswith(".py"))
+ try:
+ # First check mkdir to get an error when we cannot write.
+ files_dir.mkdir(exist_ok=True)
+ except os.error as e:
+ print(f"SBK_EMBED=False: Warning: Cannot write into {files_dir}")
+ return None
+ try:
+ # Then check for a real error when unpacking the zip file.
+ zip.zfile.extractall(path=files_dir, members=names)
+ return files_dir
+ except Exception as e:
+ print(f"{e.__class__.__name__}: {e}", file=sys.stderr)
+ traceback.print_exc()
+ raise
+
+# New functionality: Loading from a zip archive.
+# There exists the zip importer, but as it is written, only real zip files are
+# supported. Before I will start an own implementation, it is easiest to use
+# a temporary zip file.
+# PYSIDE-1621: make zip file access totally virtual
+
+def prepare_zipfile():
+ """
+ Old approach:
+
+ Write the zip file to a real file and return its name.
+ It will be implicitly opened as such when we add the name to sys.path .
+
+ New approach (Python 3, only):
+
+ Use EmbeddableZipImporter and pass the zipfile structure directly.
+ The sys.path way does not work, instead we need to use sys.meta_path .
+ See https://docs.python.org/3/library/sys.html#sys.meta_path
+ """
+
+ # 'zipstring_sequence' comes from signature.cpp
+ zipbytes = base64.b64decode(''.join(zipstring_sequence))
+ vzip = zipfile.ZipFile(io.BytesIO(zipbytes))
+ return sys.meta_path, EmbeddableZipImporter(vzip)
+
+
+class EmbeddableZipImporter(object):
+
+ def __init__(self, zip_file):
+ def p2m(filename):
+ if filename.endswith("/__init__.py"):
+ return filename[:-12].replace("/", ".")
+ if filename.endswith(".py"):
+ return filename[:-3].replace("/", ".")
+ return None
+
+ self.zfile = zip_file
+ self._mod2path = {p2m(_.filename) : _.filename for _ in zip_file.filelist}
+
+ def find_spec(self, fullname, path, target=None):
+ path = self._mod2path.get(fullname)
+ return ModuleSpec(fullname, self) if path else None
+
+ def create_module(self, spec):
+ return None
+
+ def exec_module(self, module):
+ fullname = module.__spec__.name
+ filename = self._mod2path[fullname]
+ with self.zfile.open(filename, "r") as f: # "rb" not for zipfile
+ codeob = compile(f.read(), filename, "exec")
+ exec(codeob, module.__dict__)
+ module.__file__ = filename
+ module.__loader__ = self
+ if filename.endswith("/__init__.py"):
+ module.__path__ = []
+ module.__package__ = fullname
+ else:
+ module.__package__ = fullname.rpartition('.')[0]
+ sys.modules[fullname] = module
+
+# eof
diff --git a/sources/shiboken6/libshiboken/gilstate.cpp b/sources/shiboken6/libshiboken/gilstate.cpp
new file mode 100644
index 000000000..8daa93b8b
--- /dev/null
+++ b/sources/shiboken6/libshiboken/gilstate.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "gilstate.h"
+
+namespace Shiboken
+{
+
+GilState::GilState()
+{
+ if (Py_IsInitialized()) {
+ m_gstate = PyGILState_Ensure();
+ m_locked = true;
+ }
+}
+
+GilState::~GilState()
+{
+ release();
+}
+
+void GilState::release()
+{
+ if (m_locked && Py_IsInitialized()) {
+ PyGILState_Release(m_gstate);
+ m_locked = false;
+ }
+}
+
+// Abandon the lock: Only for special situations, like termination of a
+// POSIX thread (PYSIDE 1282).
+void GilState::abandon()
+{
+ m_locked = false;
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/gilstate.h b/sources/shiboken6/libshiboken/gilstate.h
new file mode 100644
index 000000000..abad9d955
--- /dev/null
+++ b/sources/shiboken6/libshiboken/gilstate.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef GILSTATE_H
+#define GILSTATE_H
+
+#include <shibokenmacros.h>
+#include "sbkpython.h"
+
+namespace Shiboken
+{
+
+class LIBSHIBOKEN_API GilState
+{
+public:
+ GilState(const GilState &) = delete;
+ GilState(GilState &&) = delete;
+ GilState &operator=(const GilState &) = delete;
+ GilState &operator=(GilState &&) = delete;
+
+ GilState();
+ ~GilState();
+ void release();
+ void abandon();
+private:
+ PyGILState_STATE m_gstate;
+ bool m_locked = false;
+};
+
+} // namespace Shiboken
+
+#endif // GILSTATE_H
+
diff --git a/sources/shiboken6/libshiboken/helper.cpp b/sources/shiboken6/libshiboken/helper.cpp
new file mode 100644
index 000000000..46af68956
--- /dev/null
+++ b/sources/shiboken6/libshiboken/helper.cpp
@@ -0,0 +1,637 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "helper.h"
+#include "basewrapper_p.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings.h"
+#include "pep384impl.h"
+
+#include <algorithm>
+#include <optional>
+
+#include <iomanip>
+#include <iostream>
+#include <climits>
+#include <cstring>
+#include <cstdarg>
+#include <cctype>
+
+#ifdef _WIN32
+# include <sbkwindows.h>
+#else
+# include <pthread.h>
+#endif
+
+static std::optional<std::string> getStringAttr(PyObject *obj, const char *what)
+{
+ if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error.
+ Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what));
+ if (PyUnicode_Check(result.object()) != 0)
+ return _PepUnicode_AsString(result.object());
+ }
+ return std::nullopt;
+}
+
+static std::optional<int> getIntAttr(PyObject *obj, const char *what)
+{
+ if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error.
+ Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what));
+ if (PyLong_Check(result.object()) != 0)
+ return PyLong_AsLong(result.object());
+ }
+ return std::nullopt;
+}
+
+static bool verbose = false;
+
+static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str);
+
+static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool verbose)
+{
+ if (obj == nullptr) {
+ str << '0';
+ return;
+ }
+
+ str << '"' << obj->tp_name << '"';
+ if (verbose) {
+ bool immutableType = false;
+ str << ", 0x" << std::hex << obj->tp_flags << std::dec;
+ if (obj->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ str << " [heaptype]";
+ if (obj->tp_flags & Py_TPFLAGS_BASETYPE)
+ str << " [base]";
+ if (obj->tp_flags & Py_TPFLAGS_HAVE_GC)
+ str << " [gc]";
+ if (obj->tp_flags & Py_TPFLAGS_LONG_SUBCLASS)
+ str << " [long]";
+ if (obj->tp_flags & Py_TPFLAGS_LIST_SUBCLASS)
+ str << " [list]";
+ if (obj->tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS)
+ str << " [tuple]";
+ if (obj->tp_flags & Py_TPFLAGS_BYTES_SUBCLASS)
+ str << " [bytes]";
+ if (obj->tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS)
+ str << " [unicode]";
+ if (obj->tp_flags & Py_TPFLAGS_DICT_SUBCLASS)
+ str << " [dict]";
+ if (obj->tp_flags & Py_TPFLAGS_TYPE_SUBCLASS)
+ str << " [type]";
+ if (obj->tp_flags & Py_TPFLAGS_IS_ABSTRACT)
+ str << " [abstract]";
+ if (obj->tp_flags & Py_TPFLAGS_READY)
+ str << " [ready]";
+ if (obj->tp_flags & Py_TPFLAGS_READYING)
+ str << " [readying]";
+ if (obj->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ str << " [method_descriptor]";
+# ifndef Py_LIMITED_API
+ if (obj->tp_flags & Py_TPFLAGS_HAVE_VECTORCALL)
+ str << " [vectorcall]";
+# endif // !Py_LIMITED_API
+# if PY_VERSION_HEX >= 0x030A0000
+ immutableType = (obj->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) != 0;
+ if (immutableType)
+ str << " [immutabletype]";
+ if (obj->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)
+ str << " [disallow_instantiation]";
+# ifndef Py_LIMITED_API
+ if (obj->tp_flags & Py_TPFLAGS_MAPPING)
+ str << " [mapping]";
+ if (obj->tp_flags & Py_TPFLAGS_SEQUENCE)
+ str << " [sequence]";
+# endif // !Py_LIMITED_API
+# endif // 3.10
+ if (obj->tp_basicsize != 0)
+ str << ", basicsize=" << obj->tp_basicsize;
+ if (verbose) {
+ formatTypeTuple(obj->tp_bases, "bases", str);
+ formatTypeTuple(obj->tp_mro, "mro", str);
+ if (!immutableType) {
+ auto *underlying = reinterpret_cast<const PyObject *>(obj)->ob_type;
+ if (underlying != nullptr && underlying != obj) {
+ str << ", underlying=\"" << underlying->tp_name << '"';
+ }
+ }
+ }
+ }
+}
+
+static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str)
+{
+ const Py_ssize_t size = t != nullptr && PyTuple_Check(t) != 0 ? PyTuple_Size(t) : 0;
+ if (size > 0) {
+ str << ", " << what << "=[" << size << "]{";
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (i != 0)
+ str << ", ";
+ Shiboken::AutoDecRef item(PyTuple_GetItem(t, i));
+ if (item.isNull())
+ str << '0'; // Observed with non-ready types
+ else
+ str << '"' << reinterpret_cast<PyTypeObject *>(item.object())->tp_name << '"';
+ }
+ str << '}';
+ }
+}
+
+static void formatPyObject(PyObject *obj, std::ostream &str);
+
+static void formatPySequence(PyObject *obj, std::ostream &str)
+{
+ const Py_ssize_t size = PySequence_Size(obj);
+ const Py_ssize_t printSize = std::min(size, Py_ssize_t(5));
+ str << size << " <";
+ for (Py_ssize_t i = 0; i < printSize; ++i) {
+ if (i)
+ str << ", ";
+ str << '(';
+ PyObject *item = PySequence_GetItem(obj, i);
+ formatPyObject(item, str);
+ str << ')';
+ Py_XDECREF(item);
+ }
+ if (printSize < size)
+ str << ",...";
+ str << '>';
+}
+
+static void formatPyTuple(PyObject *obj, std::ostream &str)
+{
+
+ const Py_ssize_t size = PyTuple_Size(obj);
+ str << size << " <";
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << '(';
+ PyObject *item = PyTuple_GetItem(obj, i);
+ formatPyObject(item, str);
+ str << ')';
+ Py_XDECREF(item);
+ }
+ str << '>';
+}
+
+static void formatPyDict(PyObject *obj, std::ostream &str)
+{
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ str << '{';
+ while (PyDict_Next(obj, &pos, &key, &value) != 0) {
+ if (pos)
+ str << ", ";
+ str << Shiboken::debugPyObject(key) << '=' << Shiboken::debugPyObject(value);
+ }
+ str << '}';
+}
+
+// Helper to format a 0-terminated character sequence
+template <class Char>
+static void formatCharSequence(const Char *s, std::ostream &str)
+{
+ str << '"';
+ const auto oldFillC = str.fill('0');
+ str << std::hex;
+ for (; *s; ++s) {
+ const unsigned c = *s;
+ if (c < 127)
+ str << char(c);
+ else
+ str << "0x" << std::right << std::setw(sizeof(Char) * 2) << c << std::left;
+ }
+ str << std::dec;
+ str.fill(oldFillC);
+ str << '"';
+}
+
+static void formatPyUnicode(PyObject *obj, std::ostream &str)
+{
+ // Note: The below call create the PyCompactUnicodeObject.utf8 representation
+ str << '"' << _PepUnicode_AsString(obj) << '"';
+ if (!verbose)
+ return;
+
+ str << " (" << PyUnicode_GetLength(obj) << ')';
+ const auto kind = _PepUnicode_KIND(obj);
+ switch (kind) {
+#if PY_VERSION_HEX < 0x030C0000
+ case PepUnicode_WCHAR_KIND:
+ str << " [wchar]";
+ break;
+#endif
+ case PepUnicode_1BYTE_KIND:
+ str << " [1byte]";
+ break;
+ case PepUnicode_2BYTE_KIND:
+ str << " [2byte]";
+ break;
+ case PepUnicode_4BYTE_KIND:
+ str << " [4byte]";
+ break;
+ }
+
+ const bool ascii = _PepUnicode_IS_ASCII(obj);
+ if (ascii)
+ str << " [ascii]";
+ const bool compact = _PepUnicode_IS_COMPACT(obj);
+ if (compact)
+ str << " [compact]";
+ void *data =_PepUnicode_DATA(obj);
+ str << ", data=";
+ switch (kind) {
+#if PY_VERSION_HEX < 0x030C0000
+ case PepUnicode_WCHAR_KIND:
+ formatCharSequence(reinterpret_cast<const wchar_t *>(data), str);
+#endif
+ break;
+ case PepUnicode_1BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS1 *>(data), str);
+ break;
+ case PepUnicode_2BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS2 *>(data), str);
+ break;
+ case PepUnicode_4BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS4 *>(data), str);
+ break;
+ }
+
+#ifndef Py_LIMITED_API
+ const char *utf8 = nullptr;
+ if (!ascii && compact && kind == PepUnicode_1BYTE_KIND) {
+ const auto *compactObj = reinterpret_cast<const PyCompactUnicodeObject *>(obj);
+ if (compactObj->utf8_length)
+ utf8 = compactObj->utf8;
+ }
+ if (utf8) {
+ str << ", utf8=";
+ formatCharSequence(reinterpret_cast<const Py_UCS1 *>(utf8), str);
+ } else {
+ str << ", no-utf8";
+ }
+#endif // !Py_LIMITED_API
+}
+
+static std::string getQualName(PyObject *obj)
+{
+ Shiboken::AutoDecRef result(PyObject_GetAttr(obj, Shiboken::PyMagicName::qualname()));
+ return result.object() != nullptr
+ ? _PepUnicode_AsString(result.object()) : std::string{};
+}
+
+static void formatPyFunction(PyObject *obj, std::ostream &str)
+{
+ str << '"' << getQualName(obj) << "()\"";
+}
+
+static void formatPyMethod(PyObject *obj, std::ostream &str)
+{
+ if (auto *func = PyMethod_Function(obj))
+ formatPyFunction(func, str);
+ str << ", instance=" << PyMethod_Self(obj);
+}
+
+static void formatPyCodeObject(PyObject *obj, std::ostream &str)
+{
+ if (auto name = getStringAttr(obj, "co_name"))
+ str << '"' << name.value() << '"';
+ if (auto qualName = getStringAttr(obj, "co_qualname"))
+ str << ", co_qualname=\"" << qualName.value() << '"';
+ if (auto flags = getIntAttr(obj, "co_flags"))
+ str << ", flags=0x" << std::hex << flags.value() << std::dec;
+ if (auto c = getIntAttr(obj, "co_argcount"))
+ str << ", co_argcounts=" << c.value();
+ if (auto c = getIntAttr(obj, "co_posonlyargcount"))
+ str << ", co_posonlyargcount=" << c.value();
+ if (auto c = getIntAttr(obj, "co_kwonlyargcount"))
+ str << ", co_kwonlyargcount=" << c.value();
+ if (auto fileName = getStringAttr(obj, "co_filename")) {
+ str << " @" << fileName.value();
+ if (auto l = getIntAttr(obj, "co_firstlineno"))
+ str << ':'<< l.value();
+ }
+}
+
+static void formatPyObjectHelper(PyObject *obj, std::ostream &str)
+{
+ str << ", ";
+ if (obj == Py_None) {
+ str << "None";
+ return;
+ }
+ if (obj == Py_True) {
+ str << "True";
+ return;
+ }
+ if (obj == Py_False) {
+ str << "False";
+ return;
+ }
+ const auto refs = Py_REFCNT(obj);
+ if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT
+ str << "immortal, ";
+ else
+ str << "refs=" << refs << ", ";
+ if (PyType_Check(obj)) {
+ str << "type: ";
+ formatPyTypeObject(reinterpret_cast<PyTypeObject *>(obj), str, true);
+ return;
+ }
+ formatPyTypeObject(obj->ob_type, str, false);
+ str << ", ";
+ if (PyLong_Check(obj)) {
+ const auto llv = PyLong_AsLongLong(obj);
+ if (PyErr_Occurred() != PyExc_OverflowError) {
+ str << llv;
+ } else {
+ PyErr_Clear();
+ str << "0x" << std::hex << PyLong_AsUnsignedLongLong(obj) << std::dec;
+ }
+ }
+ else if (PyFloat_Check(obj))
+ str << PyFloat_AsDouble(obj);
+ else if (PyUnicode_Check(obj))
+ formatPyUnicode(obj, str);
+ else if (PyFunction_Check(obj) != 0)
+ formatPyFunction(obj, str);
+ else if (PyMethod_Check(obj) != 0)
+ formatPyMethod(obj, str);
+ else if (PepCode_Check(obj) != 0)
+ formatPyCodeObject(obj, str);
+ else if (PySequence_Check(obj))
+ formatPySequence(obj, str);
+ else if (PyDict_Check(obj))
+ formatPyDict(obj, str);
+ else if (PyTuple_CheckExact(obj))
+ formatPyTuple(obj, str);
+ else
+ str << "<unknown>";
+}
+
+static void formatPyObject(PyObject *obj, std::ostream &str)
+{
+ str << obj;
+ if (obj)
+ formatPyObjectHelper(obj, str);
+}
+
+namespace Shiboken
+{
+
+debugPyObject::debugPyObject(PyObject *o) : m_object(o)
+{
+}
+
+debugSbkObject::debugSbkObject(SbkObject *o) : m_object(o)
+{
+}
+
+debugPyTypeObject::debugPyTypeObject(const PyTypeObject *o) : m_object(o)
+{
+}
+
+debugPyBuffer::debugPyBuffer(const Py_buffer &b) : m_buffer(b)
+{
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o)
+{
+ str << "PyTypeObject(";
+ formatPyTypeObject(o.m_object, str, true);
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugSbkObject &o)
+{
+ str << "SbkObject(" << o.m_object;
+ if (o.m_object) {
+ Shiboken::Object::_debugFormat(str, o.m_object);
+ formatPyObjectHelper(reinterpret_cast<PyObject *>(o.m_object), str);
+ }
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyObject &o)
+{
+ str << "PyObject(";
+ formatPyObject(o.m_object, str);
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b)
+{
+ str << "PyBuffer(buf=" << b.m_buffer.buf << ", len="
+ << b.m_buffer.len << ", itemsize=" << b.m_buffer.itemsize
+ << ", readonly=" << b.m_buffer.readonly << ", ndim=" << b.m_buffer.ndim;
+ if (b.m_buffer.format)
+ str << ", format=\"" << b.m_buffer.format << '"';
+ str << ", shape=" << b.m_buffer.shape << ", strides=" << b.m_buffer.strides
+ << ", suboffsets=" << b.m_buffer.suboffsets << ')';
+ return str;
+}
+
+std::ios_base &debugVerbose(std::ios_base &s)
+{
+ verbose = true;
+ return s;
+}
+
+std::ios_base &debugBrief(std::ios_base &s)
+{
+ verbose = false;
+ return s;
+}
+
+#ifdef _WIN32
+// Converts a Unicode string to a string encoded in the Windows console's
+// code page via wchar_t for use with argv (PYSIDE-1425).
+// FIXME: Remove once Windows console uses UTF-8
+static char *toWindowsConsoleEncoding(PyObject *unicode)
+{
+ wchar_t *buf = PyUnicode_AsWideCharString(unicode, nullptr);
+ if (buf == nullptr)
+ return nullptr;
+ const int required = WideCharToMultiByte(CP_ACP, 0, buf, -1,
+ nullptr, 0, nullptr, nullptr);
+ if (required == 0) {
+ PyMem_Free(buf);
+ return nullptr;
+ }
+ char *result = new char[required];
+ WideCharToMultiByte(CP_ACP, 0, buf, -1,
+ result, required, nullptr, nullptr);
+ PyMem_Free(buf);
+ return result;
+}
+#endif // _WIN32
+
+// PySide-510: Changed from PySequence to PyList, which is correct.
+bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defaultAppName)
+{
+ if (!PyList_Check(argList))
+ return false;
+
+ if (!defaultAppName)
+ defaultAppName = "PySideApplication";
+
+ // Check all items
+ Shiboken::AutoDecRef args(PySequence_Fast(argList, nullptr));
+ int numArgs = int(PySequence_Fast_GET_SIZE(argList));
+ for (int i = 0; i < numArgs; ++i) {
+ PyObject *item = PyList_GET_ITEM(args.object(), i);
+ if (!PyBytes_Check(item) && !PyUnicode_Check(item))
+ return false;
+ }
+
+ bool hasEmptyArgList = numArgs == 0;
+ if (hasEmptyArgList)
+ numArgs = 1;
+
+ *argc = numArgs;
+ *argv = new char *[*argc];
+
+ if (hasEmptyArgList) {
+ // Try to get the script name
+ PyObject *globals = PyEval_GetGlobals();
+ PyObject *appName = PyDict_GetItem(globals, Shiboken::PyMagicName::file());
+ (*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName);
+ } else {
+ for (int i = 0; i < numArgs; ++i) {
+ PyObject *item = PyList_GET_ITEM(args.object(), i);
+ char *string = nullptr;
+ if (Shiboken::String::check(item)) {
+#ifdef _WIN32
+ string = toWindowsConsoleEncoding(item);
+#else
+ string = strdup(Shiboken::String::toCString(item));
+#endif
+ }
+ (*argv)[i] = string;
+ }
+ }
+
+ return true;
+}
+
+int *sequenceToIntArray(PyObject *obj, bool zeroTerminated)
+{
+ AutoDecRef seq(PySequence_Fast(obj, "Sequence of ints expected"));
+ if (seq.isNull())
+ return nullptr;
+
+ Py_ssize_t size = PySequence_Fast_GET_SIZE(seq.object());
+ int *array = new int[size + (zeroTerminated ? 1 : 0)];
+
+ for (int i = 0; i < size; i++) {
+ PyObject *item = PySequence_Fast_GET_ITEM(seq.object(), i);
+ if (!PyLong_Check(item)) {
+ PyErr_SetString(PyExc_TypeError, "Sequence of ints expected");
+ delete[] array;
+ return nullptr;
+ }
+ array[i] = PyLong_AsLong(item);
+ }
+
+ if (zeroTerminated)
+ array[size] = 0;
+
+ return array;
+}
+
+
+int warning(PyObject *category, int stacklevel, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#ifdef _WIN32
+ va_list args2 = args;
+#else
+ va_list args2;
+ va_copy(args2, args);
+#endif
+
+ // check the necessary memory
+ int size = vsnprintf(nullptr, 0, format, args) + 1;
+ auto message = new char[size];
+ int result = 0;
+ if (message) {
+ // format the message
+ vsnprintf(message, size, format, args2);
+ result = PyErr_WarnEx(category, message, stacklevel);
+ delete [] message;
+ }
+ va_end(args2);
+ va_end(args);
+ return result;
+}
+
+ThreadId currentThreadId()
+{
+#if defined(_WIN32)
+ return GetCurrentThreadId();
+#elif defined(__APPLE_CC__)
+ return reinterpret_cast<ThreadId>(pthread_self());
+#else
+ return pthread_self();
+#endif
+}
+
+// Internal, used by init() from main thread
+static ThreadId _mainThreadId{0};
+void _initMainThreadId() { _mainThreadId = currentThreadId(); }
+
+ThreadId mainThreadId()
+{
+ return _mainThreadId;
+}
+
+const char *typeNameOf(const char *typeIdName)
+{
+ auto size = std::strlen(typeIdName);
+#if defined(Q_CC_MSVC) // MSVC: "class QPaintDevice * __ptr64"
+ if (auto *lastStar = strchr(typeName, '*')) {
+ // MSVC: "class QPaintDevice * __ptr64"
+ while (*--lastStar == ' ') {
+ }
+ size = lastStar - typeName + 1;
+ }
+#else // g++, Clang: "QPaintDevice *" -> "P12QPaintDevice"
+ if (size > 2 && typeIdName[0] == 'P' && std::isdigit(typeIdName[1])) {
+ ++typeIdName;
+ --size;
+ }
+#endif
+ char *result = new char[size + 1];
+ result[size] = '\0';
+ std::memcpy(result, typeIdName, size);
+ return result;
+}
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION)
+static int _getPyVerbose()
+{
+ PyConfig config;
+ PyConfig_InitPythonConfig(&config);
+ return config.verbose;
+}
+#endif // !Py_LIMITED_API >= 3.10
+
+int pyVerbose()
+{
+#ifdef Py_LIMITED_API
+ return Pep_GetVerboseFlag();
+#elif PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION)
+ static const int result = _getPyVerbose();
+ return result;
+#else
+ return Py_VerboseFlag;
+#endif
+}
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/helper.h b/sources/shiboken6/libshiboken/helper.h
new file mode 100644
index 000000000..f226e8c24
--- /dev/null
+++ b/sources/shiboken6/libshiboken/helper.h
@@ -0,0 +1,120 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef HELPER_H
+#define HELPER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "autodecref.h"
+
+#include <iosfwd>
+
+#define SBK_UNUSED(x) (void)(x);
+
+namespace Shiboken
+{
+
+/**
+* It transforms a python sequence into two C variables, argc and argv.
+* This function tries to find the application (script) name and put it into argv[0], if
+* the application name can't be guessed, defaultAppName will be used.
+*
+* No memory is allocated is an error occur.
+*
+* \note argc must be a valid address.
+* \note The argv array is allocated using new operator and each item is allocated using malloc.
+* \returns True on sucess, false otherwise.
+*/
+LIBSHIBOKEN_API bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defaultAppName = nullptr);
+
+/**
+ * Convert a python sequence into a heap-allocated array of ints.
+ *
+ * \returns The newly allocated array or NULL in case of error or empty sequence. Check with PyErr_Occurred
+ * if it was successfull.
+ */
+LIBSHIBOKEN_API int *sequenceToIntArray(PyObject *obj, bool zeroTerminated = false);
+
+/// Fix a type name returned by typeid(t).name(), depending on compiler.
+/// \returns Fixed name (allocated).
+LIBSHIBOKEN_API const char *typeNameOf(const char *typeIdName);
+
+/**
+ * Creates and automatically deallocates C++ arrays.
+ */
+template<class T>
+class AutoArrayPointer
+{
+ public:
+ AutoArrayPointer(const AutoArrayPointer &) = delete;
+ AutoArrayPointer(AutoArrayPointer &&) = delete;
+ AutoArrayPointer &operator=(const AutoArrayPointer &) = delete;
+ AutoArrayPointer &operator=(AutoArrayPointer &&) = delete;
+
+
+ explicit AutoArrayPointer(Py_ssize_t size) { data = new T[size]; }
+ T &operator[](Py_ssize_t pos) { return data[pos]; }
+ operator T *() const { return data; }
+ ~AutoArrayPointer() { delete[] data; }
+ private:
+ T *data;
+};
+
+using ThreadId = unsigned long long;
+LIBSHIBOKEN_API ThreadId currentThreadId();
+LIBSHIBOKEN_API ThreadId mainThreadId();
+
+LIBSHIBOKEN_API int pyVerbose();
+
+/**
+ * An utility function used to call PyErr_WarnEx with a formatted message.
+ */
+LIBSHIBOKEN_API int warning(PyObject *category, int stacklevel, const char *format, ...);
+
+struct LIBSHIBOKEN_API debugPyObject
+{
+ explicit debugPyObject(PyObject *o);
+
+ PyObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugSbkObject
+{
+ explicit debugSbkObject(SbkObject *o);
+
+ SbkObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugPyTypeObject
+{
+ explicit debugPyTypeObject(const PyTypeObject *o);
+
+ const PyTypeObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugPyBuffer
+{
+ explicit debugPyBuffer(const Py_buffer &b);
+
+ const Py_buffer &m_buffer;
+};
+
+struct debugPyArrayObject
+{
+ explicit debugPyArrayObject(PyObject *object) : m_object(object) {}
+
+ PyObject *m_object;
+};
+
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugSbkObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &b);
+LIBSHIBOKEN_API std::ios_base &debugVerbose(std::ios_base &s);
+LIBSHIBOKEN_API std::ios_base &debugBrief(std::ios_base &s);
+} // namespace Shiboken
+
+
+#endif // HELPER_H
diff --git a/sources/shiboken6/libshiboken/pep384ext.h b/sources/shiboken6/libshiboken/pep384ext.h
new file mode 100644
index 000000000..021c53d16
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384ext.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PEP384EXT_H
+#define PEP384EXT_H
+
+#include "pep384impl.h"
+
+/// Returns the allocator slot of the PyTypeObject.
+inline allocfunc PepExt_Type_GetAllocSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<allocfunc>(PepType_GetSlot(t, Py_tp_alloc));
+}
+
+/// Invokes the allocator slot of the PyTypeObject.
+template <class Type>
+inline Type *PepExt_TypeCallAlloc(PyTypeObject *t, Py_ssize_t nitems)
+{
+ PyObject *result = PepExt_Type_GetAllocSlot(t)(t, nitems);
+ return reinterpret_cast<Type *>(result);
+}
+
+/// Returns the getattro slot of the PyTypeObject.
+inline getattrofunc PepExt_Type_GetGetAttroSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<getattrofunc>(PepType_GetSlot(t, Py_tp_getattro));
+}
+
+/// Returns the setattro slot of the PyTypeObject.
+inline setattrofunc PepExt_Type_GetSetAttroSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<setattrofunc>(PepType_GetSlot(t, Py_tp_setattro));
+}
+
+/// Returns the descr_get slot of the PyTypeObject.
+inline descrgetfunc PepExt_Type_GetDescrGetSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<descrgetfunc>(PepType_GetSlot(t, Py_tp_descr_get));
+}
+
+/// Invokes the descr_get slot of the PyTypeObject.
+inline PyObject *PepExt_Type_CallDescrGet(PyObject *self, PyObject *obj, PyObject *type)
+{
+ return PepExt_Type_GetDescrGetSlot(Py_TYPE(self))(self, obj, type);
+}
+
+/// Returns the descr_set slot of the PyTypeObject.
+inline descrsetfunc PepExt_Type_GetDescrSetSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<descrsetfunc>(PepType_GetSlot(t, Py_tp_descr_set));
+}
+
+/// Returns the call slot of the PyTypeObject.
+inline ternaryfunc PepExt_Type_GetCallSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<ternaryfunc>(PepType_GetSlot(t, Py_tp_call));
+}
+
+/// Returns the new slot of the PyTypeObject.
+inline newfunc PepExt_Type_GetNewSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<newfunc>(PepType_GetSlot(t, Py_tp_new));
+}
+
+/// Returns the init slot of the PyTypeObject.
+inline initproc PepExt_Type_GetInitSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<initproc>(PepType_GetSlot(t, Py_tp_init));
+}
+
+/// Returns the free slot of the PyTypeObject.
+inline freefunc PepExt_Type_GetFreeSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<freefunc>(PepType_GetSlot(t, Py_tp_free));
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyTypeObject *t, void *object)
+{
+ PepExt_Type_GetFreeSlot(t)(object);
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyObject *object)
+{
+ PepExt_Type_GetFreeSlot(Py_TYPE(object))(object);
+}
+
+#endif // PEP384EXT_H
diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
new file mode 100644
index 000000000..5310207a3
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384impl.cpp
@@ -0,0 +1,1319 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define PEP384_INTERN
+
+#include "sbkpython.h"
+#include "autodecref.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "sbkenum.h"
+#include "voidptr.h"
+
+#include <cstdlib>
+#include <cstring>
+
+extern "C"
+{
+
+/*
+ * The documentation is located in `sources/pyside6/doc/developer/limited_api.rst`.
+
+ * Here is the verification code for PyTypeObject.
+ * We create a type object and check if its fields
+ * appear at the right offsets.
+ */
+#ifdef Py_LIMITED_API
+
+#define make_dummy_int(x) (x * sizeof(void *))
+#define make_dummy(x) (reinterpret_cast<void *>(make_dummy_int(x)))
+
+static PyObject *
+dummy_func(PyObject * /* self */, PyObject * /* args */)
+{
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef probe_methoddef[] = {
+ {"dummy", dummy_func, METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyGetSetDef probe_getseters[] = {
+ {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
+};
+
+static PyMemberDef probe_members[] = {
+ {nullptr, 0, 0, 0, nullptr} /* Sentinel */
+};
+
+#define probe_tp_dealloc make_dummy(1)
+#define probe_tp_repr make_dummy(2)
+#define probe_tp_call make_dummy(3)
+#define probe_tp_getattro make_dummy(16)
+#define probe_tp_setattro make_dummy(17)
+#define probe_tp_str make_dummy(4)
+#define probe_tp_traverse make_dummy(5)
+#define probe_tp_clear make_dummy(6)
+#define probe_tp_iternext make_dummy(7)
+#define probe_tp_methods probe_methoddef
+#define probe_tp_members probe_members
+#define probe_tp_getset probe_getseters
+#define probe_tp_descr_get make_dummy(10)
+#define probe_tp_descr_set make_dummy(18)
+#define probe_tp_init make_dummy(11)
+#define probe_tp_alloc make_dummy(12)
+#define probe_tp_new make_dummy(13)
+#define probe_tp_free make_dummy(14)
+#define probe_tp_is_gc make_dummy(15)
+
+#define probe_tp_name "type.probe"
+#define probe_tp_basicsize make_dummy_int(42)
+
+static PyType_Slot typeprobe_slots[] = {
+ {Py_tp_dealloc, probe_tp_dealloc},
+ {Py_tp_repr, probe_tp_repr},
+ {Py_tp_call, probe_tp_call},
+ {Py_tp_getattro, probe_tp_getattro},
+ {Py_tp_setattro, probe_tp_setattro},
+ {Py_tp_str, probe_tp_str},
+ {Py_tp_traverse, probe_tp_traverse},
+ {Py_tp_clear, probe_tp_clear},
+ {Py_tp_iternext, probe_tp_iternext},
+ {Py_tp_methods, probe_tp_methods},
+ {Py_tp_members, probe_tp_members},
+ {Py_tp_getset, probe_tp_getset},
+ {Py_tp_descr_get, probe_tp_descr_get},
+ {Py_tp_descr_set, probe_tp_descr_set},
+ {Py_tp_init, probe_tp_init},
+ {Py_tp_alloc, probe_tp_alloc},
+ {Py_tp_new, probe_tp_new},
+ {Py_tp_free, probe_tp_free},
+ {Py_tp_is_gc, probe_tp_is_gc},
+ {0, nullptr}
+};
+static PyType_Spec typeprobe_spec = {
+ probe_tp_name,
+ probe_tp_basicsize,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeprobe_slots,
+};
+
+static void
+check_PyTypeObject_valid()
+{
+ auto *typetype = &PyType_Type;
+ auto *obtype = reinterpret_cast<PyObject *>(typetype);
+ auto *probe_tp_base_obj = PyObject_GetAttr(obtype, Shiboken::PyMagicName::base());
+ auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(probe_tp_base_obj);
+ auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases());
+ auto *checkObj = PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases);
+ auto *check = reinterpret_cast<PyTypeObject *>(checkObj);
+ PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset());
+ long probe_tp_weakrefoffset = PyLong_AsLong(w);
+ PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
+ long probe_tp_dictoffset = PyLong_AsLong(d);
+ PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro());
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(check));
+ auto *checkDict = tpDict.object();
+ if (false
+ || strcmp(probe_tp_name, check->tp_name) != 0
+ || probe_tp_basicsize != check->tp_basicsize
+ || probe_tp_dealloc != check->tp_dealloc
+ || probe_tp_repr != check->tp_repr
+ || probe_tp_call != check->tp_call
+ || probe_tp_getattro != check->tp_getattro
+ || probe_tp_setattro != check->tp_setattro
+ || probe_tp_str != check->tp_str
+ || probe_tp_traverse != check->tp_traverse
+ || probe_tp_clear != check->tp_clear
+ || probe_tp_weakrefoffset != typetype->tp_weaklistoffset
+ || probe_tp_iternext != check->tp_iternext
+ || probe_tp_methods != check->tp_methods
+ || probe_tp_getset != check->tp_getset
+ || probe_tp_base != typetype->tp_base
+ || !PyDict_Check(checkDict)
+ || !PyDict_GetItemString(checkDict, "dummy")
+ || probe_tp_descr_get != check->tp_descr_get
+ || probe_tp_descr_set != check->tp_descr_set
+ || probe_tp_dictoffset != typetype->tp_dictoffset
+ || probe_tp_init != check->tp_init
+ || probe_tp_alloc != check->tp_alloc
+ || probe_tp_new != check->tp_new
+ || probe_tp_free != check->tp_free
+ || probe_tp_is_gc != check->tp_is_gc
+ || probe_tp_bases != typetype->tp_bases
+ || probe_tp_mro != typetype->tp_mro
+ || Py_TPFLAGS_DEFAULT != (check->tp_flags & Py_TPFLAGS_DEFAULT))
+ Py_FatalError("The structure of type objects has changed!");
+ Py_DECREF(checkObj);
+ Py_DECREF(probe_tp_base_obj);
+ Py_DECREF(w);
+ Py_DECREF(d);
+ Py_DECREF(probe_tp_bases);
+ Py_DECREF(probe_tp_mro);
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Additional for object.h / class properties
+ *
+ */
+#ifdef Py_LIMITED_API
+/*
+ * This implementation of `_PyType_Lookup` works for lookup in our classes.
+ * The implementation ignores all caching and versioning and is also
+ * less optimized. This is reduced from the Python implementation.
+ */
+
+/* Internal API to look for a name through the MRO, bypassing the method cache.
+ This returns a borrowed reference, and might set an exception.
+ 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
+static PyObject *
+find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
+{
+ Py_ssize_t i, n;
+ PyObject *mro, *res, *base;
+
+ /* Look in tp_dict of types in MRO */
+ mro = type->tp_mro;
+
+ res = nullptr;
+ /* Keep a strong reference to mro because type->tp_mro can be replaced
+ during dict lookup, e.g. when comparing to non-string keys. */
+ Py_INCREF(mro);
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(mro, i);
+ assert(PyType_Check(base));
+ auto *type = reinterpret_cast<PyTypeObject *>(base);
+ Shiboken::AutoDecRef dict(PepType_GetDict(type));
+ assert(!dict.isNull() && PyDict_Check(dict.object()));
+ res = PyDict_GetItem(dict.object(), name);
+ if (res != nullptr)
+ break;
+ if (PyErr_Occurred()) {
+ *error = -1;
+ goto done;
+ }
+ }
+ *error = 0;
+done:
+ Py_DECREF(mro);
+ return res;
+}
+
+/* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PepType_Lookup(PyTypeObject *type, PyObject *name)
+{
+ PyObject *res;
+ int error;
+
+ /* We may end up clearing live exceptions below, so make sure it's ours. */
+ assert(!PyErr_Occurred());
+
+ res = find_name_in_mro(type, name, &error);
+ /* Only put NULL results into cache if there was no error. */
+ if (error) {
+ /* It's not ideal to clear the error condition,
+ but this function is documented as not setting
+ an exception, and I don't want to change that.
+ E.g., when PyType_Ready() can't proceed, it won't
+ set the "ready" flag, so future attempts to ready
+ the same type will call it again -- hopefully
+ in a context that propagates the exception out.
+ */
+ if (error == -1) {
+ PyErr_Clear();
+ }
+ return nullptr;
+ }
+ return res;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for unicodeobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// structs and macros modelled after their equivalents in
+// cpython/Include/cpython/unicodeobject.h
+
+struct PepASCIIObject // since 3.12
+{
+ PyObject_HEAD
+ Py_ssize_t length; /* Number of code points in the string */
+ Py_hash_t hash; /* Hash value; -1 if not set */
+ struct {
+ unsigned int interned:2;
+ unsigned int kind:3;
+ unsigned int compact:1;
+ unsigned int ascii:1;
+ unsigned int ready:1;
+ unsigned int :24;
+ } state;
+};
+
+struct PepASCIIObject_311 : public PepASCIIObject
+{
+ wchar_t *wstr; /* wchar_t representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject // since 3.12
+{
+ PepASCIIObject _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject_311 // since 3.12
+{
+ PepASCIIObject_311 _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+ Py_ssize_t wstr_length; /* Number of code points in wstr */
+};
+
+struct PepUnicodeObject // since 3.12
+{
+ PepCompactUnicodeObject _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+struct PepUnicodeObject_311
+{
+ PepCompactUnicodeObject_311 _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+int _PepUnicode_KIND(PyObject *str)
+{
+ return reinterpret_cast<PepASCIIObject *>(str)->state.kind;
+}
+
+int _PepUnicode_IS_ASCII(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.ascii;
+}
+
+int _PepUnicode_IS_COMPACT(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.compact;
+}
+
+static void *_PepUnicode_ASCII_DATA(PyObject *str)
+{
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *asciiObj_311 = reinterpret_cast<PepASCIIObject_311 *>(str);
+ return asciiObj_311 + 1;
+ }
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj + 1;
+}
+
+static void *_PepUnicode_COMPACT_DATA(PyObject *str)
+{
+ if (_PepUnicode_IS_ASCII(str) != 0)
+ return _PepUnicode_ASCII_DATA(str);
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *compactObj_311 = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ return compactObj_311 + 1;
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ return compactObj + 1;
+}
+
+static void *_PepUnicode_NONCOMPACT_DATA(PyObject *str)
+{
+ return _PepRuntimeVersion() < 0x030C00
+ ? reinterpret_cast<PepUnicodeObject_311 *>(str)->data.any
+ : reinterpret_cast<PepUnicodeObject *>(str)->data.any;
+}
+
+void *_PepUnicode_DATA(PyObject *str)
+{
+ return _PepUnicode_IS_COMPACT(str)
+ ? _PepUnicode_COMPACT_DATA(str) : _PepUnicode_NONCOMPACT_DATA(str);
+}
+
+// Fast path accessing UTF8 data without doing a conversion similar
+// to _PyUnicode_AsUTF8String
+static const char *utf8FastPath_311(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject_311 *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+static const char *utf8FastPath(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+const char *_PepUnicode_AsString(PyObject *str)
+{
+ /*
+ * This function is the surrogate for PyUnicode_AsUTF8, which keeps the data
+ * in the unicode object as long as that object exists.
+ *
+ * The function does too much if not optimized by utf8, because it keeps the
+ * string alive, unconditionally.
+ * We should not rely on this behavior and think of PyUnicode_AsUTF8, only.
+ */
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define AT __FILE__ ":" TOSTRING(__LINE__)
+
+ if (const auto *utf8 = _PepRuntimeVersion() < 0x030C00
+ ? utf8FastPath_311(str) : utf8FastPath(str)) {
+ return utf8;
+ }
+
+ static PyObject *cstring_dict = nullptr;
+ if (cstring_dict == nullptr) {
+ cstring_dict = PyDict_New();
+ if (cstring_dict == nullptr)
+ Py_FatalError("Error in " AT);
+ }
+ PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", nullptr);
+ PyObject *entry = PyDict_GetItemWithError(cstring_dict, bytesStr);
+ if (entry == nullptr) {
+ int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr);
+ if (e != 0)
+ Py_FatalError("Error in " AT);
+ entry = bytesStr;
+ }
+ else
+ Py_DECREF(bytesStr);
+ return PyBytes_AsString(entry);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pydebug.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+static PyObject *sys_flags = nullptr;
+
+int
+Pep_GetFlag(const char *name)
+{
+ static int initialized = 0;
+ int ret = -1;
+
+ if (!initialized) {
+ sys_flags = PySys_GetObject("flags");
+ // func gives no error if nullptr is returned and does not incref.
+ Py_XINCREF(sys_flags);
+ initialized = 1;
+ }
+ if (sys_flags != nullptr) {
+ PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ }
+ return ret;
+}
+
+int
+Pep_GetVerboseFlag()
+{
+ static int initialized = 0;
+ static int verbose_flag = -1;
+
+ if (!initialized) {
+ verbose_flag = Pep_GetFlag("verbose");
+ if (verbose_flag != -1)
+ initialized = 1;
+ }
+ return verbose_flag;
+}
+#endif // Py_LIMITED_API
+
+// Support for pyerrors.h
+
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+// Emulate PyErr_GetRaisedException() using the deprecated PyErr_Fetch()/PyErr_Store()
+PyObject *PepErr_GetRaisedException()
+{
+ PyObject *type{};
+ PyObject *value{};
+ PyObject *traceback{};
+ PyErr_Fetch(&type, &value, &traceback);
+ Py_XINCREF(value);
+ PyErr_Restore(type, value, traceback);
+ return value;
+}
+
+struct PepException_HEAD
+{
+ PyObject_HEAD
+ PyObject *x1; // dict
+ PyObject *args;
+};
+
+// PyException_GetArgs/PyException_SetArgs were added to the stable API in 3.12
+PyObject *PepException_GetArgs(PyObject *ex)
+{
+ auto *h = reinterpret_cast<PepException_HEAD *>(ex);
+ Py_XINCREF(h->args);
+ return h->args;
+}
+
+LIBSHIBOKEN_API void PepException_SetArgs(PyObject *ex, PyObject *args)
+{
+ auto *h = reinterpret_cast<PepException_HEAD *>(ex);
+ Py_XINCREF(args);
+ auto *old = h->args; // Py_XSETREF()
+ h->args = args;
+ Py_XDECREF(old);
+
+}
+#endif // Limited or < 3.12
+
+/*****************************************************************************
+ *
+ * Support for code.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+int
+PepCode_Get(PepCodeObject *co, const char *name)
+{
+ PyObject *ob = reinterpret_cast<PyObject *>(co);
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+int PepCode_Check(PyObject *o)
+{
+ return o != nullptr && std::strcmp(Py_TYPE(o)->tp_name, "code") == 0 ? 1 : 0;
+}
+
+#endif // Py_LIMITED_API
+
+#if defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+PyObject *PepFunction_GetDefaults(PyObject *function)
+{
+ auto *ob_ret = PyObject_GetAttrString(function, "__defaults__");
+ Py_XDECREF(ob_ret); // returns borrowed ref
+ return ob_ret != Py_None ? ob_ret : nullptr;
+}
+
+#endif // defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+
+/*****************************************************************************
+ *
+ * Support for datetime.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+datetime_struc *PyDateTimeAPI = nullptr;
+
+static PyTypeObject *dt_getCheck(const char *name)
+{
+ PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name);
+ if (op == nullptr) {
+ fprintf(stderr, "datetime.%s not found\n", name);
+ Py_FatalError("aborting");
+ }
+ return reinterpret_cast<PyTypeObject *>(op);
+}
+
+// init_DateTime is called earlier than our module init.
+// We use the provided PyDateTime_IMPORT machinery.
+datetime_struc *
+init_DateTime(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc));
+ if (PyDateTimeAPI == nullptr)
+ Py_FatalError("PyDateTimeAPI malloc error, aborting");
+ PyDateTimeAPI->module = PyImport_ImportModule("datetime");
+ if (PyDateTimeAPI->module == nullptr)
+ Py_FatalError("datetime module not found, aborting");
+ PyDateTimeAPI->DateType = dt_getCheck("date");
+ PyDateTimeAPI->DateTimeType = dt_getCheck("datetime");
+ PyDateTimeAPI->TimeType = dt_getCheck("time");
+ PyDateTimeAPI->DeltaType = dt_getCheck("timedelta");
+ PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo");
+ initialized = 1;
+ }
+ return PyDateTimeAPI;
+}
+
+int
+PyDateTime_Get(PyObject *ob, const char *name)
+{
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+PyObject *
+PyDate_FromDate(int year, int month, int day)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType,
+ (char *)"(iii)", year, month, day);
+}
+
+PyObject *
+PyDateTime_FromDateAndTime(int year, int month, int day,
+ int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType,
+ (char *)"(iiiiiii)", year, month, day,
+ hour, min, sec, usec);
+}
+
+PyObject *
+PyTime_FromTime(int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType,
+ (char *)"(iiii)", hour, min, sec, usec);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pythonrun.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// Flags are ignored in these simple helpers.
+PyObject *
+PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
+{
+ PyObject *code = Py_CompileString(str, "pyscript", start);
+ PyObject *ret = nullptr;
+
+ if (code != nullptr) {
+ ret = PyEval_EvalCode(code, globals, locals);
+ }
+ Py_XDECREF(code);
+ return ret;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for classobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepMethod_TypePtr = nullptr;
+
+static PyTypeObject *getMethodType(void)
+{
+ static const char prog[] =
+ "class _C:\n"
+ " def _m(self): pass\n"
+ "result = type(_C()._m)\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+// We have no access to PyMethod_New and must call types.MethodType, instead.
+PyObject *
+PyMethod_New(PyObject *func, PyObject *self)
+{
+ return PyObject_CallFunction((PyObject *)PepMethod_TypePtr,
+ (char *)"(OO)", func, self);
+}
+
+PyObject *
+PyMethod_Function(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::func());
+
+ // We have to return a borrowed reference.
+ Py_DECREF(ret);
+ return ret;
+}
+
+PyObject *
+PyMethod_Self(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::self());
+
+ // We have to return a borrowed reference.
+ // If we don't obey that here, then we get a test error!
+ Py_DECREF(ret);
+ return ret;
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for funcobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PepFunction_Get(PyObject *ob, const char *name)
+{
+ PyObject *ret;
+
+ // We have to return a borrowed reference.
+ ret = PyObject_GetAttrString(ob, name);
+ Py_XDECREF(ret);
+ return ret;
+}
+
+// This became necessary after Windows was activated.
+
+PyTypeObject *PepFunction_TypePtr = nullptr;
+
+static PyTypeObject *getFunctionType(void)
+{
+ static const char prog[] =
+ "from types import FunctionType as result\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+#endif // Py_LIMITED_API || Python 2
+
+/*****************************************************************************
+ *
+ * Support for dictobject.h
+ *
+ */
+
+/*****************************************************************************
+ *
+ * Extra support for signature.cpp
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepStaticMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getStaticMethodType(void)
+{
+ static const char prog[] =
+ "result = type(str.__dict__['maketrans'])\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *sm_callable;
+ PyObject *sm_dict;
+} staticmethod;
+
+PyObject *
+PyStaticMethod_New(PyObject *callable)
+{
+ staticmethod *sm = (staticmethod *)
+ PyType_GenericAlloc(PepStaticMethod_TypePtr, 0);
+ if (sm != nullptr) {
+ Py_INCREF(callable);
+ sm->sm_callable = callable;
+ }
+ return reinterpret_cast<PyObject *>(sm);
+}
+#endif // Py_LIMITED_API
+
+#ifdef PYPY_VERSION
+PyTypeObject *PepBuiltinMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getBuiltinMethodType(void)
+{
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ //
+ // There is no public declaration for the "builtin method" type.
+ // We also cannot grep it with a Python script since the import is too early.
+ // Pick a demo "builtin method" by using the VoidPtr type.
+ // Create the equivalent of
+ // "from shiboken6.Shiboken import VoidPtr\n"
+ // "result = type(VoidPtr(0).toBytes)\n";
+ auto *pyVoidP = reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF());
+ Shiboken::AutoDecRef arg(Py_BuildValue("i", 0));
+ Shiboken::AutoDecRef inst(PyObject_CallFunctionObjArgs(pyVoidP, arg.object(), nullptr));
+ Shiboken::AutoDecRef meth(PyObject_GetAttrString(inst, "toBytes"));
+ auto *result = reinterpret_cast<PyTypeObject *>(PyObject_Type(meth));
+ return result;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Common newly needed functions
+ *
+ */
+
+// The introduction of heaptypes converted many type names to the
+// dotted form, since PyType_FromSpec uses it to compute the module
+// name. This function reverts this effect.
+const char *
+PepType_GetNameStr(PyTypeObject *type)
+{
+ const char *ret = type->tp_name;
+ const char *nodots = std::strrchr(ret, '.');
+ if (nodots)
+ ret = nodots + 1;
+ return ret;
+}
+
+// PYSIDE-2264: Find the _functools or functools module and retrieve the
+// partial function. This can be tampered with, check carefully.
+PyObject *
+Pep_GetPartialFunction(void)
+{
+ static bool initialized = false;
+ static PyObject *result{};
+ if (initialized) {
+ Py_INCREF(result);
+ return result;
+ }
+ auto *functools = PyImport_ImportModule("_functools");
+ if (!functools) {
+ PyErr_Clear();
+ functools = PyImport_ImportModule("functools");
+ }
+ if (!functools)
+ Py_FatalError("functools cannot be found");
+ result = PyObject_GetAttrString(functools, "partial");
+ if (!result || !PyCallable_Check(result))
+ Py_FatalError("partial not found or not a function");
+ initialized = true;
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Newly introduced convenience functions
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PyImport_GetModule(PyObject *name)
+{
+ PyObject *m;
+ PyObject *modules = PyImport_GetModuleDict();
+ if (modules == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
+ return NULL;
+ }
+ Py_INCREF(modules);
+ if (PyDict_CheckExact(modules)) {
+ m = PyDict_GetItemWithError(modules, name); /* borrowed */
+ Py_XINCREF(m);
+ }
+ else {
+ m = PyObject_GetItem(modules, name);
+ if (m == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ }
+ }
+ Py_DECREF(modules);
+ return m;
+}
+
+#endif // Py_LIMITED_API
+
+// 2020-06-16: For simplicity of creating arbitrary things, this function
+// is now made public.
+
+PyObject *
+PepRun_GetResult(const char *command)
+{
+ /*
+ * Evaluate a string and return the variable `result`
+ */
+ PyObject *d, *v, *res;
+
+ d = PyDict_New();
+ if (d == nullptr
+ || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) {
+ return nullptr;
+ }
+ v = PyRun_String(command, Py_file_input, d, d);
+ res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr;
+ Py_XDECREF(v);
+ Py_DECREF(d);
+ return res;
+}
+
+PyTypeObject *PepType_Type_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ auto ret = PyType_Type.tp_new(metatype, args, kwds);
+ return reinterpret_cast<PyTypeObject *>(ret);
+}
+
+/*****************************************************************************
+ *
+ * Extra support for name mangling
+ *
+ */
+
+#ifdef Py_LIMITED_API
+// We keep these definitions local, because they don't work in Python 2.
+# define PyUnicode_GET_LENGTH(op) PyUnicode_GetLength((PyObject *)(op))
+# define PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar((PyObject *)(u), (i))
+#endif // Py_LIMITED_API
+
+PyObject *
+_Pep_PrivateMangle(PyObject *self, PyObject *name)
+{
+ /*
+ * Name mangling: __private becomes _classname__private.
+ * This function is modelled after _Py_Mangle, but is optimized
+ * a little for our purpose.
+ */
+ if (PyUnicode_READ_CHAR(name, 0) != '_' ||
+ PyUnicode_READ_CHAR(name, 1) != '_') {
+ Py_INCREF(name);
+ return name;
+ }
+ size_t nlen = PyUnicode_GET_LENGTH(name);
+ /* Don't mangle __id__ or names with dots. */
+ if ((PyUnicode_READ_CHAR(name, nlen-1) == '_' &&
+ PyUnicode_READ_CHAR(name, nlen-2) == '_') ||
+ PyUnicode_FindChar(name, '.', 0, nlen, 1) != -1) {
+ Py_INCREF(name);
+ return name;
+ }
+ Shiboken::AutoDecRef privateobj(PyObject_GetAttr(
+ reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name()));
+
+ // PYSIDE-1436: _Py_Mangle is no longer exposed; implement it always.
+ // The rest of this function is our own implementation of _Py_Mangle.
+ // Please compare the original function in compile.c .
+ size_t plen = PyUnicode_GET_LENGTH(privateobj.object());
+ /* Strip leading underscores from class name */
+ size_t ipriv = 0;
+ while (PyUnicode_READ_CHAR(privateobj.object(), ipriv) == '_')
+ ipriv++;
+ if (ipriv == plen) {
+ Py_INCREF(name);
+ return name; /* Don't mangle if class is just underscores */
+ }
+ plen -= ipriv;
+
+ if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
+ PyErr_SetString(PyExc_OverflowError,
+ "private identifier too large to be mangled");
+ return nullptr;
+ }
+ size_t const amount = ipriv + 1 + plen + nlen;
+ size_t const big_stack = 1000;
+ wchar_t bigbuf[big_stack];
+ wchar_t *resbuf = amount <= big_stack ? bigbuf : (wchar_t *)malloc(sizeof(wchar_t) * amount);
+ if (!resbuf)
+ return nullptr;
+ /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */
+ resbuf[0] = '_';
+ if (PyUnicode_AsWideChar(privateobj, resbuf + 1, ipriv + plen) < 0)
+ return nullptr;
+ if (PyUnicode_AsWideChar(name, resbuf + ipriv + plen + 1, nlen) < 0)
+ return nullptr;
+ PyObject *result = PyUnicode_FromWideChar(resbuf + ipriv, 1 + plen + nlen);
+ if (amount > big_stack)
+ free(resbuf);
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.8 incompatibilities
+ *
+ */
+
+int PepRuntime_38_flag = 0;
+
+static void
+init_PepRuntime()
+{
+ // We expect a string of the form "\d\.\d+\."
+ const char *version = Py_GetVersion();
+ if (version[0] < '3')
+ return;
+ if (std::atoi(version + 2) >= 8)
+ PepRuntime_38_flag = 1;
+}
+
+static long _GetPepRuntimeVersion()
+{
+ auto *version = PySys_GetObject("version_info");
+ const auto major = PyLong_AsLong(PyTuple_GetItem(version, 0));
+ const auto minor = PyLong_AsLong(PyTuple_GetItem(version, 1));
+ const auto micro = PyLong_AsLong(PyTuple_GetItem(version, 2));
+ return major << 16 | minor << 8 | micro;
+}
+
+long _PepRuntimeVersion()
+{
+ static const auto number = _GetPepRuntimeVersion();
+ return number;
+}
+
+/*****************************************************************************
+ *
+ * PYSIDE-535: Support for PyPy
+ *
+ * This has the nice side effect of a more clean implementation,
+ * and we don't keep the old macro version.
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+//
+// PEP 697: Support for embedded type structures.
+//
+// According to `https://docs.python.org/3/c-api/object.html?highlight=pyobject_gettypedata#c.PyObject_GetTypeData`
+// the function `PyObject_GetTypeData` should belong to the Stable API
+// since version 3.12.0, but it does not. We use instead some copies
+// from Python source code.
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+# define PepObject_GetTypeData PyObject_GetTypeData
+
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
+{
+ // PYSIDE-2676: Use the meta type explicitly.
+ // A derived type would fail the offset calculation.
+ static auto *meta = SbkObjectType_TypeF();
+ assert(SbkObjectType_Check(type));
+ auto *obType = reinterpret_cast<PyObject *>(type);
+ void *data = PyObject_GetTypeData(obType, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+}
+
+void PepType_SOTP_delete(PyTypeObject * /*type*/)
+{
+}
+
+#else
+
+// The following comments are directly copied from Python 3.12
+//
+
+// Make sure we have maximum alignment, even if the current compiler
+// does not support max_align_t. Note that:
+// - Autoconf reports alignment of unknown types to 0.
+// - 'long double' has maximum alignment on *most* platforms,
+// looks like the best we can do for pre-C11 compilers.
+// - The value is tested, see test_alignof_max_align_t
+# if !defined(ALIGNOF_MAX_ALIGN_T) || ALIGNOF_MAX_ALIGN_T == 0
+# undef ALIGNOF_MAX_ALIGN_T
+# define ALIGNOF_MAX_ALIGN_T alignof(long double)
+# endif
+
+/* Align up to the nearest multiple of alignof(max_align_t)
+ * (like _Py_ALIGN_UP, but for a size rather than pointer)
+ */
+static Py_ssize_t _align_up(Py_ssize_t size)
+{
+ return (size + ALIGNOF_MAX_ALIGN_T - 1) & ~(ALIGNOF_MAX_ALIGN_T - 1);
+}
+
+static void *PepObject_GetTypeData(PyObject *obj, PyTypeObject *cls)
+{
+ assert(PyObject_TypeCheck(obj, cls));
+ return reinterpret_cast<char *>(obj) + _align_up(cls->tp_base->tp_basicsize);
+}
+//
+///////////////////////////////////////////////////////////////////////
+
+/*
+ * PyTypeObject extender
+ */
+
+static std::unordered_map<PyTypeObject *, SbkObjectTypePrivate > SOTP_extender{};
+static thread_local PyTypeObject *SOTP_key{};
+static thread_local SbkObjectTypePrivate *SOTP_value{};
+
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
+{
+ static auto *meta = SbkObjectType_TypeF();
+ static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+ assert(SbkObjectType_Check(type));
+ if (use_312) {
+ auto *obType = reinterpret_cast<PyObject *>(type);
+ void *data = PepObject_GetTypeData(obType, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+ }
+ if (type == SOTP_key)
+ return SOTP_value;
+ auto it = SOTP_extender.find(type);
+ if (it == SOTP_extender.end()) {
+ it = SOTP_extender.insert({type, {}}).first;
+ memset(&it->second, 0, sizeof(SbkObjectTypePrivate));
+ }
+ SOTP_key = type;
+ SOTP_value = &it->second;
+ return SOTP_value;
+}
+
+void PepType_SOTP_delete(PyTypeObject *type)
+{
+ static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+ assert(SbkObjectType_Check(type));
+ if (use_312)
+ return;
+ SOTP_extender.erase(type);
+ SOTP_key = nullptr;
+}
+
+#endif // !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+/*
+ * SbkEnumType extender
+ */
+static std::unordered_map<SbkEnumType *, SbkEnumTypePrivate> SETP_extender{};
+static thread_local SbkEnumType *SETP_key{};
+static thread_local SbkEnumTypePrivate *SETP_value{};
+
+SbkEnumTypePrivate *PepType_SETP(SbkEnumType *enumType)
+{
+ // PYSIDE-2230: This makes no sense at all for Enum types.
+ if (enumType == SETP_key)
+ return SETP_value;
+ auto it = SETP_extender.find(enumType);
+ if (it == SETP_extender.end()) {
+ it = SETP_extender.insert({enumType, {}}).first;
+ memset(&it->second, 0, sizeof(SbkEnumTypePrivate));
+ }
+ SETP_key = enumType;
+ SETP_value = &it->second;
+ return SETP_value;
+}
+
+void PepType_SETP_delete(SbkEnumType *enumType)
+{
+ SETP_extender.erase(enumType);
+ SETP_key = nullptr;
+}
+
+#ifdef Py_LIMITED_API
+static PyObject *emulatePyType_GetDict(PyTypeObject *type)
+{
+ if (_PepRuntimeVersion() < 0x030C00 || type->tp_dict) {
+ auto *res = type->tp_dict;
+ Py_XINCREF(res);
+ return res;
+ }
+ // PYSIDE-2230: Here we are really cheating. We don't know how to
+ // access an internal dict, and so we simply pretend
+ // it were an empty dict. This works great for our types.
+ // This was an unexpectedly simple solution :D
+ return PyDict_New();
+}
+#endif
+
+// PyType_GetDict: replacement for <static type>.tp_dict, which is
+// zero for builtin types since 3.12.
+PyObject *PepType_GetDict(PyTypeObject *type)
+{
+#if !defined(Py_LIMITED_API)
+# if PY_VERSION_HEX >= 0x030C0000
+ return PyType_GetDict(type);
+# else
+ // pre 3.12 fallback code, mimicking the addref-behavior.
+ Py_XINCREF(type->tp_dict);
+ return type->tp_dict;
+# endif
+#else
+ return emulatePyType_GetDict(type);
+#endif // Py_LIMITED_API
+}
+
+int PepType_SetDict(PyTypeObject *type, PyObject *dict)
+{
+ type->tp_dict = dict;
+ return 0;
+}
+
+// Pre 3.10, PyType_GetSlot() would only work for heap types.
+// FIXME: PyType_GetSlot() can be used unconditionally when the
+// minimum limited API version is >= 3.10.
+void *PepType_GetSlot(PyTypeObject *type, int aSlot)
+{
+ static const bool is310 = _PepRuntimeVersion() >= 0x030A00;
+ if (is310 || (type->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0)
+ return PyType_GetSlot(type, aSlot);
+
+ switch (aSlot) {
+ case Py_tp_alloc:
+ return reinterpret_cast<void *>(type->tp_alloc);
+ case Py_tp_getattro:
+ return reinterpret_cast<void *>(type->tp_getattro);
+ case Py_tp_setattro:
+ return reinterpret_cast<void *>(type->tp_setattro);
+ case Py_tp_descr_get:
+ return reinterpret_cast<void *>(type->tp_descr_get);
+ case Py_tp_descr_set:
+ return reinterpret_cast<void *>(type->tp_descr_set);
+ case Py_tp_call:
+ return reinterpret_cast<void *>(type->tp_call);
+ case Py_tp_new:
+ return reinterpret_cast<void *>(type->tp_new);
+ case Py_tp_init:
+ return reinterpret_cast<void *>(type->tp_init);
+ case Py_tp_free:
+ return reinterpret_cast<void *>(type->tp_free);
+ }
+ assert(false);
+ return nullptr;
+}
+
+/***************************************************************************
+ *
+ * PYSIDE-535: The enum/flag error
+ * -------------------------------
+ *
+ * This is a fragment of the code which was used to find the enum/flag
+ * alias error. See the change to `setTypeConverter` in sbkenum.cpp .
+ *
+
+Usage:
+
+python3 -c "from PySide6 import QtCore" 2>&1 | python3 tools/debug_renamer.py | uniq -c | head -10
+
+ 5 PepType_ExTP:940 x_A SOTP s=96
+ 4 PepType_ExTP:940 x_B SETP s=24
+ 2 PepType_ExTP:940 x_C PFTP s=16
+ 4 PepType_ExTP:940 x_D SETP s=24
+ 1 PepType_ExTP:940 x_C SETP s=24
+ 2 PepType_ExTP:940 x_E PFTP s=16
+ 4 PepType_ExTP:940 x_F SETP s=24
+ 1 PepType_ExTP:940 x_E SETP s=24
+ 4 PepType_ExTP:940 x_G SETP s=24
+ 4 PepType_ExTP:940 x_H SETP s=24
+
+static inline void *PepType_ExTP(PyTypeObject *type, size_t size)
+{
+ static const char *env_p = std::getenv("PFTP");
+ if (env_p) {
+ static PyTypeObject *alias{};
+ const char *kind = size == sizeof(SbkObjectTypePrivate) ? "SOTP" :
+ size == sizeof(SbkEnumTypePrivate) ? "SETP" :
+ size == sizeof(SbkQFlagsTypePrivate) ? "PFTP" :
+ "unk.";
+ fprintf(stderr, "%s:%d %p x %s s=%ld\n", __func__, __LINE__, type, kind, size);
+ PyObject *kill{};
+ if (strlen(env_p) > 0) {
+ if (size == sizeof(SbkQFlagsTypePrivate)) {
+ if (alias == nullptr)
+ alias = type;
+ }
+ if (size != sizeof(SbkQFlagsTypePrivate)) {
+ if (type == alias)
+ Py_INCREF(kill);
+ }
+ }
+ }
+ const auto ikey = reinterpret_cast<std::uintptr_t>(type);
+ if (ikey == cached_key)
+ return cached_value;
+ auto it = SOTP_extender.find(ikey);
+ if (it == SOTP_extender.end()) {
+ PepType_ExTP_init(type, size);
+ return PepType_ExTP(type, size);
+ }
+ cached_key = ikey;
+ cached_value = reinterpret_cast<void *>(it->second);
+ return cached_value;
+}
+*/
+
+/*****************************************************************************
+ *
+ * Module Initialization
+ *
+ */
+
+void
+Pep384_Init()
+{
+ init_PepRuntime();
+#ifdef Py_LIMITED_API
+ check_PyTypeObject_valid();
+ Pep_GetVerboseFlag();
+ PepMethod_TypePtr = getMethodType();
+ PepFunction_TypePtr = getFunctionType();
+ PepStaticMethod_TypePtr = getStaticMethodType();
+#endif // Py_LIMITED_API
+#ifdef PYPY_VERSION
+ PepBuiltinMethod_TypePtr = getBuiltinMethodType();
+#endif
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h
new file mode 100644
index 000000000..7188366e2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384impl.h
@@ -0,0 +1,611 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PEP384IMPL_H
+#define PEP384IMPL_H
+
+extern "C"
+{
+
+/*****************************************************************************
+ *
+ * RESOLVED: memoryobject.h
+ *
+ */
+
+// Extracted into bufferprocs27.h
+#ifdef Py_LIMITED_API
+#include "bufferprocs_py37.h"
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: object.h
+ *
+ */
+#ifdef Py_LIMITED_API
+// Why the hell is this useful debugging function not allowed?
+// BTW: When used, it breaks on Windows, intentionally!
+LIBSHIBOKEN_API void _PyObject_Dump(PyObject *);
+#endif
+
+/*
+ * There are a few structures that are needed, but cannot be used without
+ * breaking the API. We use some heuristics to get those fields anyway
+ * and validate that we really found them, see pep384impl.cpp .
+ */
+
+#ifdef Py_LIMITED_API
+
+/*
+ * These are the type object fields that we use.
+ * We will verify that they never change.
+ * The unused fields are intentionally named as "void *Xnn" because
+ * the chance is smaller to forget to validate a field.
+ * When we need more fields, we replace it back and add it to the
+ * validation.
+ */
+typedef struct _typeobject {
+ PyVarObject ob_base;
+ const char *tp_name;
+ Py_ssize_t tp_basicsize;
+ void *X03; // Py_ssize_t tp_itemsize;
+#ifdef PEP384_INTERN
+ destructor tp_dealloc;
+#else
+ destructor X04;
+#endif
+ void *X05; // Py_ssize_t tp_vectorcall_offset;
+ void *X06; // getattrfunc tp_getattr;
+ void *X07; // setattrfunc tp_setattr;
+ void *X08; // PyAsyncMethods *tp_as_async;
+#ifdef PEP384_INTERN
+ reprfunc tp_repr;
+#else
+ reprfunc X09;
+#endif
+ void *X10; // PyNumberMethods *tp_as_number;
+ void *X11; // PySequenceMethods *tp_as_sequence;
+ void *X12; // PyMappingMethods *tp_as_mapping;
+ void *X13; // hashfunc tp_hash;
+#ifdef PEP384_INTERN
+ ternaryfunc tp_call;
+#else
+ ternaryfunc X14;
+#endif
+ reprfunc tp_str; // Only used for PEP384_INTERN and a shiboken test
+ getattrofunc tp_getattro;
+ setattrofunc tp_setattro;
+ void *X18; // PyBufferProcs *tp_as_buffer;
+ unsigned long tp_flags;
+ void *X20; // const char *tp_doc;
+#ifdef PEP384_INTERN
+ traverseproc tp_traverse;
+ inquiry tp_clear;
+#else
+ traverseproc X21;
+ inquiry X22;
+#endif
+ void *X23; // richcmpfunc tp_richcompare;
+ Py_ssize_t tp_weaklistoffset;
+ void *X25; // getiterfunc tp_iter;
+#ifdef PEP384_INTERN
+ iternextfunc tp_iternext;
+#else
+ iternextfunc X26;
+#endif
+ struct PyMethodDef *tp_methods;
+ struct PyMemberDef *tp_members;
+ struct PyGetSetDef *tp_getset;
+ struct _typeobject *tp_base;
+#ifdef PEP384_INTERN
+ PyObject *tp_dict;
+ descrgetfunc tp_descr_get;
+ descrsetfunc tp_descr_set;
+#else
+ void *X31;
+ descrgetfunc X32;
+ descrsetfunc X33;
+#endif
+ Py_ssize_t tp_dictoffset;
+#ifdef PEP384_INTERN
+ initproc tp_init;
+ allocfunc tp_alloc;
+#else
+ initproc X39;
+ allocfunc X40;
+#endif
+ newfunc tp_new;
+#ifdef PEP384_INTERN
+ freefunc tp_free;
+ inquiry tp_is_gc; /* For PyObject_IS_GC */
+#else
+ freefunc X41;
+ inquiry X42; /* For PyObject_IS_GC */
+#endif
+ PyObject *tp_bases;
+ PyObject *tp_mro; /* method resolution order */
+
+} PyTypeObject;
+
+#ifndef PyObject_IS_GC
+/* Test if an object has a GC head */
+#define PyObject_IS_GC(o) \
+ (PyType_IS_GC(Py_TYPE(o)) \
+ && (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
+#endif
+
+LIBSHIBOKEN_API PyObject *_PepType_Lookup(PyTypeObject *type, PyObject *name);
+
+#else // Py_LIMITED_API
+
+#define _PepType_Lookup(type, name) _PyType_Lookup(type, name)
+
+#endif // Py_LIMITED_API
+
+/// PYSIDE-939: We need the runtime version, given major << 16 + minor << 8 + micro
+LIBSHIBOKEN_API long _PepRuntimeVersion();
+/*****************************************************************************
+ *
+ * PYSIDE-535: Implement a clean type extension for PyPy
+ *
+ */
+
+struct SbkObjectTypePrivate;
+
+LIBSHIBOKEN_API SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type);
+LIBSHIBOKEN_API void PepType_SOTP_delete(PyTypeObject *type);
+
+struct SbkEnumType;
+struct SbkEnumTypePrivate;
+
+LIBSHIBOKEN_API SbkEnumTypePrivate *PepType_SETP(SbkEnumType *type);
+LIBSHIBOKEN_API void PepType_SETP_delete(SbkEnumType *enumType);
+
+struct PySideQFlagsType;
+struct SbkQFlagsTypePrivate;
+
+/*****************************************************************************/
+
+// functions used everywhere
+LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type);
+
+LIBSHIBOKEN_API PyObject *Pep_GetPartialFunction(void);
+
+/*****************************************************************************
+ *
+ * RESOLVED: pydebug.h
+ *
+ */
+#ifdef Py_LIMITED_API
+/*
+ * We have no direct access to Py_VerboseFlag because debugging is not
+ * supported. The python developers are partially a bit too rigorous.
+ * Instead, we compute the value and use a function call macro.
+ * Was before: extern LIBSHIBOKEN_API int Py_VerboseFlag;
+ */
+LIBSHIBOKEN_API int Pep_GetFlag(const char *name);
+LIBSHIBOKEN_API int Pep_GetVerboseFlag(void);
+#endif
+
+// pyerrors.h
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+LIBSHIBOKEN_API PyObject *PepErr_GetRaisedException();
+LIBSHIBOKEN_API PyObject *PepException_GetArgs(PyObject *ex);
+LIBSHIBOKEN_API void PepException_SetArgs(PyObject *ex, PyObject *args);
+#else
+# define PepErr_GetRaisedException PyErr_GetRaisedException
+# define PepException_GetArgs PyException_GetArgs
+# define PepException_SetArgs PyException_SetArgs
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: unicodeobject.h
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-813: About The Length Of Unicode Objects
+// -----------------------------------------------
+//
+// In Python 2 and before Python 3.3, the macro PyUnicode_GET_SIZE
+// worked fine and really like a macro.
+//
+// Meanwhile, the unicode objects have changed their layout very much,
+// and the former cheap macro call has become a real function call
+// that converts objects and needs PyMemory.
+//
+// That is not only inefficient, but also requires the GIL!
+// This problem was visible by debug Python and qdatastream_test.py .
+// It was found while fixing the refcount problem of PYSIDE-813 which
+// needed a debug Python.
+//
+
+// PyUnicode_GetSize is deprecated in favor of PyUnicode_GetLength.
+#define PepUnicode_GetLength(op) PyUnicode_GetLength((PyObject *)(op))
+
+// Unfortunately, we cannot ask this at runtime
+// #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
+// FIXME: Python 3.10: Replace _PepUnicode_AsString by PyUnicode_AsUTF8
+#ifdef Py_LIMITED_API
+
+LIBSHIBOKEN_API const char *_PepUnicode_AsString(PyObject *);
+
+enum PepUnicode_Kind {
+#if PY_VERSION_HEX < 0x030C0000
+ PepUnicode_WCHAR_KIND = 0,
+#endif
+ PepUnicode_1BYTE_KIND = 1,
+ PepUnicode_2BYTE_KIND = 2,
+ PepUnicode_4BYTE_KIND = 4
+};
+
+LIBSHIBOKEN_API int _PepUnicode_KIND(PyObject *);
+LIBSHIBOKEN_API int _PepUnicode_IS_ASCII(PyObject *str);
+LIBSHIBOKEN_API int _PepUnicode_IS_COMPACT(PyObject *str);
+
+LIBSHIBOKEN_API void *_PepUnicode_DATA(PyObject *str);
+
+#else
+
+enum PepUnicode_Kind {
+#if PY_VERSION_HEX < 0x030C0000
+ PepUnicode_WCHAR_KIND = PyUnicode_WCHAR_KIND,
+#endif
+ PepUnicode_1BYTE_KIND = PyUnicode_1BYTE_KIND,
+ PepUnicode_2BYTE_KIND = PyUnicode_2BYTE_KIND,
+ PepUnicode_4BYTE_KIND = PyUnicode_4BYTE_KIND
+};
+
+#define _PepUnicode_AsString PyUnicode_AsUTF8
+#define _PepUnicode_KIND PyUnicode_KIND
+#define _PepUnicode_DATA PyUnicode_DATA
+#define _PepUnicode_IS_COMPACT PyUnicode_IS_COMPACT
+#define _PepUnicode_IS_ASCII PyUnicode_IS_ASCII
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: bytesobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyBytes_AS_STRING(op) PyBytes_AsString(op)
+#define PyBytes_GET_SIZE(op) PyBytes_Size(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: floatobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyFloat_AS_DOUBLE(op) PyFloat_AsDouble(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: tupleobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyTuple_GET_ITEM(op, i) PyTuple_GetItem((PyObject *)op, i)
+#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem(op, i, v)
+#define PyTuple_GET_SIZE(op) PyTuple_Size((PyObject *)op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: listobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyList_GET_ITEM(op, i) PyList_GetItem(op, i)
+#define PyList_SET_ITEM(op, i, v) PyList_SetItem(op, i, v)
+#define PyList_GET_SIZE(op) PyList_Size(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: methodobject.h
+ *
+ */
+
+#ifdef Py_LIMITED_API
+
+using PyCFunctionObject = struct _pycfunc;
+#define PyCFunction_GET_FUNCTION(func) PyCFunction_GetFunction((PyObject *)func)
+#define PyCFunction_GET_SELF(func) PyCFunction_GetSelf((PyObject *)func)
+#define PyCFunction_GET_FLAGS(func) PyCFunction_GetFlags((PyObject *)func)
+#define PepCFunction_GET_NAMESTR(func) \
+ _PepUnicode_AsString(PyObject_GetAttrString((PyObject *)func, "__name__"))
+#else
+#define PepCFunction_GET_NAMESTR(func) ((func)->m_ml->ml_name)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: pythonrun.h
+ *
+ */
+#ifdef Py_LIMITED_API
+LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *);
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: abstract.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// This definition breaks the limited API a little, because it re-enables the
+// buffer functions.
+// But this is no problem as we check it's validity for every version.
+
+// PYSIDE-1960 The buffer interface is since Python 3.11 part of the stable
+// API and we do not need to check the compatibility by hand anymore.
+
+typedef struct {
+ getbufferproc bf_getbuffer;
+ releasebufferproc bf_releasebuffer;
+} PyBufferProcs;
+
+typedef struct _Pepbuffertype {
+ PyVarObject ob_base;
+ void *skip[17];
+ PyBufferProcs *tp_as_buffer;
+} PepBufferType;
+
+#define PepType_AS_BUFFER(type) \
+ reinterpret_cast<PepBufferType *>(type)->tp_as_buffer
+
+#define PyObject_CheckBuffer(obj) \
+ ((PepType_AS_BUFFER(Py_TYPE(obj)) != NULL) && \
+ (PepType_AS_BUFFER(Py_TYPE(obj))->bf_getbuffer != NULL))
+
+LIBSHIBOKEN_API int PyObject_GetBuffer(PyObject *ob, Pep_buffer *view, int flags);
+LIBSHIBOKEN_API void PyBuffer_Release(Pep_buffer *view);
+
+#else
+
+#define Pep_buffer Py_buffer
+#define PepType_AS_BUFFER(type) ((type)->tp_as_buffer)
+
+#endif /* Py_LIMITED_API */
+
+/*****************************************************************************
+ *
+ * RESOLVED: funcobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+typedef struct _func PyFunctionObject;
+
+extern LIBSHIBOKEN_API PyTypeObject *PepFunction_TypePtr;
+LIBSHIBOKEN_API PyObject *PepFunction_Get(PyObject *, const char *);
+
+#define PyFunction_Check(op) (Py_TYPE(op) == PepFunction_TypePtr)
+#define PyFunction_GET_CODE(func) PyFunction_GetCode(func)
+
+#define PyFunction_GetCode(func) PepFunction_Get((PyObject *)func, "__code__")
+#define PepFunction_GetName(func) PepFunction_Get((PyObject *)func, "__name__")
+#else
+#define PepFunction_TypePtr (&PyFunction_Type)
+#define PepFunction_GetName(func) (((PyFunctionObject *)func)->func_name)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: classobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+typedef struct _meth PyMethodObject;
+
+extern LIBSHIBOKEN_API PyTypeObject *PepMethod_TypePtr;
+
+LIBSHIBOKEN_API PyObject *PyMethod_New(PyObject *, PyObject *);
+LIBSHIBOKEN_API PyObject *PyMethod_Function(PyObject *);
+LIBSHIBOKEN_API PyObject *PyMethod_Self(PyObject *);
+
+#define PyMethod_Check(op) ((op)->ob_type == PepMethod_TypePtr)
+
+#define PyMethod_GET_SELF(op) PyMethod_Self(op)
+#define PyMethod_GET_FUNCTION(op) PyMethod_Function(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: code.h
+ *
+ */
+#ifdef Py_LIMITED_API
+/* Bytecode object */
+
+// we have to grab the code object from python
+typedef struct _code PepCodeObject;
+
+LIBSHIBOKEN_API int PepCode_Get(PepCodeObject *co, const char *name);
+LIBSHIBOKEN_API int PepCode_Check(PyObject *o);
+
+# define PepCode_GET_FLAGS(o) PepCode_Get(o, "co_flags")
+# define PepCode_GET_ARGCOUNT(o) PepCode_Get(o, "co_argcount")
+
+LIBSHIBOKEN_API PyObject *PepFunction_GetDefaults(PyObject *function);
+
+/* Masks for co_flags above */
+# define CO_OPTIMIZED 0x0001
+# define CO_NEWLOCALS 0x0002
+# define CO_VARARGS 0x0004
+# define CO_VARKEYWORDS 0x0008
+# define CO_NESTED 0x0010
+# define CO_GENERATOR 0x0020
+
+#else
+
+# define PepCodeObject PyCodeObject
+# define PepCode_GET_FLAGS(o) ((o)->co_flags)
+# define PepCode_GET_ARGCOUNT(o) ((o)->co_argcount)
+# define PepCode_Check PyCode_Check
+
+# ifdef PYPY_VERSION
+
+LIBSHIBOKEN_API PyObject *PepFunction_GetDefaults(PyObject *function);
+
+# else
+# define PepFunction_GetDefaults PyFunction_GetDefaults
+# endif
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: datetime.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+LIBSHIBOKEN_API int PyDateTime_Get(PyObject *ob, const char *name);
+
+#define PyDateTime_GetYear(o) PyDateTime_Get(o, "year")
+#define PyDateTime_GetMonth(o) PyDateTime_Get(o, "month")
+#define PyDateTime_GetDay(o) PyDateTime_Get(o, "day")
+#define PyDateTime_GetHour(o) PyDateTime_Get(o, "hour")
+#define PyDateTime_GetMinute(o) PyDateTime_Get(o, "minute")
+#define PyDateTime_GetSecond(o) PyDateTime_Get(o, "second")
+#define PyDateTime_GetMicrosecond(o) PyDateTime_Get(o, "microsecond")
+#define PyDateTime_GetFold(o) PyDateTime_Get(o, "fold")
+
+#define PyDateTime_GET_YEAR(o) PyDateTime_GetYear(o)
+#define PyDateTime_GET_MONTH(o) PyDateTime_GetMonth(o)
+#define PyDateTime_GET_DAY(o) PyDateTime_GetDay(o)
+
+#define PyDateTime_DATE_GET_HOUR(o) PyDateTime_GetHour(o)
+#define PyDateTime_DATE_GET_MINUTE(o) PyDateTime_GetMinute(o)
+#define PyDateTime_DATE_GET_SECOND(o) PyDateTime_GetSecond(o)
+#define PyDateTime_DATE_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o)
+#define PyDateTime_DATE_GET_FOLD(o) PyDateTime_GetFold(o)
+
+#define PyDateTime_TIME_GET_HOUR(o) PyDateTime_GetHour(o)
+#define PyDateTime_TIME_GET_MINUTE(o) PyDateTime_GetMinute(o)
+#define PyDateTime_TIME_GET_SECOND(o) PyDateTime_GetSecond(o)
+#define PyDateTime_TIME_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o)
+#define PyDateTime_TIME_GET_FOLD(o) PyDateTime_GetFold(o)
+
+/* Define structure slightly similar to C API. */
+typedef struct {
+ PyObject *module;
+ /* type objects */
+ PyTypeObject *DateType;
+ PyTypeObject *DateTimeType;
+ PyTypeObject *TimeType;
+ PyTypeObject *DeltaType;
+ PyTypeObject *TZInfoType;
+} datetime_struc;
+
+LIBSHIBOKEN_API datetime_struc *init_DateTime(void);
+
+#define PyDateTime_IMPORT PyDateTimeAPI = init_DateTime()
+
+extern LIBSHIBOKEN_API datetime_struc *PyDateTimeAPI;
+
+#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)
+#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType)
+#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType)
+
+LIBSHIBOKEN_API PyObject *PyDate_FromDate(int year, int month, int day);
+LIBSHIBOKEN_API PyObject *PyDateTime_FromDateAndTime(
+ int year, int month, int day, int hour, int min, int sec, int usec);
+LIBSHIBOKEN_API PyObject *PyTime_FromTime(
+ int hour, int minute, int second, int usecond);
+
+#endif /* Py_LIMITED_API */
+
+/*****************************************************************************
+ *
+ * Extra support for name mangling
+ *
+ */
+
+// PYSIDE-772: This function supports the fix, but is not meant as public.
+LIBSHIBOKEN_API PyObject *_Pep_PrivateMangle(PyObject *self, PyObject *name);
+
+/*****************************************************************************
+ *
+ * Extra support for signature.cpp
+ *
+ */
+
+#ifdef Py_LIMITED_API
+extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr;
+LIBSHIBOKEN_API PyObject *PyStaticMethod_New(PyObject *callable);
+#else
+#define PepStaticMethod_TypePtr &PyStaticMethod_Type
+#endif
+
+#ifdef PYPY_VERSION
+extern LIBSHIBOKEN_API PyTypeObject *PepBuiltinMethod_TypePtr;
+#endif
+
+// Although not PEP specific, we resolve this similar issue, here:
+#define PepMethodDescr_TypePtr &PyMethodDescr_Type
+
+/*****************************************************************************
+ *
+ * Newly introduced convenience functions
+ *
+ * This is not defined if Py_LIMITED_API is defined.
+ */
+#ifdef Py_LIMITED_API
+LIBSHIBOKEN_API PyObject *PyImport_GetModule(PyObject *name);
+#endif // Py_LIMITED_API
+
+// Evaluate a script and return the variable `result`
+LIBSHIBOKEN_API PyObject *PepRun_GetResult(const char *command);
+
+// Call PyType_Type.tp_new returning a PyType object.
+LIBSHIBOKEN_API PyTypeObject *PepType_Type_tp_new(PyTypeObject *metatype,
+ PyObject *args,
+ PyObject *kwds);
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.8 incompatibilities
+ *
+ */
+
+#ifndef Py_TPFLAGS_METHOD_DESCRIPTOR
+/* Objects behave like an unbound method */
+#define Py_TPFLAGS_METHOD_DESCRIPTOR (1UL << 17)
+#endif
+
+extern LIBSHIBOKEN_API int PepRuntime_38_flag;
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.12 incompatibility
+ *
+ */
+
+LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
+
+// This function does not exist as PyType_SetDict. But because tp_dict
+// is no longer considered to be accessible, we treat it as such.
+LIBSHIBOKEN_API int PepType_SetDict(PyTypeObject *type, PyObject *dict);
+
+LIBSHIBOKEN_API void *PepType_GetSlot(PyTypeObject *type, int aSlot);
+
+/*****************************************************************************
+ *
+ * Module Initialization
+ *
+ */
+
+LIBSHIBOKEN_API void Pep384_Init(void);
+
+} // extern "C"
+
+#endif // PEP384IMPL_H
diff --git a/sources/shiboken6/libshiboken/pyobjectholder.h b/sources/shiboken6/libshiboken/pyobjectholder.h
new file mode 100644
index 000000000..857748c2f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pyobjectholder.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYOBJECTHOLDER_H
+#define PYOBJECTHOLDER_H
+
+#include "sbkpython.h"
+
+#include <cassert>
+#include <utility>
+
+namespace Shiboken
+{
+
+/// PyObjectHolder holds a PyObject pointer, keeping a reference decrementing
+/// its reference counter when destroyed. It makes sure to hold the GIL when
+/// releasing. It implements copy/move semantics and is mainly intended as a
+/// base class for functors holding a callable which can be passed around and
+/// stored in containers or moved from freely.
+/// For one-shot functors, release() can be invoked after the call.
+class PyObjectHolder
+{
+public:
+ PyObjectHolder() noexcept = default;
+
+ /// PyObjectHolder constructor.
+ /// \param pyobj A reference to a Python object
+ explicit PyObjectHolder(PyObject *pyObj) noexcept : m_pyObj(pyObj)
+ {
+ assert(pyObj != nullptr);
+ Py_INCREF(m_pyObj);
+ }
+
+ PyObjectHolder(const PyObjectHolder &o) noexcept : m_pyObj(o.m_pyObj)
+ {
+ Py_XINCREF(m_pyObj);
+ }
+
+ PyObjectHolder &operator=(const PyObjectHolder &o) noexcept
+ {
+ if (this != &o) {
+ m_pyObj = o.m_pyObj;
+ Py_XINCREF(m_pyObj);
+ }
+ return *this;
+ }
+
+ PyObjectHolder(PyObjectHolder &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
+
+ PyObjectHolder &operator=(PyObjectHolder &&o) noexcept
+ {
+ m_pyObj = std::exchange(o.m_pyObj, nullptr);
+ return *this;
+ }
+
+ /// Decref the python reference
+ ~PyObjectHolder() { release(); }
+
+ [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
+ [[nodiscard]] operator bool() const { return m_pyObj != nullptr; }
+
+ /// Returns the pointer of the Python object being held.
+ [[nodiscard]] PyObject *object() const { return m_pyObj; }
+ [[nodiscard]] operator PyObject *() const { return m_pyObj; }
+
+ [[nodiscard]] PyObject *operator->() { return m_pyObj; }
+
+protected:
+ void release()
+ {
+ if (m_pyObj != nullptr) {
+ assert(Py_IsInitialized());
+ auto gstate = PyGILState_Ensure();
+ Py_DECREF(m_pyObj);
+ PyGILState_Release(gstate);
+ m_pyObj = nullptr;
+ }
+ }
+
+private:
+ PyObject *m_pyObj = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // PYOBJECTHOLDER_H
diff --git a/sources/shiboken6/libshiboken/qt_attribution.json b/sources/shiboken6/libshiboken/qt_attribution.json
new file mode 100644
index 000000000..36e7f6868
--- /dev/null
+++ b/sources/shiboken6/libshiboken/qt_attribution.json
@@ -0,0 +1,12 @@
+{
+ "Id": "python",
+ "Name": "Python",
+ "QDocModule": "QtForPython",
+ "QtUsage": "Used for Qt for Python in the signature extension.",
+ "Description": "Qt for Python is an add-on for Python. The libshiboken packages of PySide uses certain parts of the source files (bufferprocs_py37.cpp, bufferprocs_py37.h). See the folder sources/shiboken6/libshiboken .",
+ "Homepage": "http://www.python.org/",
+ "Version": "3.7.0",
+ "License": "PSF LICENSE AGREEMENT FOR PYTHON 3.7.0",
+ "LicenseFile": "bufferprocs_py37.h",
+ "Copyright": "© Copyright 2001-2018, Python Software Foundation."
+}
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter.cpp b/sources/shiboken6/libshiboken/sbkarrayconverter.cpp
new file mode 100644
index 000000000..bcc3fb767
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter.cpp
@@ -0,0 +1,246 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkarrayconverter.h"
+#include "sbkarrayconverter_p.h"
+#include "helper.h"
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+
+#include <longobject.h>
+#include <floatobject.h>
+
+#include <algorithm>
+
+static SbkArrayConverter *ArrayTypeConverters[Shiboken::Conversions::SBK_ARRAY_IDX_SIZE] [2] = {};
+
+namespace Shiboken::Conversions {
+
+// Check whether Predicate is true for all elements of a sequence
+template <class Predicate>
+static bool sequenceAllOf(PyObject *pyIn, Predicate p)
+{
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ PyObject *item = PySequence_GetItem(pyIn, i);
+ const bool ok = p(item);
+ Py_XDECREF(item);
+ if (!ok)
+ return false;
+ }
+ return true;
+}
+
+// Convert a sequence to output iterator
+template <class T, class Converter>
+inline void convertPySequence(PyObject *pyIn, Converter c, T *out)
+{
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ PyObject *item = PySequence_GetItem(pyIn, i);
+ *out++ = c(item);
+ Py_XDECREF(item);
+ }
+}
+
+// Internal, for usage by numpy
+SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc)
+{
+ auto *result = new SbkArrayConverter;
+ result->toCppConversions.push_back(toCppCheckFunc);
+ return result;
+}
+
+static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int)
+{
+ return nullptr;
+}
+
+SbkArrayConverter *unimplementedArrayConverter()
+{
+ static SbkArrayConverter *result = createArrayConverter(unimplementedArrayCheck);
+ return result;
+}
+
+// Integers
+
+static inline bool intCheck(PyObject *pyIn)
+{
+ return PyLong_Check(pyIn);
+}
+
+static short toShort(PyObject *pyIn) { return short(PyLong_AsLong(pyIn)); }
+
+static void sequenceToCppShortArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<short> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, toShort, handle->data());
+}
+
+static inline bool sequenceSizeCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ if (expectedSize >= 0) {
+ const int size = int(PySequence_Size(pyIn));
+ if (size < expectedSize) {
+ warning(PyExc_RuntimeWarning, 0, "A sequence of size %d was passed to a function that expects %d.",
+ size, expectedSize);
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool intArrayCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ return PySequence_Check(pyIn) && sequenceAllOf(pyIn, intCheck)
+ && sequenceSizeCheck(pyIn, expectedSize);
+}
+
+static PythonToCppFunc sequenceToCppShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppShortArray : nullptr;
+}
+
+static short toUnsignedShort(PyObject *pyIn) { return static_cast<unsigned short>(PyLong_AsUnsignedLong(pyIn)); }
+
+static void sequenceToCppUnsignedShortArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned short> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, toUnsignedShort, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedShortArray : nullptr;
+}
+
+static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppIntArray : nullptr;
+}
+
+static void sequenceToCppUnsignedArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsUnsignedLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedArray : nullptr;
+}
+
+static void sequenceToCppLongLongArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<long long> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsLongLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppLongLongArray : nullptr;
+}
+
+static void sequenceToCppUnsignedLongLongArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned long long> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsUnsignedLongLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedLongLongArray : nullptr;
+}
+
+// Float
+
+static inline bool floatCheck(PyObject *pyIn) { return PyFloat_Check(pyIn); }
+
+static inline bool floatArrayCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ return PySequence_Check(pyIn) && sequenceAllOf(pyIn, floatCheck)
+ && sequenceSizeCheck(pyIn, expectedSize);
+}
+
+static void sequenceToCppDoubleArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<double> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyFloat_AsDouble, handle->data());
+}
+
+static inline float pyToFloat(PyObject *pyIn) { return float(PyFloat_AsDouble(pyIn)); }
+
+static void sequenceToCppFloatArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<float> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, pyToFloat, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppFloatArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return floatArrayCheck(pyIn, dim1) ? sequenceToCppFloatArray : nullptr;
+}
+
+static PythonToCppFunc sequenceToCppDoubleArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return floatArrayCheck(pyIn, dim1) ? sequenceToCppDoubleArray : nullptr;
+}
+
+#ifdef HAVE_NUMPY
+void initNumPyArrayConverters();
+#endif
+
+void initArrayConverters()
+{
+ SbkArrayConverter **start = &ArrayTypeConverters[0][0];
+ std::fill(start, start + sizeof(ArrayTypeConverters) / sizeof(ArrayTypeConverters[0][0]), nullptr);
+ // Populate 1-dimensional sequence converters
+ ArrayTypeConverters[SBK_DOUBLE_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppDoubleArrayCheck);
+ ArrayTypeConverters[SBK_FLOAT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppFloatArrayCheck);
+ ArrayTypeConverters[SBK_SHORT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppShortArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDSHORT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedShortArrayCheck);
+ ArrayTypeConverters[SBK_INT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppIntArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDINT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedArrayCheck);
+ ArrayTypeConverters[SBK_LONGLONG_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppLongLongArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDLONGLONG_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedLongLongArrayCheck);
+
+#ifdef HAVE_NUMPY
+ initNumPyArrayConverters();
+#endif
+}
+
+SbkArrayConverter *arrayTypeConverter(int index, int dimension)
+{
+ SbkArrayConverter *c = ArrayTypeConverters[index][dimension - 1];
+ return c ? c : unimplementedArrayConverter();
+}
+
+// Internal, for usage by numpy
+void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c)
+{
+ ArrayTypeConverters[index][dimension - 1] = c;
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter.h b/sources/shiboken6/libshiboken/sbkarrayconverter.h
new file mode 100644
index 000000000..f07cb1d70
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter.h
@@ -0,0 +1,136 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKARRAYCONVERTERS_H
+#define SBKARRAYCONVERTERS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C" {
+struct SbkArrayConverter;
+}
+
+namespace Shiboken::Conversions {
+
+enum : int {
+ SBK_UNIMPLEMENTED_ARRAY_IDX,
+ SBK_DOUBLE_ARRAY_IDX,
+ SBK_FLOAT_ARRAY_IDX,
+ SBK_SHORT_ARRAY_IDX,
+ SBK_UNSIGNEDSHORT_ARRAY_IDX,
+ SBK_INT_ARRAY_IDX,
+ SBK_UNSIGNEDINT_ARRAY_IDX,
+ SBK_LONGLONG_ARRAY_IDX,
+ SBK_UNSIGNEDLONGLONG_ARRAY_IDX,
+ SBK_ARRAY_IDX_SIZE
+};
+
+/**
+ * ArrayHandle is the type expected by shiboken6's array converter
+ * functions. It provides access to array data which it may own
+ * (in the case of conversions from PySequence) or a flat pointer
+ * to internal data (in the case of array modules like numpy).
+ */
+
+template <class T>
+class ArrayHandle
+{
+public:
+ ArrayHandle(const ArrayHandle &) = delete;
+ ArrayHandle& operator=(const ArrayHandle &) = delete;
+ ArrayHandle(ArrayHandle &&) = delete;
+ ArrayHandle& operator=(ArrayHandle &&) = delete;
+
+ ArrayHandle() = default;
+ ~ArrayHandle() { destroy(); }
+
+ void allocate(Py_ssize_t size);
+ void setData(T *d, size_t size);
+
+ size_t size() const { return m_size; }
+ T *data() const { return m_data; }
+ operator T *() const { return m_data; }
+
+private:
+ void destroy();
+
+ T *m_data = nullptr;
+ Py_ssize_t m_size = 0;
+ bool m_owned = false;
+};
+
+/**
+ * Similar to ArrayHandle for fixed size 2 dimensional arrays.
+ * columns is the size of the last dimension
+ * It only has a setData() methods since it will be used for numpy only.
+ */
+
+template <class T, int columns>
+class Array2Handle
+{
+public:
+ typedef T RowType[columns];
+
+ Array2Handle() = default;
+
+ operator RowType *() const { return m_rows; }
+
+ void setData(RowType *d) { m_rows = d; }
+
+private:
+ RowType *m_rows = nullptr;
+};
+
+/// Returns the converter for an array type.
+LIBSHIBOKEN_API SbkArrayConverter *arrayTypeConverter(int index, int dimension = 1);
+
+template <class T>
+struct ArrayTypeIndex{
+ enum : int { index = SBK_UNIMPLEMENTED_ARRAY_IDX };
+};
+
+template <> struct ArrayTypeIndex<double> { enum : int { index = SBK_DOUBLE_ARRAY_IDX }; };
+template <> struct ArrayTypeIndex<float> { enum : int { index = SBK_FLOAT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<short> { enum : int { index = SBK_SHORT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned short> { enum : int { index = SBK_UNSIGNEDSHORT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<int> { enum : int { index = SBK_INT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned> { enum : int { index = SBK_UNSIGNEDINT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<long long> { enum : int { index = SBK_LONGLONG_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned long long> { enum : int { index = SBK_UNSIGNEDLONGLONG_ARRAY_IDX };};
+
+template<typename T> SbkArrayConverter *ArrayTypeConverter(int dimension)
+{ return arrayTypeConverter(ArrayTypeIndex<T>::index, dimension); }
+
+// ArrayHandle methods
+template<class T>
+void ArrayHandle<T>::allocate(Py_ssize_t size)
+{
+ destroy();
+ m_data = new T[size];
+ m_size = size;
+ m_owned = true;
+}
+
+template<class T>
+void ArrayHandle<T>::setData(T *d, size_t size)
+{
+ destroy();
+ m_data = d;
+ m_size = size;
+ m_owned = false;
+}
+
+template<class T>
+void ArrayHandle<T>::destroy()
+{
+ if (m_owned)
+ delete [] m_data;
+ m_data = nullptr;
+ m_size = 0;
+ m_owned = false;
+}
+
+} // namespace Shiboken::Conversions
+
+#endif // SBKARRAYCONVERTERS_H
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter_p.h b/sources/shiboken6/libshiboken/sbkarrayconverter_p.h
new file mode 100644
index 000000000..63d03fb12
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter_p.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKARRAYCONVERTER_P_H
+#define SBKARRAYCONVERTER_P_H
+
+#include "sbkconverter_p.h"
+#include <vector>
+
+extern "C"
+{
+
+using IsArrayConvertibleToCppFunc = PythonToCppFunc (*)(PyObject *, int dim1, int dim2);
+/**
+ * \internal
+ * Private structure of SbkArrayConverter.
+ */
+
+struct SbkArrayConverter
+{
+ std::vector<IsArrayConvertibleToCppFunc> toCppConversions;
+};
+
+} // extern "C"
+
+#endif // SBKARRAYCONVERTER_P_H
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.cpp b/sources/shiboken6/libshiboken/sbkcontainer.cpp
new file mode 100644
index 000000000..7de1f03e6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcontainer.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkcontainer.h"
+#include "sbkstaticstrings.h"
+#include "autodecref.h"
+
+namespace Shiboken
+{
+bool isOpaqueContainer(PyObject *o)
+{
+ if (!o)
+ return false;
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(o->ob_type));
+ return o != nullptr && o != Py_None
+ && PyDict_Contains(tpDict.object(), Shiboken::PyMagicName::opaque_container()) == 1;
+
+}
+} // Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.h b/sources/shiboken6/libshiboken/sbkcontainer.h
new file mode 100644
index 000000000..8ad5aadc6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcontainer.h
@@ -0,0 +1,259 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONTAINER_H
+#define SBK_CONTAINER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "shibokenbuffer.h"
+
+#include <algorithm>
+#include <iterator>
+#include <optional>
+#include <utility>
+
+extern "C"
+{
+struct LIBSHIBOKEN_API ShibokenContainer
+{
+ PyObject_HEAD
+ void *d;
+};
+
+} // extern "C"
+
+// Conversion helper traits for container values (Keep it out of namespace as
+// otherwise clashes occur).
+template <class Value>
+struct ShibokenContainerValueConverter
+{
+ static bool checkValue(PyObject *pyArg);
+ static PyObject *convertValueToPython(Value v);
+ static std::optional<Value> convertValueToCpp(PyObject pyArg);
+};
+
+// SFINAE test for the presence of reserve() in a sequence container (std::vector/QList)
+template <typename T>
+class ShibokenContainerHasReserve
+{
+private:
+ using YesType = char[1];
+ using NoType = char[2];
+
+ template <typename C> static YesType& test( decltype(&C::reserve) ) ;
+ template <typename C> static NoType& test(...);
+
+public:
+ enum { value = sizeof(test<T>(nullptr)) == sizeof(YesType) };
+};
+
+template <class SequenceContainer>
+class ShibokenSequenceContainerPrivate // Helper for sequence type containers
+{
+public:
+ using value_type = typename SequenceContainer::value_type;
+ using OptionalValue = typename std::optional<value_type>;
+
+ SequenceContainer *m_list{};
+ bool m_ownsList = false;
+ bool m_const = false;
+ static constexpr const char *msgModifyConstContainer =
+ "Attempt to modify a constant container.";
+
+ static PyObject *tpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ allocfunc allocFunc = reinterpret_cast<allocfunc>(PepType_GetSlot(subtype, Py_tp_alloc));
+ auto *me = reinterpret_cast<ShibokenContainer *>(allocFunc(subtype, 0));
+ auto *d = new ShibokenSequenceContainerPrivate;
+ d->m_list = new SequenceContainer;
+ d->m_ownsList = true;
+ me->d = d;
+ return reinterpret_cast<PyObject *>(me);
+ }
+
+ static PyObject *tpNewInvalid(PyTypeObject * /* subtype */, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ return PyErr_Format(PyExc_NotImplementedError,
+ "Opaque containers of type '%s' cannot be instantiated.",
+ typeid(SequenceContainer).name());
+ }
+
+ static int tpInit(PyObject * /* self */, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ return 0;
+ }
+
+ static void tpFree(void *self)
+ {
+ auto *pySelf = reinterpret_cast<PyObject *>(self);
+ auto *d = get(pySelf);
+ if (d->m_ownsList)
+ delete d->m_list;
+ delete d;
+ auto freeFunc = reinterpret_cast<freefunc>(PepType_GetSlot(Py_TYPE(pySelf)->tp_base,
+ Py_tp_free));
+ freeFunc(self);
+ }
+
+ static Py_ssize_t sqLen(PyObject *self)
+ {
+ return get(self)->m_list->size();
+ }
+
+ static PyObject *sqGetItem(PyObject *self, Py_ssize_t i)
+ {
+ auto *d = get(self);
+ if (i < 0 || i >= Py_ssize_t(d->m_list->size()))
+ return PyErr_Format(PyExc_IndexError, "index out of bounds");
+ auto it = std::cbegin(*d->m_list);
+ std::advance(it, i);
+ return ShibokenContainerValueConverter<value_type>::convertValueToPython(*it);
+ }
+
+ static int sqSetItem(PyObject *self, Py_ssize_t i, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ if (i < 0 || i >= Py_ssize_t(d->m_list->size())) {
+ PyErr_SetString(PyExc_IndexError, "index out of bounds");
+ return -1;
+ }
+ auto it = std::begin(*d->m_list);
+ std::advance(it, i);
+ OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
+ if (!value.has_value())
+ return -1;
+ *it = value.value();
+ return 0;
+ }
+
+ static PyObject *push_back(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
+ if (!value.has_value())
+ return nullptr;
+ d->m_list->push_back(value.value());
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *push_front(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
+ if (!value.has_value())
+ return nullptr;
+ d->m_list->push_front(value.value());
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *clear(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->clear();
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *pop_back(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->pop_back();
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *pop_front(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->pop_front();
+ Py_RETURN_NONE;
+ }
+
+ // Support for containers with reserve/capacity
+ static PyObject *reserve(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ if (PyLong_Check(pyArg) == 0)
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to reserve().");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const Py_ssize_t size = PyLong_AsSsize_t(pyArg);
+ d->m_list->reserve(size);
+ } else {
+ return PyErr_Format(PyExc_TypeError, "Container does not support reserve().");
+ }
+
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *capacity(PyObject *self)
+ {
+ Py_ssize_t result = -1;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ result = d->m_list->capacity();
+ }
+ return PyLong_FromSsize_t(result);
+ }
+
+ static PyObject *data(PyObject *self)
+ {
+ PyObject *result = nullptr;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ auto *data = d->m_list->data();
+ const Py_ssize_t size = sizeof(value_type) * d->m_list->size();
+ result = Shiboken::Buffer::newObject(data, size, Shiboken::Buffer::ReadWrite);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Container does not support data().");
+ }
+ return result;
+ }
+
+ static PyObject *constData(PyObject *self)
+ {
+ PyObject *result = nullptr;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ const auto *data = std::as_const(d->m_list)->data();
+ const Py_ssize_t size = sizeof(value_type) * d->m_list->size();
+ result = Shiboken::Buffer::newObject(data, size);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Container does not support constData().");
+ }
+ return result;
+ }
+
+ static ShibokenSequenceContainerPrivate *get(PyObject *self)
+ {
+ auto *data = reinterpret_cast<ShibokenContainer *>(self);
+ return reinterpret_cast<ShibokenSequenceContainerPrivate *>(data->d);
+ }
+};
+
+namespace Shiboken
+{
+LIBSHIBOKEN_API bool isOpaqueContainer(PyObject *o);
+}
+
+#endif // SBK_CONTAINER_H
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
new file mode 100644
index 000000000..9ab674415
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -0,0 +1,910 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+#include "sbkarrayconverter_p.h"
+#include "sbkmodule.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "autodecref.h"
+#include "helper.h"
+#include "voidptr.h"
+
+#include <string>
+#include <cstring>
+#include <iostream>
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+
+static SbkConverter **PrimitiveTypeConverters;
+
+using ConvertersMap = std::unordered_map<std::string, SbkConverter *>;
+static ConvertersMap converters;
+
+namespace Shiboken::Conversions {
+
+void initArrayConverters();
+
+void init()
+{
+ static SbkConverter *primitiveTypeConverters[] = {
+ Primitive<PY_LONG_LONG>::createConverter(),
+ Primitive<bool>::createConverter(),
+ Primitive<char>::createConverter(),
+ Primitive<const char *>::createConverter(),
+ Primitive<double>::createConverter(),
+ Primitive<float>::createConverter(),
+ Primitive<int>::createConverter(),
+ Primitive<long>::createConverter(),
+ Primitive<short>::createConverter(),
+ Primitive<signed char>::createConverter(),
+ Primitive<std::string>::createConverter(),
+ Primitive<std::wstring>::createConverter(),
+ Primitive<unsigned PY_LONG_LONG>::createConverter(),
+ Primitive<unsigned char>::createConverter(),
+ Primitive<unsigned int>::createConverter(),
+ Primitive<unsigned long>::createConverter(),
+ Primitive<unsigned short>::createConverter(),
+ VoidPtr::createConverter(),
+ Primitive<std::nullptr_t>::createConverter()
+ };
+ PrimitiveTypeConverters = primitiveTypeConverters;
+
+ assert(converters.empty());
+ converters["PY_LONG_LONG"] = primitiveTypeConverters[SBK_PY_LONG_LONG_IDX];
+ converters["bool"] = primitiveTypeConverters[SBK_BOOL_IDX_1];
+ converters["char"] = primitiveTypeConverters[SBK_CHAR_IDX];
+ converters["const char *"] = primitiveTypeConverters[SBK_CONSTCHARPTR_IDX];
+ converters["double"] = primitiveTypeConverters[SBK_DOUBLE_IDX];
+ converters["float"] = primitiveTypeConverters[SBK_FLOAT_IDX];
+ converters["int"] = primitiveTypeConverters[SBK_INT_IDX];
+ converters["long"] = primitiveTypeConverters[SBK_LONG_IDX];
+ converters["short"] = primitiveTypeConverters[SBK_SHORT_IDX];
+ converters["signed char"] = primitiveTypeConverters[SBK_SIGNEDCHAR_IDX];
+ converters["std::string"] = primitiveTypeConverters[SBK_STD_STRING_IDX];
+ converters["std::wstring"] = primitiveTypeConverters[SBK_STD_WSTRING_IDX];
+ converters["unsigned PY_LONG_LONG"] = primitiveTypeConverters[SBK_UNSIGNEDPY_LONG_LONG_IDX];
+ converters["unsigned char"] = primitiveTypeConverters[SBK_UNSIGNEDCHAR_IDX];
+ converters["unsigned int"] = primitiveTypeConverters[SBK_UNSIGNEDINT_IDX];
+ converters["unsigned long"] = primitiveTypeConverters[SBK_UNSIGNEDLONG_IDX];
+ converters["unsigned short"] = primitiveTypeConverters[SBK_UNSIGNEDSHORT_IDX];
+ converters["void*"] = primitiveTypeConverters[SBK_VOIDPTR_IDX];
+ converters["std::nullptr_t"] = primitiveTypeConverters[SBK_NULLPTR_T_IDX];
+
+ initArrayConverters();
+}
+
+static void dumpPyTypeObject(std::ostream &str, PyTypeObject *t)
+{
+ str << "\nPython type ";
+ if (t == nullptr) {
+ str << "<None>";
+ return;
+ }
+ str << '"' << t->tp_name << '"';
+ if (t->tp_base != nullptr && t->tp_base != &PyBaseObject_Type)
+ str << '(' << t->tp_base->tp_name << ')';
+}
+
+static void dumpSbkConverter(std::ostream &str, const SbkConverter *c)
+{
+ str << "SbkConverter " << static_cast<const void *>(c) << ": ";
+ if (c->pointerToPython != nullptr)
+ str << ", C++ pointer->Python";
+ if (c->copyToPython != nullptr)
+ str << ", copy->Python";
+ if (c->toCppPointerConversion.second != nullptr)
+ str << ", Python->C++ pointer";
+ if (!c->toCppConversions.empty())
+ str << ", " << c->toCppConversions.size() << " Python->C++ conversions";
+}
+
+// Less than operator for a PyTypeObject for dumping the converter map
+static bool pyTypeObjectLessThan(const PyTypeObject *t1, const PyTypeObject *t2)
+{
+ const bool isNull1 = t1 == nullptr;
+ const bool isNull2 = t2 == nullptr;
+ if (isNull1 || isNull2)
+ return isNull1 && !isNull2;
+ // Internal types (lower case) first
+ const bool isInternal1 = std::islower(t1->tp_name[0]);
+ const bool isInternal2 = std::islower(t2->tp_name[0]);
+ if (isInternal1 != isInternal2)
+ return !isInternal2;
+ return std::strcmp(t1->tp_name, t2->tp_name) < 0;
+}
+
+void dumpConverters()
+{
+ struct PyTypeObjectLess {
+
+ bool operator()(const PyTypeObject *t1, const PyTypeObject *t2) const {
+ return pyTypeObjectLessThan(t1, t2);
+ }
+ };
+
+ using StringSet = std::set<std::string>;
+ using SbkConverterNamesMap = std::unordered_map<SbkConverter *, StringSet>;
+ using PyTypeObjectConverterMap = std::map<PyTypeObject *, SbkConverterNamesMap,
+ PyTypeObjectLess>;
+
+ auto &str = std::cerr;
+
+ // Sort the entries by the associated PyTypeObjects and converters
+ PyTypeObjectConverterMap pyTypeObjectConverterMap;
+ for (const auto &converter : converters) {
+ auto *sbkConverter = converter.second;
+ if (sbkConverter == nullptr) {
+ str << "Non-existent: \"" << converter.first << "\"\n";
+ continue;
+ }
+ auto *typeObject = sbkConverter->pythonType;
+ auto typeIt = pyTypeObjectConverterMap.find(typeObject);
+ if (typeIt == pyTypeObjectConverterMap.end())
+ typeIt = pyTypeObjectConverterMap.insert(std::make_pair(typeObject,
+ SbkConverterNamesMap{})).first;
+ SbkConverterNamesMap &sbkConverterMap = typeIt->second;
+ auto convIt = sbkConverterMap.find(sbkConverter);
+ if (convIt == sbkConverterMap.end())
+ convIt = sbkConverterMap.insert(std::make_pair(sbkConverter,
+ StringSet{})).first;
+ convIt->second.insert(converter.first);
+ }
+
+ for (const auto &tc : pyTypeObjectConverterMap) {
+ dumpPyTypeObject(str, tc.first);
+ str << ", " << tc.second.size() << " converter(s):\n";
+ for (const auto &cn : tc.second) {
+ str << " ";
+ dumpSbkConverter(str, cn.first);
+ str << ", " << cn.second.size() << " alias(es):";
+ int i = 0;
+ for (const auto &name : cn.second) {
+ if ((i++ % 5) == 0)
+ str << "\n ";
+ str << " \"" << name << '"';
+ }
+ str << '\n';
+ }
+ }
+
+ str << '\n';
+}
+
+SbkConverter *createConverterObject(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ auto converter = new SbkConverter;
+ converter->pythonType = type;
+ // PYSIDE-595: All types are heaptypes now, so provide reference.
+ Py_XINCREF(type);
+
+ converter->pointerToPython = pointerToPythonFunc;
+ converter->copyToPython = copyToPythonFunc;
+
+ if (toCppPointerCheckFunc && toCppPointerConvFunc)
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+ converter->toCppConversions.clear();
+
+ return converter;
+}
+
+SbkConverter *createConverter(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ SbkConverter *converter =
+ createConverterObject(type,
+ toCppPointerConvFunc, toCppPointerCheckFunc,
+ pointerToPythonFunc, copyToPythonFunc);
+ PepType_SOTP(type)->converter = converter;
+ return converter;
+}
+
+SbkConverter *createConverter(PyTypeObject *type, CppToPythonFunc toPythonFunc)
+{
+ return createConverterObject(type, nullptr, nullptr, nullptr, toPythonFunc);
+}
+
+void deleteConverter(SbkConverter *converter)
+{
+ if (converter) {
+ converter->toCppConversions.clear();
+ delete converter;
+ }
+}
+
+void setCppPointerToPythonFunction(SbkConverter *converter, CppToPythonFunc pointerToPythonFunc)
+{
+ converter->pointerToPython = pointerToPythonFunc;
+}
+
+void setPythonToCppPointerFunctions(SbkConverter *converter,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc)
+{
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+}
+
+void addPythonToCppValueConversion(SbkConverter *converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc));
+}
+
+void addPythonToCppValueConversion(PyTypeObject *type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ auto *sotp = PepType_SOTP(type);
+ addPythonToCppValueConversion(sotp->converter, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ addPythonToCppValueConversion(typeStruct.type, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+PyObject *pointerToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return pointerToPython(sotp->converter, cppIn);
+}
+
+PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn)
+{
+ assert(converter);
+ if (!cppIn)
+ Py_RETURN_NONE;
+ if (!converter->pointerToPython) {
+ warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->pointerToPython(cppIn);
+}
+
+PyObject *referenceToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return referenceToPython(sotp->converter, cppIn);
+}
+
+PyObject *referenceToPython(const SbkConverter *converter, const void *cppIn)
+{
+ assert(cppIn);
+
+ auto *pyOut = reinterpret_cast<PyObject *>(BindingManager::instance().retrieveWrapper(cppIn));
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+ if (!converter->pointerToPython) {
+ warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->pointerToPython(cppIn);
+}
+
+static inline PyObject *CopyCppToPython(const SbkConverter *converter, const void *cppIn)
+{
+ if (!cppIn)
+ Py_RETURN_NONE;
+ if (!converter->copyToPython) {
+ warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->copyToPython(cppIn);
+}
+
+PyObject *copyToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return CopyCppToPython(sotp->converter, cppIn);
+}
+
+PyObject *copyToPython(const SbkConverter *converter, const void *cppIn)
+{
+ return CopyCppToPython(converter, cppIn);
+}
+
+PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(pyIn);
+ auto *sotp = PepType_SOTP(type);
+ return sotp->converter->toCppPointerConversion.first(pyIn);
+}
+
+PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ return {};
+}
+
+PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn)
+{
+ return pythonToCppPointerConversion(typeStruct.type, pyIn);
+}
+
+static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
+{
+ assert(pyIn);
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
+ return toCppFunc;
+ }
+ return nullptr;
+}
+
+PythonToCppFunc isPythonToCppValueConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return IsPythonToCppConvertible(sotp->converter, pyIn);
+}
+
+PythonToCppConversion pythonToCppValueConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
+{
+ return IsPythonToCppConvertible(converter, pyIn);
+}
+
+PythonToCppConversion pythonToCppReferenceConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (converter->toCppPointerConversion.first) {
+ if (auto toCppPtr = converter->toCppPointerConversion.first(pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
+ return {toCppFunc, PythonToCppConversion::Value};
+ }
+ return {};
+}
+
+PythonToCppConversion pythonToCppConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (auto func = IsPythonToCppConvertible(converter, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn)
+{
+ assert(pyIn);
+ for (IsArrayConvertibleToCppFunc f : converter->toCppConversions) {
+ if (PythonToCppFunc c = f(pyIn, dim1, dim2))
+ return c;
+ }
+ return nullptr;
+}
+
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn)
+{
+ if (auto func = isPythonToCppConvertible(converter, dim1, dim2, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppReferenceConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn != Py_None) {
+ PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn);
+ if (toCpp)
+ return toCpp;
+ }
+ return isPythonToCppValueConvertible(type, pyIn);
+}
+
+PythonToCppConversion pythonToCppReferenceConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (pyIn != Py_None) {
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
+void nonePythonToCppNullPtr(PyObject *, void *cppOut)
+{
+ assert(cppOut);
+ *static_cast<void **>(cppOut) = nullptr;
+}
+
+void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn)
+{
+ assert(pyIn);
+ if (!ObjectType::checkType(desiredType))
+ return pyIn;
+ auto *inType = Py_TYPE(pyIn);
+ if (ObjectType::hasCast(inType))
+ return ObjectType::cast(inType, pyIn, desiredType);
+ return Object::cppPointer(pyIn, desiredType);
+}
+
+void pythonToCppPointer(PyTypeObject *type, PyObject *pyIn, void *cppOut)
+{
+ assert(type);
+ assert(pyIn);
+ assert(cppOut);
+ *reinterpret_cast<void **>(cppOut) = pyIn == Py_None
+ ? nullptr
+ : cppPointer(type, reinterpret_cast<SbkObject *>(pyIn));
+}
+
+void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ assert(converter);
+ assert(pyIn);
+ assert(cppOut);
+ *reinterpret_cast<void **>(cppOut) = pyIn == Py_None
+ ? nullptr
+ : cppPointer(converter->pythonType, reinterpret_cast<SbkObject *>(pyIn));
+}
+
+static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ assert(converter);
+ assert(pyIn);
+ assert(cppOut);
+ PythonToCppFunc toCpp = IsPythonToCppConvertible(converter, pyIn);
+ if (toCpp)
+ toCpp(pyIn, cppOut);
+}
+
+void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ _pythonToCppCopy(sotp->converter, pyIn, cppOut);
+}
+
+void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ _pythonToCppCopy(converter, pyIn, cppOut);
+}
+
+bool isImplicitConversion(PyTypeObject *type, PythonToCppFunc toCppFunc)
+{
+ auto *sotp = PepType_SOTP(type);
+ // This is the Object Type or Value Type conversion that only
+ // retrieves the C++ pointer held in the Python wrapper.
+ if (toCppFunc == sotp->converter->toCppPointerConversion.second)
+ return false;
+
+ // Object Types doesn't have any kind of value conversion,
+ // only C++ pointer retrieval.
+ if (sotp->converter->toCppConversions.empty())
+ return false;
+
+ // The first conversion of the non-pointer conversion list is
+ // a Value Type's copy to C++ function, which is not an implicit
+ // conversion.
+ // Otherwise it must be one of the implicit conversions.
+ // Note that we don't check if the Python to C++ conversion is in
+ // the list of the type's conversions, for it is expected that the
+ // caller knows what he's doing.
+ const auto conv = sotp->converter->toCppConversions.cbegin();
+ return toCppFunc != (*conv).second;
+}
+
+void registerConverterName(SbkConverter *converter, const char *typeName)
+{
+ auto iter = converters.find(typeName);
+ if (iter == converters.end())
+ converters.insert(std::make_pair(typeName, converter));
+}
+
+static std::string getRealTypeName(const std::string &typeName)
+{
+ auto size = typeName.size();
+ if (std::isalnum(typeName[size - 1]) == 0)
+ return typeName.substr(0, size - 1);
+ return typeName;
+}
+
+// PYSIDE-2404: Build a negative cache of already failed lookups.
+// The resulting list must be reset after each new import,
+// because that can change results. Also clear the cache after
+// reaching some threashold.
+static std::unordered_set<std::string> nonExistingTypeNames{};
+
+// Arbitrary size limit to prevent random name overflows.
+static constexpr std::size_t negativeCacheLimit = 50;
+
+static void rememberAsNonexistent(const std::string &typeName)
+{
+ if (nonExistingTypeNames.size() > negativeCacheLimit)
+ clearNegativeLazyCache();
+ converters.insert(std::make_pair(typeName, nullptr));
+ nonExistingTypeNames.insert(typeName);
+}
+
+SbkConverter *getConverter(const char *typeNameC)
+{
+ std::string typeName = typeNameC;
+ auto it = converters.find(typeName);
+ // PYSIDE-2404: This can also contain explicit nullptr as a negative cache.
+ if (it != converters.end())
+ return it->second;
+ // PYSIDE-2404: Did not find the name. Load the lazy classes
+ // which have this name and try again.
+ Shiboken::Module::loadLazyClassesWithName(getRealTypeName(typeName).c_str());
+ it = converters.find(typeName);
+ if (it != converters.end())
+ return it->second;
+ // Cache the negative result. Don't forget to clear the cache for new modules.
+ rememberAsNonexistent(typeName);
+
+ if (Shiboken::pyVerbose() > 0) {
+ const std::string message =
+ std::string("Can't find type resolver for type '") + typeName + "'.";
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
+ }
+ return nullptr;
+}
+
+void clearNegativeLazyCache()
+{
+ for (const auto &typeName : nonExistingTypeNames) {
+ auto it = converters.find(typeName);
+ converters.erase(it);
+ }
+ nonExistingTypeNames.clear();
+}
+
+SbkConverter *primitiveTypeConverter(int index)
+{
+ return PrimitiveTypeConverters[index];
+}
+
+bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!PyObject_TypeCheck(pyItem, type))
+ return false;
+ }
+ return true;
+}
+
+bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ assert(pyIn);
+ if (PySequence_Size(pyIn) < 0) {
+ // clear the error if < 0 which means no length at all
+ PyErr_Clear();
+ return false;
+ }
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, i)), type))
+ return false;
+ }
+ return true;
+}
+
+bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!isPythonToCppConvertible(converter, pyItem))
+ return false;
+ }
+ return true;
+}
+
+bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn)
+{
+ assert(converter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (!isPythonToCppConvertible(converter, AutoDecRef(PySequence_GetItem(pyIn, i))))
+ return false;
+ }
+ return true;
+}
+bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleSequenceTypes(sotp->converter, pyIn);
+}
+
+bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleIterableTypes(sotp->converter, pyIn);
+}
+
+bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn)
+{
+ assert(firstType);
+ assert(secondType);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 0)), firstType))
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 1)), secondType))
+ return false;
+ return true;
+}
+bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact,
+ const SbkConverter *secondConverter, bool secondCheckExact,
+ PyObject *pyIn)
+{
+ assert(firstConverter);
+ assert(secondConverter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ AutoDecRef firstItem(PySequence_GetItem(pyIn, 0));
+ if (firstCheckExact) {
+ if (!PyObject_TypeCheck(firstItem, firstConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(firstConverter, firstItem)) {
+ return false;
+ }
+ AutoDecRef secondItem(PySequence_GetItem(pyIn, 1));
+ if (secondCheckExact) {
+ if (!PyObject_TypeCheck(secondItem, secondConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(secondConverter, secondItem)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool checkDictTypes(PyTypeObject *keyType, PyTypeObject *valueType, PyObject *pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ return true;
+}
+
+bool checkMultiDictTypes(PyTypeObject *keyType, PyTypeObject *valueType,
+ PyObject *pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact, const SbkConverter *valueConverter,
+ bool valueCheckExact, PyObject *pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value, valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool convertibleMultiDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
+ const SbkConverter *valueConverter,
+ bool valueCheckExact, PyObject *pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value.object(), valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value.object())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+PyTypeObject *getPythonTypeObject(const SbkConverter *converter)
+{
+ if (converter)
+ return converter->pythonType;
+ return nullptr;
+}
+
+PyTypeObject *getPythonTypeObject(const char *typeName)
+{
+ return getPythonTypeObject(getConverter(typeName));
+}
+
+bool pythonTypeIsValueType(const SbkConverter *converter)
+{
+ // Unlikely to happen but for multi-inheritance SbkObjs
+ // the converter is not defined, hence we need a default return.
+ if (!converter)
+ return false;
+ return converter->pointerToPython && converter->copyToPython;
+}
+
+bool pythonTypeIsObjectType(const SbkConverter *converter)
+{
+ return converter->pointerToPython && !converter->copyToPython;
+}
+
+bool pythonTypeIsWrapperType(const SbkConverter *converter)
+{
+ return converter->pointerToPython != nullptr;
+}
+
+SpecificConverter::SpecificConverter(const char *typeName)
+ : m_type(InvalidConversion)
+{
+ m_converter = getConverter(typeName);
+ if (!m_converter)
+ return;
+ const Py_ssize_t len = strlen(typeName);
+ char lastChar = typeName[len -1];
+ if (lastChar == '&') {
+ m_type = ReferenceConversion;
+ } else if (lastChar == '*' || pythonTypeIsObjectType(m_converter)) {
+ m_type = PointerConversion;
+ } else {
+ m_type = CopyConversion;
+ }
+}
+
+PyObject *SpecificConverter::toPython(const void *cppIn)
+{
+ switch (m_type) {
+ case CopyConversion:
+ return copyToPython(m_converter, cppIn);
+ case PointerConversion:
+ return pointerToPython(m_converter, *static_cast<const void * const *>(cppIn));
+ case ReferenceConversion:
+ return referenceToPython(m_converter, cppIn);
+ default:
+ PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'C++ to Python' conversion");
+ }
+ return nullptr;
+}
+
+void SpecificConverter::toCpp(PyObject *pyIn, void *cppOut)
+{
+ switch (m_type) {
+ case CopyConversion:
+ pythonToCppCopy(m_converter, pyIn, cppOut);
+ break;
+ case PointerConversion:
+ pythonToCppPointer(m_converter, pyIn, cppOut);
+ break;
+ case ReferenceConversion:
+ pythonToCppPointer(m_converter, pyIn, &cppOut);
+ break;
+ default:
+ PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'Python to C++' conversion");
+ }
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbkconverter.h b/sources/shiboken6/libshiboken/sbkconverter.h
new file mode 100644
index 000000000..0d68f3faf
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter.h
@@ -0,0 +1,422 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONVERTER_H
+#define SBK_CONVERTER_H
+
+#include "sbkpython.h"
+#include "sbkmodule.h"
+#include "shibokenmacros.h"
+#include "sbkenum.h"
+#include "basewrapper_p.h"
+
+#include <limits>
+#include <string>
+
+struct SbkObject;
+
+/**
+ * This is a convenience macro identical to Python's PyObject_TypeCheck,
+ * except that the arguments have swapped places, for the great convenience
+ * of generator.
+ */
+#define SbkObject_TypeCheck(tp, ob) \
+ (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp)))
+
+extern "C"
+{
+
+/**
+ * SbkConverter is used to perform type conversions from C++
+ * to Python and vice-versa;.and it is also used for type checking.
+ * SbkConverter is a private structure that must be accessed
+ * using the functions provided by the converter API.
+ */
+struct SbkConverter;
+struct SbkArrayConverter;
+
+/**
+ * Given a void pointer to a C++ object, this function must return
+ * the proper Python object. It may be either an existing wrapper
+ * for the C++ object, or a newly create one. Or even the Python
+ * equivalent of the C++ value passed in the argument.
+ *
+ * C++ -> Python
+ */
+using CppToPythonFunc = PyObject *(*)(const void *);
+
+/**
+ * This function converts a Python object to a C++ value, it may be
+ * a pointer, value, class, container or primitive type, passed via
+ * a void pointer, that will be cast properly inside the function.
+ * This function is usually returned by an IsConvertibleToCppFunc
+ * function, or obtained knowing the type of the Python object input,
+ * thus it will not check the Python object type, and will expect
+ * the void pointer to be pointing to a proper variable.
+ *
+ * Python -> C++
+ */
+using PythonToCppFunc = void (*)(PyObject *,void *);
+
+/**
+ * Checks if the Python object passed in the argument is convertible to a
+ * C++ type defined inside the function, it returns the converter function
+ * that will transform a Python argument into a C++ value.
+ * It returns NULL if the Python object is not convertible to the C++ type
+ * that the function represents.
+ *
+ * Python -> C++ ?
+ */
+using IsConvertibleToCppFunc = PythonToCppFunc (*)(PyObject *);
+
+} // extern "C"
+
+namespace Shiboken {
+namespace Conversions {
+
+
+class LIBSHIBOKEN_API SpecificConverter
+{
+public:
+ enum Type
+ {
+ InvalidConversion,
+ CopyConversion,
+ PointerConversion,
+ ReferenceConversion
+ };
+
+ explicit SpecificConverter(const char *typeName);
+
+ inline SbkConverter *converter() { return m_converter; }
+ inline operator SbkConverter *() const { return m_converter; }
+
+ inline bool isValid() { return m_type != InvalidConversion; }
+ inline operator bool() const { return m_type != InvalidConversion; }
+
+ inline Type conversionType() { return m_type; }
+
+ PyObject *toPython(const void *cppIn);
+ void toCpp(PyObject *pyIn, void *cppOut);
+private:
+ SbkConverter *m_converter;
+ Type m_type;
+};
+
+
+/**
+ * Creates a converter for a wrapper type.
+ * \param type A Shiboken.ObjectType that will receive the new converter.
+ * \param toCppPointerConvFunc Function to retrieve the C++ pointer held by a Python wrapper.
+ * \param toCppPointerCheckFunc Check and return the retriever function of the C++ pointer held by a Python wrapper.
+ * \param pointerToPythonFunc Function to convert a C++ object to a Python \p type wrapper, keeping their identity.
+ * \param copyToPythonFunc Function to convert a C++ object to a Python \p type, copying the object.
+ * \returns The new converter referred by the wrapper \p type.
+ */
+LIBSHIBOKEN_API SbkConverter *createConverter(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc = nullptr);
+
+/**
+ * Creates a converter for a non wrapper type (primitive or container type).
+ * \param type Python type representing to the new converter.
+ * \param toPythonFunc Function to convert a C++ object to a Python \p type.
+ * \returns A new type converter.
+ */
+LIBSHIBOKEN_API SbkConverter *createConverter(PyTypeObject *type, CppToPythonFunc toPythonFunc);
+
+LIBSHIBOKEN_API void deleteConverter(SbkConverter *converter);
+
+/// Sets the Python object to C++ pointer conversion function.
+LIBSHIBOKEN_API void setCppPointerToPythonFunction(SbkConverter *converter, CppToPythonFunc pointerToPythonFunc);
+
+/// Sets the C++ pointer to Python object conversion functions.
+LIBSHIBOKEN_API void setPythonToCppPointerFunctions(SbkConverter *converter,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc);
+
+/**
+ * Adds a new conversion of a Python object to a C++ value.
+ * This is used in copy and implicit conversions.
+ */
+LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter *converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(PyTypeObject *type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+
+// C++ -> Python ---------------------------------------------------------------------------
+
+/**
+ * Retrieves the Python wrapper object for the given \p cppIn C++ pointer object.
+ * This function is used only for Value and Object Types.
+ * Example usage:
+ * TYPE *var;
+ * PyObject *pyVar = pointerToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *pointerToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn);
+
+/**
+ * For the given \p cppIn C++ reference it returns the Python wrapper object,
+ * always for Object Types, and when they already exist for reference types;
+ * for when the latter doesn't have an existing wrapper type, the C++ object
+ * is copied to Python.
+ * Example usage:
+ * TYPE &var = SOMETHING;
+ * PyObject *pyVar = referenceToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *referenceToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *referenceToPython(const SbkConverter *converter, const void *cppIn);
+
+/**
+ * Retrieves the Python wrapper object for the given C++ value pointed by \p cppIn.
+ * This function is used only for Value Types.
+ * Example usage:
+ * TYPE var;
+ * PyObject *pyVar = copyToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *copyToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *copyToPython(const SbkConverter *converter, const void *cppIn);
+
+// Python -> C++ ---------------------------------------------------------------------------
+
+struct PythonToCppConversion
+{
+ enum Type {Invalid, Pointer, Value};
+
+ operator bool() const { return type != Invalid; }
+
+ void operator()(PyObject *po,void *cpp) const { function(po, cpp); }
+
+ bool isValue() const { return type == Value; }
+
+ PythonToCppFunc function = nullptr;
+ Type type = Invalid;
+};
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value.
+ * The resulting converter function will create a copy of the Python object in C++, or implicitly
+ * convert the object to the expected \p type.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppValueConversion(PyTypeObject *type, PyObject *pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference.
+ * The resulting converter function will return the underlying C++ object held by the Python wrapper,
+ * or a new C++ value if it must be a implicit conversion.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppReferenceConversion(PyTypeObject *type, PyObject *pyIn);
+
+/// This is the same as isPythonToCppValueConvertible function.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppReferenceConversion(const SbkConverter *converter, PyObject *pyIn);
+
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkConverter *converter, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn);
+
+/**
+ * Returns the C++ pointer for the \p pyIn object cast to the type passed via \p desiredType.
+ * It differs from Shiboken::Object::cppPointer because it casts the pointer to a proper
+ * memory offset depending on the desired type.
+ */
+LIBSHIBOKEN_API void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn);
+
+/// Converts a Python object \p pyIn to C++ and stores the result in the C++ pointer passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppPointer(PyTypeObject *type, PyObject *pyIn, void *cppOut);
+LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut);
+
+/// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut);
+LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut);
+
+/**
+ * Helper function returned by generated convertible checking functions
+ * that returns a C++ NULL when the input Python object is None.
+ */
+LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject *, void *cppOut);
+
+/**
+ * Returns true if the \p toCpp function passed is an implicit conversion of Python \p type.
+ * It is used when C++ expects a reference argument, so it may be the same object received
+ * from Python, or another created through implicit conversion.
+ */
+[[deprecated]] LIBSHIBOKEN_API bool isImplicitConversion(PyTypeObject *type, PythonToCppFunc toCpp);
+
+/// Registers a converter with a type name that may be used to retrieve the converter.
+LIBSHIBOKEN_API void registerConverterName(SbkConverter *converter, const char *typeName);
+
+/// Returns the converter for a given type name, or NULL if it wasn't registered before.
+LIBSHIBOKEN_API SbkConverter *getConverter(const char *typeName);
+
+/// Returns the converter for a primitive type.
+LIBSHIBOKEN_API SbkConverter *primitiveTypeConverter(int index);
+
+/// Returns true if a Python sequence is comprised of objects of the given \p type.
+LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of the
+/// given \p type.
+LIBSHIBOKEN_API bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact,
+ const SbkConverter *secondConverter, bool secondCheckExact,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool checkDictTypes(PyTypeObject *keyType, PyTypeObject *valueType, PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ multi hash/map.
+/// The Python dictionary is expected to contain lists of values
+bool checkMultiDictTypes(PyTypeObject *keyType, PyTypeObject *valueType,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
+ const SbkConverter *valueConverter, bool valueCheckExact,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ multi hash/map.
+/// The Python dictionary is expected to contain lists of values
+LIBSHIBOKEN_API bool convertibleMultiDictTypes(const SbkConverter *keyConverter,
+ bool keyCheckExact,
+ const SbkConverter *valueConverter,
+ bool valueCheckExact,
+ PyObject *pyIn);
+
+/// Returns the Python type object associated with the given \p converter.
+LIBSHIBOKEN_API PyTypeObject *getPythonTypeObject(const SbkConverter *converter);
+
+/// Returns the Python type object for the given \p typeName.
+LIBSHIBOKEN_API PyTypeObject *getPythonTypeObject(const char *typeName);
+
+/// Returns true if the Python type associated with the converter is a value type.
+LIBSHIBOKEN_API bool pythonTypeIsValueType(const SbkConverter *converter);
+
+/// Returns true if the Python type associated with the converter is an object type.
+LIBSHIBOKEN_API bool pythonTypeIsObjectType(const SbkConverter *converter);
+
+/// Returns true if the Python type associated with the converter is a wrapper type.
+LIBSHIBOKEN_API bool pythonTypeIsWrapperType(const SbkConverter *converter);
+
+#define SBK_PY_LONG_LONG_IDX 0
+// Qt5: name collision in QtCore after QBool is replaced by bool
+#define SBK_BOOL_IDX_1 1
+#define SBK_CHAR_IDX 2
+#define SBK_CONSTCHARPTR_IDX 3
+#define SBK_DOUBLE_IDX 4
+#define SBK_FLOAT_IDX 5
+#define SBK_INT_IDX 6
+#define SBK_SIGNEDINT_IDX 6
+#define SBK_LONG_IDX 7
+#define SBK_SHORT_IDX 8
+#define SBK_SIGNEDCHAR_IDX 9
+#define SBK_STD_STRING_IDX 10
+#define SBK_STD_WSTRING_IDX 11
+#define SBK_UNSIGNEDPY_LONG_LONG_IDX 12
+#define SBK_UNSIGNEDCHAR_IDX 13
+#define SBK_UNSIGNEDINT_IDX 14
+#define SBK_UNSIGNEDLONG_IDX 15
+#define SBK_UNSIGNEDSHORT_IDX 16
+#define SBK_VOIDPTR_IDX 17
+#define SBK_NULLPTR_T_IDX 18
+
+template<typename T> SbkConverter *PrimitiveTypeConverter() { return nullptr; }
+template<> inline SbkConverter *PrimitiveTypeConverter<PY_LONG_LONG>() { return primitiveTypeConverter(SBK_PY_LONG_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<bool>() { return primitiveTypeConverter(SBK_BOOL_IDX_1); }
+template<> inline SbkConverter *PrimitiveTypeConverter<char>() { return primitiveTypeConverter(SBK_CHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<const char *>() { return primitiveTypeConverter(SBK_CONSTCHARPTR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<double>() { return primitiveTypeConverter(SBK_DOUBLE_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<float>() { return primitiveTypeConverter(SBK_FLOAT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<int>() { return primitiveTypeConverter(SBK_INT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<long>() { return primitiveTypeConverter(SBK_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<short>() { return primitiveTypeConverter(SBK_SHORT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<signed char>() { return primitiveTypeConverter(SBK_SIGNEDCHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::string>() { return primitiveTypeConverter(SBK_STD_STRING_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::wstring>() { return primitiveTypeConverter(SBK_STD_WSTRING_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned PY_LONG_LONG>() { return primitiveTypeConverter(SBK_UNSIGNEDPY_LONG_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned char>() { return primitiveTypeConverter(SBK_UNSIGNEDCHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned int>() { return primitiveTypeConverter(SBK_UNSIGNEDINT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned long>() { return primitiveTypeConverter(SBK_UNSIGNEDLONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned short>() { return primitiveTypeConverter(SBK_UNSIGNEDSHORT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<void *>() { return primitiveTypeConverter(SBK_VOIDPTR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::nullptr_t>() { return primitiveTypeConverter(SBK_NULLPTR_T_IDX); }
+
+} // namespace Shiboken::Conversions
+
+/**
+* This function template is used to get the PyTypeObject of a C++ type T.
+* All implementations should be provided by template specializations generated by the generator when
+* T isn't a C++ primitive type.
+* \see SpecialCastFunction
+*/
+template<typename T> PyTypeObject *SbkType() { return nullptr; }
+
+// Below are the template specializations for C++ primitive types.
+template<> inline PyTypeObject *SbkType<PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<bool>() { return &PyBool_Type; }
+template<> inline PyTypeObject *SbkType<char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<double>() { return &PyFloat_Type; }
+template<> inline PyTypeObject *SbkType<float>() { return &PyFloat_Type; }
+template<> inline PyTypeObject *SbkType<int>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<long>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<short>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<signed char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned int>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned long>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned short>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<std::nullptr_t>() { return Py_TYPE(&_Py_NoneStruct); }
+
+} // namespace Shiboken
+
+#define SbkChar_Check(X) (PyNumber_Check(X) || Shiboken::String::checkChar(X))
+
+struct PySideQFlagsType;
+struct SbkQFlagsTypePrivate
+{
+ SbkConverter *converter;
+};
+
+#endif // SBK_CONVERTER_H
diff --git a/sources/shiboken6/libshiboken/sbkconverter_p.h b/sources/shiboken6/libshiboken/sbkconverter_p.h
new file mode 100644
index 000000000..08fc4c8e1
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter_p.h
@@ -0,0 +1,542 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONVERTER_P_H
+#define SBK_CONVERTER_P_H
+
+#include "sbkpython.h"
+#include "sbkconverter.h"
+#include "sbkcppstring.h"
+#include "sbkstring.h"
+#include <limits>
+#include <typeinfo>
+#include <sstream>
+#include <iostream>
+#include <vector>
+
+extern "C"
+{
+
+using ToCppConversion = std::pair<IsConvertibleToCppFunc, PythonToCppFunc>;
+using ToCppConversionVector = std::vector<ToCppConversion>;
+
+/**
+ * \internal
+ * Private structure of SbkConverter.
+ */
+struct SbkConverter
+{
+ /**
+ * Python type associated with this converter. If the type is a Shiboken
+ * wrapper, then it must be a SbkObjectType; otherwise it will be the
+ * Python type to which the C++ value will be converted (note that the
+ * C++ type could be produced from various Python types).
+ */
+ PyTypeObject *pythonType;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the C++ object is kept,
+ * because it looks for an already existing Python wrapper associated
+ * with the C++ instance.
+ * It is used to convert C++ pointers and references to Python objects.
+ */
+ CppToPythonFunc pointerToPython;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the object is not kept,
+ * because a new instance of the C++ object is created.
+ * It is used to convert objects passed by value, or reference, if said
+ * reference can't be traced to an object that already has a Python
+ * wrapper assigned for it.
+ */
+ CppToPythonFunc copyToPython;
+ /**
+ * This is a special case of a Python to C++ conversion. It returns
+ * the underlying C++ pointer of a Python wrapper passed as parameter
+ * or NULL if the Python object is a None value.
+ * It comes separated from the other toCppConversions because if you
+ * have a Python object representing a Value Type the type checking
+ * for both ValueType and ValueType *would be the same, thus the first
+ * check would be true and the second would never be reached.
+ */
+ ToCppConversion toCppPointerConversion;
+ /**
+ * This is a list of type checking functions that return the
+ * proper Python to C++ conversion function, for the given Python
+ * object.
+ * For Object Types, that never have implicit conversions, this
+ * list is always empty.
+ */
+ ToCppConversionVector toCppConversions;
+};
+
+} // extern "C"
+
+template<typename T, typename MaxLimitType, bool isSigned>
+struct OverFlowCheckerBase {
+ static void formatOverFlowMessage(const MaxLimitType &value,
+ const std::string *valueAsString = nullptr)
+ {
+ std::ostringstream str;
+ str << "libshiboken: Overflow: Value ";
+ if (valueAsString != nullptr && !valueAsString->empty())
+ str << *valueAsString;
+ else
+ str << value;
+ str << " exceeds limits of type "
+ << " [" << (isSigned ? "signed" : "unsigned")
+ << "] \"" << typeid(T).name()
+ << "\" (" << sizeof(T) << "bytes).";
+ const std::string message = str.str();
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
+ }
+
+ // Checks if an overflow occurred inside Python code.
+ // Precondition: use after calls like PyLong_AsLongLong or PyLong_AsUnsignedLongLong.
+ // Postcondition: if error ocurred, sets the string reference to the string representation of
+ // the passed value.
+ static bool checkForInternalPyOverflow(PyObject *pyIn, std::string &valueAsString)
+ {
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyObject *stringRepresentation = PyObject_Str(pyIn);
+ const char *cString = Shiboken::String::toCString(stringRepresentation);
+ valueAsString.assign(cString);
+ Py_DECREF(stringRepresentation);
+ return true;
+ }
+ return false;
+ }
+};
+
+// Helper template for checking if a value overflows when cast to type T.
+// The MaxLimitType size is usually >= than type T size, so that it can still represent values that
+// can't be stored in T (unless the types are of course the same).
+// TLDR: MaxLimitType is either long long or unsigned long long.
+template<typename T, typename MaxLimitType = PY_LONG_LONG,
+ bool isSigned = std::numeric_limits<T>::is_signed >
+struct OverFlowChecker;
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, true> :
+ public OverFlowCheckerBase<T, MaxLimitType, true> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < std::numeric_limits<T>::min()
+ || value > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, false>
+ : public OverFlowCheckerBase<T, MaxLimitType, false> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < 0
+ || static_cast<unsigned long long>(value) > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+template<>
+struct OverFlowChecker<PY_LONG_LONG, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<PY_LONG_LONG, PY_LONG_LONG, true> {
+ static bool check(const PY_LONG_LONG &value, PyObject *pyIn) {
+ std::string valueAsString;
+ const bool isOverflow = checkForInternalPyOverflow(pyIn, valueAsString);
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+
+ }
+};
+template<>
+struct OverFlowChecker<double, PY_LONG_LONG, true> {
+ static bool check(const double &, PyObject *) { return false; }
+};
+template<>
+struct OverFlowChecker<float, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<float, PY_LONG_LONG, true> {
+ static bool check(const double &value, PyObject *)
+ {
+ const bool result = value < std::numeric_limits<float>::min()
+ || value > std::numeric_limits<float>::max();
+ if (result)
+ formatOverFlowMessage(value);
+ return result;
+ }
+};
+
+// Basic primitive type converters ---------------------------------------------------------
+
+template <typename T> struct Primitive {};
+
+template <typename T>
+struct OnePrimitive
+{
+ static PyObject *toPython(const void *) { return nullptr; }
+ static PythonToCppFunc isConvertible(PyObject *) { return nullptr; }
+ static void toCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = Shiboken::Conversions::createConverter(Shiboken::SbkType<T>(),
+ Primitive<T>::toPython);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ Primitive<T>::toCpp,
+ Primitive<T>::isConvertible);
+ return converter;
+ }
+};
+template <typename T>
+struct TwoPrimitive : OnePrimitive<T>
+{
+ static PythonToCppFunc isOtherConvertible(PyObject *) { return nullptr; }
+ static void otherToCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = OnePrimitive<T>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive<T>::otherToCpp, Primitive<T>::isOtherConvertible);
+ return converter;
+ }
+};
+
+// Integers --------------------------------------------------------------------------------
+
+template <typename INT>
+struct IntPrimitive : TwoPrimitive<INT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLong(*reinterpret_cast<const INT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ double result = PyFloat_AS_DOUBLE(pyIn);
+ // If cast to long directly it could overflow silently.
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyFloat_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<int> : IntPrimitive<int> {};
+template <> struct Primitive<long> : IntPrimitive<long> {};
+template <> struct Primitive<short> : IntPrimitive<short> {};
+template <> struct Primitive<unsigned short> : IntPrimitive<unsigned short> {};
+
+// Unsigned Long Integers ------------------------------------------------------------------
+
+template <typename LONG>
+struct UnsignedLongPrimitive : IntPrimitive<LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLong(*reinterpret_cast<const LONG *>(cppIn));
+ }
+};
+template <> struct Primitive<unsigned int> : UnsignedLongPrimitive<unsigned int> {};
+template <> struct Primitive<unsigned long> : UnsignedLongPrimitive<unsigned long> {};
+
+// Big integers ----------------------------------------------------------------------------
+
+template <>
+struct Primitive<PY_LONG_LONG> : OnePrimitive<PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLongLong(*reinterpret_cast<const PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<PY_LONG_LONG * >(cppOut) = result;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<unsigned PY_LONG_LONG> : OnePrimitive<unsigned PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLongLong(*static_cast<const unsigned PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ if (PyLong_Check(pyIn)) {
+ unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn);
+ if (OverFlowChecker<unsigned PY_LONG_LONG, unsigned PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<unsigned PY_LONG_LONG * >(cppOut) = result;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion");
+ }
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+// Floating point --------------------------------------------------------------------------
+
+template <typename FLOAT>
+struct FloatPrimitive : TwoPrimitive<FLOAT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyFloat_FromDouble(*reinterpret_cast<const FLOAT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyLong_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyLong_Check(pyIn) || PyLong_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyFloat_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<float> : FloatPrimitive<float> {};
+template <> struct Primitive<double> : FloatPrimitive<double> {};
+
+// Boolean ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<bool> : OnePrimitive<bool>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyBool_FromLong(*reinterpret_cast<const bool *>(cppIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<bool *>(cppOut) = PyLong_AS_LONG(pyIn) != 0;
+ }
+};
+
+// Characters ------------------------------------------------------------------------------
+
+template <typename CHAR>
+struct CharPrimitive : IntPrimitive<CHAR>
+{
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(Shiboken::String::toCString(pyIn)[0]);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::checkChar(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<CHAR>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = IntPrimitive<CHAR>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive<CHAR>::otherToCpp, CharPrimitive<CHAR>::isOtherConvertible);
+ return converter;
+ }
+
+};
+template <> struct Primitive<signed char> : CharPrimitive<signed char> {};
+template <> struct Primitive<unsigned char> : CharPrimitive<unsigned char> {};
+template <> struct Primitive<char> : CharPrimitive<char> {
+ using CharPrimitive<char>::toPython;
+ static PyObject *toPython(const void *cppIn) {
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn), 1);
+ }
+};
+
+
+
+// Strings ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<const char *> : TwoPrimitive<const char *>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ if (!cppIn)
+ Py_RETURN_NONE;
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = Shiboken::String::toCString(pyIn);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::string> : TwoPrimitive<std::string>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppString(*reinterpret_cast<const std::string *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::string *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppString(pyIn, reinterpret_cast<std::string *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::wstring> : TwoPrimitive<std::wstring>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppWString(*reinterpret_cast<const std::wstring *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::wstring *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ return pyIn == Py_None ? toCpp : nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppWString(pyIn, reinterpret_cast<std::wstring *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ return PyUnicode_Check(pyIn) ? otherToCpp : nullptr;
+ }
+};
+
+// nullptr_t
+template <>
+struct Primitive<std::nullptr_t> : OnePrimitive<std::nullptr_t>
+{
+ static PyObject *toPython(const void * /* cppIn */)
+ {
+ Py_RETURN_NONE;
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<std::nullptr_t *>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+};
+
+namespace Shiboken::Conversions {
+
+SbkConverter *createConverterObject(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc);
+
+LIBSHIBOKEN_API void dumpConverters();
+
+/// Interface for sbkmodule which must reset cache when new module is loaded.
+LIBSHIBOKEN_API void clearNegativeLazyCache();
+
+} // namespace Shiboken::Conversions
+
+#endif // SBK_CONVERTER_P_H
diff --git a/sources/shiboken6/libshiboken/sbkcppstring.cpp b/sources/shiboken6/libshiboken/sbkcppstring.cpp
new file mode 100644
index 000000000..8e8324f5e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcppstring.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkcppstring.h"
+#include "autodecref.h"
+
+namespace Shiboken::String
+{
+
+PyObject *fromCppString(const std::string &value)
+{
+ return PyUnicode_FromStringAndSize(value.data(), value.size());
+}
+
+PyObject *fromCppStringView(std::string_view value)
+{
+ return PyUnicode_FromStringAndSize(value.data(), value.size());
+}
+
+PyObject *fromCppWString(const std::wstring &value)
+{
+ return PyUnicode_FromWideChar(value.data(), value.size());
+}
+
+void toCppString(PyObject *str, std::string *value)
+{
+ value->clear();
+
+ if (str == Py_None)
+ return;
+
+ if (PyUnicode_Check(str)) {
+ if (PyUnicode_GetLength(str) > 0)
+ value->assign(_PepUnicode_AsString(str));
+ return;
+ }
+
+ if (PyBytes_Check(str))
+ value->assign(PyBytes_AS_STRING(str));
+}
+
+void toCppWString(PyObject *str, std::wstring *value)
+{
+ value->clear();
+
+ if (str == Py_None || PyUnicode_Check(str) == 0 || PyUnicode_GetLength(str) == 0)
+ return;
+
+ wchar_t *w = PyUnicode_AsWideCharString(str, nullptr);
+ value->assign(w);
+ PyMem_Free(w);
+}
+
+} // namespace Shiboken::String
diff --git a/sources/shiboken6/libshiboken/sbkcppstring.h b/sources/shiboken6/libshiboken/sbkcppstring.h
new file mode 100644
index 000000000..7ffe11c75
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcppstring.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKCPPSTRING_H
+#define SBKCPPSTRING_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+#include <string>
+#include <string_view>
+
+namespace Shiboken::String
+{
+ LIBSHIBOKEN_API PyObject *fromCppString(const std::string &value);
+ LIBSHIBOKEN_API PyObject *fromCppStringView(std::string_view value);
+ LIBSHIBOKEN_API PyObject *fromCppWString(const std::wstring &value);
+ LIBSHIBOKEN_API void toCppString(PyObject *str, std::string *value);
+ LIBSHIBOKEN_API void toCppWString(PyObject *str, std::wstring *value);
+} // namespace Shiboken::String
+
+#endif // SBKCPPSTRING_H
diff --git a/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
new file mode 100644
index 000000000..7637efa70
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+namespace Shiboken::Numpy {
+
+#ifdef HAVE_NUMPY
+
+// Helper to create a 1-dimensional numpy array
+template <class Type>
+static PyObject *_createArray1(Py_ssize_t size, int numpyType, const Type *data)
+{
+ const npy_intp dims[1] = {size};
+ PyObject *result = PyArray_EMPTY(1, dims, numpyType, 0);
+ auto *array = reinterpret_cast<PyArrayObject *>(result);
+ auto *rawTargetData = PyArray_DATA(array);
+ auto *targetData = reinterpret_cast<Type *>(rawTargetData);
+ std::copy(data, data + size, targetData);
+ return result;
+}
+
+PyObject *createByteArray1(Py_ssize_t size, const uint8_t *data)
+{
+ return _createArray1(size, NPY_BYTE, data);
+}
+
+PyObject *createDoubleArray1(Py_ssize_t size, const double *data)
+{
+ return _createArray1(size, NPY_DOUBLE, data);
+}
+
+PyObject *createFloatArray1(Py_ssize_t size, const float *data)
+{
+ return _createArray1(size, NPY_FLOAT, data);
+}
+
+PyObject *createIntArray1(Py_ssize_t size, const int *data)
+{
+ return _createArray1(size, NPY_INT, data);
+}
+
+#else // HAVE_NUMPY
+
+PyObject *createByteArray1(Py_ssize_t, const uint8_t *)
+{
+ return Py_None;
+}
+
+PyObject *createDoubleArray1(Py_ssize_t, const double *)
+{
+ Py_RETURN_NONE;
+}
+
+PyObject *createFloatArray1(Py_ssize_t, const float *)
+{
+ Py_RETURN_NONE;
+}
+
+PyObject *createIntArray1(Py_ssize_t, const int *)
+{
+ Py_RETURN_NONE;
+}
+
+#endif // !HAVE_NUMPY
+
+} //namespace Shiboken::Numpy
diff --git a/sources/shiboken6/libshiboken/sbkcpptonumpy.h b/sources/shiboken6/libshiboken/sbkcpptonumpy.h
new file mode 100644
index 000000000..8b9b0cfd2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcpptonumpy.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKCPPTONUMPY_H
+#define SBKCPPTONUMPY_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+#include <cstdint>
+
+namespace Shiboken::Numpy
+{
+
+/// Create a one-dimensional numpy array of type uint8/NPY_BYTE
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createByteArray1(Py_ssize_t size, const uint8_t *data);
+
+/// Create a one-dimensional numpy array of type double/NPY_DOUBLE
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createDoubleArray1(Py_ssize_t size, const double *data);
+
+/// Create a one-dimensional numpy array of type float/NPY_FLOAT
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createFloatArray1(Py_ssize_t size, const float *data);
+
+/// Create a one-dimensional numpy array of type int/NPY_INT
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createIntArray1(Py_ssize_t size, const int *data);
+
+} //namespace Shiboken::Numpy
+
+#endif // SBKCPPTONUMPY_H
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
new file mode 100644
index 000000000..4c0597bda
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -0,0 +1,455 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkenum.h"
+#include "sbkstring.h"
+#include "helper.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkconverter.h"
+#include "basewrapper.h"
+#include "autodecref.h"
+#include "sbkpython.h"
+#include "signature.h"
+
+#include <cstring>
+#include <vector>
+#include <sstream>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+struct SbkEnumType
+{
+ PyTypeObject type;
+};
+
+// Initialization
+static bool _init_enum()
+{
+ AutoDecRef shibo(PyImport_ImportModule("shiboken6.Shiboken"));
+ return !shibo.isNull();
+}
+
+static PyObject *PyEnumModule{};
+static PyObject *PyEnumMeta{};
+static PyObject *PyEnum{};
+static PyObject *PyIntEnum{};
+static PyObject *PyFlag{};
+static PyObject *PyIntFlag{};
+static PyObject *PyFlag_KEEP{};
+
+bool PyEnumMeta_Check(PyObject *ob)
+{
+ return Py_TYPE(ob) == reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+}
+
+PyTypeObject *getPyEnumMeta()
+{
+ if (PyEnumMeta)
+ return reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+
+ static auto *mod = PyImport_ImportModule("enum");
+ if (mod) {
+ PyEnumModule = mod;
+ PyEnumMeta = PyObject_GetAttrString(mod, "EnumMeta");
+ if (PyEnumMeta && PyType_Check(PyEnumMeta))
+ PyEnum = PyObject_GetAttrString(mod, "Enum");
+ if (PyEnum && PyType_Check(PyEnum))
+ PyIntEnum = PyObject_GetAttrString(mod, "IntEnum");
+ if (PyIntEnum && PyType_Check(PyIntEnum))
+ PyFlag = PyObject_GetAttrString(mod, "Flag");
+ if (PyFlag && PyType_Check(PyFlag))
+ PyIntFlag = PyObject_GetAttrString(mod, "IntFlag");
+ if (PyIntFlag && PyType_Check(PyIntFlag)) {
+ // KEEP is defined from Python 3.11 on.
+ PyFlag_KEEP = PyObject_GetAttrString(mod, "KEEP");
+ PyErr_Clear();
+ return reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+ }
+ }
+ Py_FatalError("Python module 'enum' not found");
+ return nullptr;
+}
+
+void init_enum()
+{
+ static bool isInitialized = false;
+ if (isInitialized)
+ return;
+ if (!(isInitialized || _init_enum()))
+ Py_FatalError("could not init enum");
+
+ // PYSIDE-1735: Determine whether we should use the old or the new enum implementation.
+ static PyObject *option = PySys_GetObject("pyside6_option_python_enum");
+ if (!option || !PyLong_Check(option)) {
+ PyErr_Clear();
+ option = PyLong_FromLong(1);
+ }
+ int ignoreOver{};
+ Enum::enumOption = PyLong_AsLongAndOverflow(option, &ignoreOver);
+ getPyEnumMeta();
+ isInitialized = true;
+}
+
+// PYSIDE-1735: Helper function supporting QEnum
+int enumIsFlag(PyObject *ob_type)
+{
+ init_enum();
+
+ auto *metatype = Py_TYPE(ob_type);
+ if (metatype != reinterpret_cast<PyTypeObject *>(PyEnumMeta))
+ return -1;
+ auto *mro = reinterpret_cast<PyTypeObject *>(ob_type)->tp_mro;
+ const Py_ssize_t n = PyTuple_GET_SIZE(mro);
+ for (Py_ssize_t idx = 0; idx < n; ++idx) {
+ auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (sub_type == reinterpret_cast<PyTypeObject *>(PyFlag))
+ return 1;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Support for Missing Values
+// ==========================
+//
+// Qt enums sometimes use undefined values in enums.
+// The enum module handles this by the option "KEEP" for Flag and
+// IntFlag. The handling of missing enum values is still strict.
+//
+// We changed that (also for compatibility with some competitor)
+// and provide a `_missing_` function that creates the missing value.
+//
+// The idea:
+// ---------
+// We cannot modify the already created class.
+// But we can create a one-element class with the new value and
+// pretend that this is the already existing class.
+//
+// We create each constant only once and keep the result in a dict
+// "_sbk_missing_". This is similar to a competitor's "_sip_missing_".
+//
+
+static PyObject *missing_func(PyObject * /* self */ , PyObject *args)
+{
+ // In order to relax matters to be more compatible with C++, we need
+ // to create a pseudo-member with that value.
+ static auto *const _sbk_missing = Shiboken::String::createStaticString("_sbk_missing_");
+ static auto *const _name = Shiboken::String::createStaticString("__name__");
+ static auto *const _mro = Shiboken::String::createStaticString("__mro__");
+ static auto *const _class = Shiboken::String::createStaticString("__class__");
+
+ PyObject *klass{}, *value{};
+ if (!PyArg_UnpackTuple(args, "missing", 2, 2, &klass, &value))
+ Py_RETURN_NONE;
+ if (!PyLong_Check(value))
+ Py_RETURN_NONE;
+ auto *type = reinterpret_cast<PyTypeObject *>(klass);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *sbk_missing = PyDict_GetItem(tpDict.object(), _sbk_missing);
+ if (!sbk_missing) {
+ sbk_missing = PyDict_New();
+ PyDict_SetItem(tpDict.object(), _sbk_missing, sbk_missing);
+ }
+ // See if the value is already in the dict.
+ AutoDecRef val_str(PyObject_CallMethod(value, "__str__", nullptr));
+ auto *ret = PyDict_GetItem(sbk_missing, val_str);
+ if (ret) {
+ Py_INCREF(ret);
+ return ret;
+ }
+ // No, we must create a new object and insert it into the dict.
+ AutoDecRef cls_name(PyObject_GetAttr(klass, _name));
+ AutoDecRef mro(PyObject_GetAttr(klass, _mro));
+ auto *baseClass(PyTuple_GetItem(mro, 1));
+ AutoDecRef param(PyDict_New());
+ PyDict_SetItem(param, val_str, value);
+ AutoDecRef fake(PyObject_CallFunctionObjArgs(baseClass, cls_name.object(), param.object(),
+ nullptr));
+ ret = PyObject_GetAttr(fake, val_str);
+ PyDict_SetItem(sbk_missing, val_str, ret);
+ // Now the real fake: Pretend that the type is our original type!
+ PyObject_SetAttr(ret, _class, klass);
+ return ret;
+}
+
+static struct PyMethodDef dummy_methods[] = {
+ {"_missing_", reinterpret_cast<PyCFunction>(missing_func), METH_VARARGS|METH_STATIC, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyType_Slot dummy_slots[] = {
+ {Py_tp_base, reinterpret_cast<void *>(&PyType_Type)},
+ {Py_tp_methods, reinterpret_cast<void *>(dummy_methods)},
+ {0, nullptr}
+};
+
+static PyType_Spec dummy_spec = {
+ "1:builtins.EnumType",
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ dummy_slots,
+};
+
+static PyObject *create_missing_func(PyObject *klass)
+{
+ // When creating the class, memorize it in the missing function by
+ // a partial function argument.
+ static auto *const type = SbkType_FromSpec(&dummy_spec);
+ static auto *const obType = reinterpret_cast<PyObject *>(type);
+ static auto *const _missing = Shiboken::String::createStaticString("_missing_");
+ static auto *const func = PyObject_GetAttr(obType, _missing);
+ static auto *const partial = Pep_GetPartialFunction();
+ return PyObject_CallFunctionObjArgs(partial, func, klass, nullptr);
+}
+//
+////////////////////////////////////////////////////////////////////////
+
+} // extern "C"
+
+namespace Shiboken::Enum {
+
+int enumOption{};
+
+bool check(PyObject *pyObj)
+{
+ init_enum();
+
+ static PyTypeObject *meta = getPyEnumMeta();
+ return Py_TYPE(Py_TYPE(pyObj)) == reinterpret_cast<PyTypeObject *>(meta);
+}
+
+PyObject *getEnumItemFromValue(PyTypeObject *enumType, EnumValueType itemValue)
+{
+ init_enum();
+
+ auto *obEnumType = reinterpret_cast<PyObject *>(enumType);
+ AutoDecRef val2members(PyObject_GetAttrString(obEnumType, "_value2member_map_"));
+ if (val2members.isNull()) {
+ PyErr_Clear();
+ return nullptr;
+ }
+ AutoDecRef ob_value(PyLong_FromLongLong(itemValue));
+ auto *result = PyDict_GetItem(val2members, ob_value);
+ Py_XINCREF(result);
+ return result;
+}
+
+PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue,
+ const char *itemName)
+{
+ init_enum();
+
+ auto *obEnumType = reinterpret_cast<PyObject *>(enumType);
+ if (!itemName)
+ return PyObject_CallFunction(obEnumType, "L", itemValue);
+
+ static PyObject *const _member_map_ = String::createStaticString("_member_map_");
+ AutoDecRef tpDict(PepType_GetDict(enumType));
+ auto *member_map = PyDict_GetItem(tpDict.object(), _member_map_);
+ if (!(member_map && PyDict_Check(member_map)))
+ return nullptr;
+ auto *result = PyDict_GetItemString(member_map, itemName);
+ Py_XINCREF(result);
+ return result;
+}
+
+EnumValueType getValue(PyObject *enumItem)
+{
+ init_enum();
+
+ assert(Enum::check(enumItem));
+
+ AutoDecRef pyValue(PyObject_GetAttrString(enumItem, "value"));
+ return PyLong_AsLongLong(pyValue);
+}
+
+void setTypeConverter(PyTypeObject *type, SbkConverter *converter)
+{
+ auto *enumType = reinterpret_cast<SbkEnumType *>(type);
+ PepType_SETP(enumType)->converter = converter;
+}
+
+static PyTypeObject *createEnumForPython(PyObject *scopeOrModule,
+ const char *fullName,
+ PyObject *pyEnumItems)
+{
+ const char *colon = strchr(fullName, ':');
+ assert(colon);
+ int package_level = atoi(fullName);
+ const char *mod = colon + 1;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ AutoDecRef qualname(Shiboken::String::fromCString(qual));
+ const char *dot = strrchr(qual, '.');
+ AutoDecRef name(Shiboken::String::fromCString(dot ? dot + 1 : qual));
+
+ static PyObject *enumName = String::createStaticString("IntEnum");
+ if (PyType_Check(scopeOrModule)) {
+ // For global objects, we have no good solution, yet where to put the int info.
+ auto type = reinterpret_cast<PyTypeObject *>(scopeOrModule);
+ auto *sotp = PepType_SOTP(type);
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type);
+ enumName = PyDict_GetItem(sotp->enumTypeDict, name);
+ }
+
+ SBK_UNUSED(getPyEnumMeta()); // enforce PyEnumModule creation
+ assert(PyEnumModule != nullptr);
+ AutoDecRef PyEnumType(PyObject_GetAttr(PyEnumModule, enumName));
+ assert(PyEnumType.object());
+ bool isFlag = PyObject_IsSubclass(PyEnumType, PyFlag);
+
+ // See if we should use the Int versions of the types, again
+ bool useIntInheritance = Enum::enumOption & Enum::ENOPT_INHERIT_INT;
+ if (useIntInheritance) {
+ auto *surrogate = PyObject_IsSubclass(PyEnumType, PyFlag) ? PyIntFlag : PyIntEnum;
+ Py_INCREF(surrogate);
+ PyEnumType.reset(surrogate);
+ }
+
+ // Walk the enumItemStrings and create a Python enum type.
+ auto *pyName = name.object();
+
+ // We now create the new type. Since Python 3.11, we need to pass in
+ // `boundary=KEEP` because the default STRICT crashes on us.
+ // See QDir.Filter.Drives | QDir.Filter.Files
+ AutoDecRef callArgs(Py_BuildValue("(OO)", pyName, pyEnumItems));
+ AutoDecRef callDict(PyDict_New());
+ static PyObject *boundary = String::createStaticString("boundary");
+ if (PyFlag_KEEP)
+ PyDict_SetItem(callDict, boundary, PyFlag_KEEP);
+ auto *obNewType = PyObject_Call(PyEnumType, callArgs, callDict);
+ if (!obNewType || PyObject_SetAttr(scopeOrModule, pyName, obNewType) < 0)
+ return nullptr;
+
+ // For compatibility with Qt enums, provide a permissive missing method for (Int)?Enum.
+ if (!isFlag) {
+ bool supportMissing = !(Enum::enumOption & Enum::ENOPT_NO_MISSING);
+ if (supportMissing) {
+ AutoDecRef enum_missing(create_missing_func(obNewType));
+ PyObject_SetAttrString(obNewType, "_missing_", enum_missing);
+ }
+ }
+
+ auto *newType = reinterpret_cast<PyTypeObject *>(obNewType);
+ PyObject_SetAttr(obNewType, PyMagicName::qualname(), qualname);
+ PyObject_SetAttr(obNewType, PyMagicName::module(), module);
+
+ // See if we should re-introduce shortcuts in the enclosing object.
+ const bool useGlobalShortcut = (Enum::enumOption & Enum::ENOPT_GLOBAL_SHORTCUT) != 0;
+ const bool useScopedShortcut = (Enum::enumOption & Enum::ENOPT_SCOPED_SHORTCUT) != 0;
+ if (useGlobalShortcut || useScopedShortcut) {
+ // We have to use the iterator protokol because the values dict is a mappingproxy.
+ AutoDecRef values(PyObject_GetAttr(obNewType, PyMagicName::members()));
+ AutoDecRef mapIterator(PyObject_GetIter(values));
+ AutoDecRef mapKey{};
+ bool isModule = PyModule_Check(scopeOrModule);
+ while ((mapKey.reset(PyIter_Next(mapIterator))), mapKey.object()) {
+ if ((useGlobalShortcut && isModule) || (useScopedShortcut && !isModule)) {
+ AutoDecRef value(PyObject_GetItem(values, mapKey));
+ if (PyObject_SetAttr(scopeOrModule, mapKey, value) < 0)
+ return nullptr;
+ }
+ }
+ }
+
+ return newType;
+}
+
+template <typename IntT>
+static PyObject *toPyObject(IntT v)
+{
+ if constexpr (sizeof(IntT) == 8) {
+ if constexpr (std::is_unsigned_v<IntT>)
+ return PyLong_FromUnsignedLongLong(v);
+ return PyLong_FromLongLong(v);
+ }
+ if constexpr (std::is_unsigned_v<IntT>)
+ return PyLong_FromUnsignedLong(v);
+ return PyLong_FromLong(v);
+}
+
+template <typename IntT>
+static PyTypeObject *createPythonEnumHelper(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const IntT enumValues[])
+{
+ AutoDecRef args(PyList_New(0));
+ auto *pyEnumItems = args.object();
+ for (size_t idx = 0; enumItemStrings[idx] != nullptr; ++idx) {
+ const char *kv = enumItemStrings[idx];
+ auto *key = PyUnicode_FromString(kv);
+ auto *value = toPyObject(enumValues[idx]);
+ auto *key_value = PyTuple_New(2);
+ PyTuple_SET_ITEM(key_value, 0, key);
+ PyTuple_SET_ITEM(key_value, 1, value);
+ PyList_Append(pyEnumItems, key_value);
+ }
+ return createEnumForPython(module, fullName, pyEnumItems);
+}
+
+// Now we have to concretize these functions explicitly,
+// otherwise templates will not work across modules.
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int64_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint64_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int32_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint32_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int16_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint16_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int8_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint8_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+} // namespace Shiboken::Enum
diff --git a/sources/shiboken6/libshiboken/sbkenum.h b/sources/shiboken6/libshiboken/sbkenum.h
new file mode 100644
index 000000000..e19ca4b4c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkenum.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKENUM_H
+#define SBKENUM_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API bool PyEnumMeta_Check(PyObject *ob);
+
+/// exposed for the signature module
+LIBSHIBOKEN_API void init_enum();
+
+struct SbkConverter;
+struct SbkEnumType;
+
+struct SbkEnumTypePrivate
+{
+ SbkConverter *converter;
+};
+
+/// PYSIDE-1735: Pass on the Python enum/flag information.
+LIBSHIBOKEN_API void initEnumFlagsDict(PyTypeObject *type);
+
+/// PYSIDE-1735: Make sure that we can import the Python enum implementation.
+LIBSHIBOKEN_API PyTypeObject *getPyEnumMeta();
+/// PYSIDE-1735: Helper function supporting QEnum
+LIBSHIBOKEN_API int enumIsFlag(PyObject *ob_enum);
+
+}
+
+namespace Shiboken::Enum {
+
+enum : int {
+ ENOPT_OLD_ENUM = 0x00, // PySide 6.6: no longer supported
+ ENOPT_NEW_ENUM = 0x01,
+ ENOPT_INHERIT_INT = 0x02,
+ ENOPT_GLOBAL_SHORTCUT = 0x04,
+ ENOPT_SCOPED_SHORTCUT = 0x08,
+ ENOPT_NO_FAKESHORTCUT = 0x10,
+ ENOPT_NO_FAKERENAMES = 0x20,
+ ENOPT_NO_ZERODEFAULT = 0x40,
+ ENOPT_NO_MISSING = 0x80,
+};
+
+LIBSHIBOKEN_API extern int enumOption;
+
+using EnumValueType = long long;
+
+LIBSHIBOKEN_API bool check(PyObject *obj);
+
+LIBSHIBOKEN_API PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue,
+ const char *itemName = nullptr);
+
+LIBSHIBOKEN_API EnumValueType getValue(PyObject *enumItem);
+LIBSHIBOKEN_API PyObject *getEnumItemFromValue(PyTypeObject *enumType,
+ EnumValueType itemValue);
+
+/// Sets the enum/flag's type converter.
+LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *type, SbkConverter *converter);
+
+/// Creating Python enums for different types.
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int64_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint64_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int32_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint32_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int16_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint16_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int8_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint8_t enumValues[]);
+
+/// This template removes duplication by inlining necessary type casts.
+template <typename IntT>
+inline PyTypeObject *createPythonEnum(PyTypeObject *scope,
+ const char *fullName, const char *enumItemStrings[], const IntT enumValues[])
+{
+ auto *obScope = reinterpret_cast<PyObject *>(scope);
+ return createPythonEnum(obScope, fullName, enumItemStrings, enumValues);
+}
+
+} // namespace Shiboken::Enum
+
+#endif // SKB_PYENUM_H
diff --git a/sources/shiboken6/libshiboken/sbkerrors.cpp b/sources/shiboken6/libshiboken/sbkerrors.cpp
new file mode 100644
index 000000000..84c080f8d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkerrors.cpp
@@ -0,0 +1,215 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkerrors.h"
+#include "sbkstring.h"
+#include "helper.h"
+#include "gilstate.h"
+
+#include <cstdio>
+#include <string>
+
+using namespace std::literals::string_literals;
+
+namespace Shiboken
+{
+
+// PYSIDE-2335: Track down if we can reach a Python error handler.
+// _pythonContextStack has always the current state of handler status
+// in its lowest bit.
+// Blocking calls like exec or run need to use `setBlocking`.
+static thread_local std::size_t _pythonContextStack{};
+
+PythonContextMarker::PythonContextMarker()
+{
+ // Shift history up and set lowest bit.
+ _pythonContextStack = (_pythonContextStack * 2) + 1;
+}
+
+PythonContextMarker::~PythonContextMarker()
+{
+ // Shift history down.
+ _pythonContextStack /= 2;
+}
+
+void PythonContextMarker::setBlocking()
+{
+ // Clear lowest bit.
+ _pythonContextStack = _pythonContextStack / 2 * 2;
+}
+
+namespace Errors
+{
+
+void setInstantiateAbstractClass(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "'%s' represents a C++ abstract class and cannot be instantiated", name);
+}
+
+void setInstantiateAbstractClassDisabledWrapper(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "Abstract class '%s' cannot be instantiated since the wrapper has been disabled.",
+ name);
+}
+
+void setInvalidTypeDeletion(const char *name)
+{
+ PyErr_Format(PyExc_TypeError, "'%s' may not be deleted", name);
+}
+
+void setOperatorNotImplemented()
+{
+ PyErr_SetString(PyExc_NotImplementedError, "operator not implemented.");
+}
+
+void setPureVirtualMethodError(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError, "pure virtual method '%s' not implemented.", name);
+}
+
+void setPrivateMethod(const char *name)
+{
+ PyErr_Format(PyExc_TypeError, "%s is a private method.\", ", name);
+}
+
+void setReverseOperatorNotImplemented()
+{
+ PyErr_SetString(PyExc_NotImplementedError, "reverse operator not implemented.");
+}
+
+void setSequenceTypeError(const char *expectedType)
+{
+ PyErr_Format(PyExc_TypeError,
+ "attributed value with wrong type, '%s' or other convertible type expected",
+ expectedType);
+}
+
+void setSetterTypeError(const char *name, const char *expectedType)
+{
+ PyErr_Format(PyExc_TypeError,
+ "wrong type attributed to '%s', '%s' or convertible type expected",
+ name, expectedType);
+}
+
+void setWrongContainerType()
+{
+ PyErr_SetString(PyExc_TypeError, "Wrong type passed to container conversion.");
+}
+
+// Prepend something to an exception message provided it is a single string
+// argument.
+static bool prependToExceptionMessage(PyObject *exc, const char *context)
+{
+ Shiboken::AutoDecRef args(PepException_GetArgs(exc));
+ if (args.isNull() || PyTuple_Check(args.object()) == 0 || PyTuple_Size(args) != 1)
+ return false;
+ auto *oldMessage = PyTuple_GetItem(args, 0);
+ if (oldMessage == nullptr || PyUnicode_CheckExact(oldMessage) == 0)
+ return false;
+ auto *newMessage = PyUnicode_FromFormat("%s%U", context, oldMessage);
+ PepException_SetArgs(exc, PyTuple_Pack(1, newMessage));
+ return true;
+}
+
+struct ErrorStore {
+ PyObject *type;
+ PyObject *exc;
+ PyObject *traceback;
+};
+
+static thread_local ErrorStore savedError{};
+
+static bool hasPythonContext()
+{
+ return _pythonContextStack & 1;
+}
+
+void storeErrorOrPrint()
+{
+ // This error happened in a function with no way to return an error state.
+ // Therefore, we handle the error when we are error checking, anyway.
+ // But we do that only when we know that an error handler can pick it up.
+ if (hasPythonContext())
+ PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
+ else
+ PyErr_Print();
+}
+
+// Like storeErrorOrPrint() with additional context info that is prepended
+// to the exception message or printed.
+static void storeErrorOrPrintWithContext(const char *context)
+{
+ if (hasPythonContext()) {
+ PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
+ prependToExceptionMessage(savedError.exc, context);
+ } else {
+ std::fputs(context, stderr);
+ PyErr_Print();
+ }
+}
+
+void storePythonOverrideErrorOrPrint(const char *className, const char *funcName)
+{
+ const std::string context = "Error calling Python override of "s
+ + className + "::"s + funcName + "(): "s;
+ storeErrorOrPrintWithContext(context.c_str());
+}
+
+PyObject *occurred()
+{
+ if (savedError.type) {
+ PyErr_Restore(savedError.type, savedError.exc, savedError.traceback);
+ savedError.type = nullptr;
+ }
+ return PyErr_Occurred();
+}
+
+} // namespace Errors
+
+namespace Warnings
+{
+void warnInvalidReturnValue(const char *className, const char *functionName,
+ const char *expectedType, const char *actualType)
+{
+ Shiboken::warning(PyExc_RuntimeWarning, 2,
+ "Invalid return value in function '%s.%s', expected %s, got %s.",
+ className, functionName, expectedType, actualType);
+}
+
+void warnDeprecated(const char *functionName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Function: '%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ functionName);
+}
+
+void warnDeprecated(const char *className, const char *functionName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Function: '%s.%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ className, functionName);
+}
+
+void warnDeprecatedEnum(const char *enumName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Enum: '%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ enumName);
+}
+
+void warnDeprecatedEnumValue(const char *enumName, const char *valueName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Enum value '%s.%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ enumName, valueName);
+
+}
+
+} // namespace Warnings
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkerrors.h b/sources/shiboken6/libshiboken/sbkerrors.h
new file mode 100644
index 000000000..18ce701e7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkerrors.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKERRORS_H
+#define SBKERRORS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+/// Craving for C++20 and std::source_location::current()
+#if defined(_MSC_VER)
+# define SBK_FUNC_INFO __FUNCSIG__
+#elif defined(__GNUC__)
+# define SBK_FUNC_INFO __PRETTY_FUNCTION__
+#else
+# define SBK_FUNC_INFO __FUNCTION__
+#endif
+
+namespace Shiboken
+{
+
+struct LIBSHIBOKEN_API PythonContextMarker
+{
+public:
+ PythonContextMarker(const PythonContextMarker &) = delete;
+ PythonContextMarker(PythonContextMarker &&) = delete;
+ PythonContextMarker &operator=(const PythonContextMarker &) = delete;
+ PythonContextMarker &operator=(PythonContextMarker &&) = delete;
+
+ explicit PythonContextMarker();
+ ~PythonContextMarker();
+ void setBlocking();
+};
+
+namespace Errors
+{
+
+LIBSHIBOKEN_API void setInstantiateAbstractClass(const char *name);
+LIBSHIBOKEN_API void setInstantiateAbstractClassDisabledWrapper(const char *name);
+LIBSHIBOKEN_API void setInvalidTypeDeletion(const char *name);
+LIBSHIBOKEN_API void setOperatorNotImplemented();
+LIBSHIBOKEN_API void setPureVirtualMethodError(const char *name);
+LIBSHIBOKEN_API void setPrivateMethod(const char *name);
+LIBSHIBOKEN_API void setReverseOperatorNotImplemented();
+LIBSHIBOKEN_API void setSequenceTypeError(const char *expectedType);
+LIBSHIBOKEN_API void setSetterTypeError(const char *name, const char *expectedType);
+LIBSHIBOKEN_API void setWrongContainerType();
+
+/// Report an error ASAP: Instead of printing, store for later re-raise.
+/// This replaces `PyErr_Print`, which cannot report errors as exception.
+/// To be used in contexts where raising errors is impossible.
+LIBSHIBOKEN_API void storeErrorOrPrint();
+
+/// Call storeErrorOrPrint() and print the context to report
+/// errors when calling Python overrides of virtual functions.
+LIBSHIBOKEN_API void storePythonOverrideErrorOrPrint(const char *className, const char *funcName);
+
+/// Handle an error as in PyErr_Occurred(), but also check for errors which
+/// were captured by `storeErrorOrPrint`.
+/// To be used in normal error checks.
+LIBSHIBOKEN_API PyObject *occurred();
+
+} // namespace Errors
+
+namespace Warnings
+{
+/// Warn about invalid return value of overwritten virtual
+LIBSHIBOKEN_API void warnInvalidReturnValue(const char *className, const char *functionName,
+ const char *expectedType, const char *actualType);
+LIBSHIBOKEN_API void warnDeprecated(const char *functionName);
+LIBSHIBOKEN_API void warnDeprecated(const char *className, const char *functionName);
+LIBSHIBOKEN_API void warnDeprecatedEnum(const char *enumName);
+LIBSHIBOKEN_API void warnDeprecatedEnumValue(const char *enumName, const char *valueName);
+} // namespace Warnings
+
+} // namespace Shiboken
+
+#endif // SBKERRORS_H
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
new file mode 100644
index 000000000..f31b8f4f7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -0,0 +1,424 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "autodecref.h"
+#include "pep384ext.h"
+#include "sbkenum.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "signature.h"
+#include "sbkfeature_base.h"
+#include "gilstate.h"
+
+#include <cctype>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Minimal __feature__ support in Shiboken
+//
+int currentSelectId(PyTypeObject *type)
+{
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *PyId = PyObject_GetAttr(tpDict.object(), PyName::select_id());
+ if (PyId == nullptr) {
+ PyErr_Clear();
+ return 0x00;
+ }
+ int sel = PyLong_AsLong(PyId);
+ Py_DECREF(PyId);
+ return sel;
+}
+
+static SelectableFeatureHook SelectFeatureSet = nullptr;
+static SelectableFeatureCallback featureCb = nullptr;
+
+void setSelectableFeatureCallback(SelectableFeatureCallback func)
+{
+ featureCb = func;
+}
+
+SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
+{
+ auto ret = SelectFeatureSet;
+ SelectFeatureSet = func;
+ if (featureCb)
+ featureCb(SelectFeatureSet != nullptr);
+ return ret;
+}
+//
+////////////////////////////////////////////////////////////////////////////
+
+// This useful function is for debugging
+void disassembleFrame(const char *marker)
+{
+ Shiboken::GilState gil;
+ PyObject *error_type, *error_value, *error_traceback;
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ static PyObject *dismodule = PyImport_ImportModule("dis");
+ static PyObject *disco = PyObject_GetAttrString(dismodule, "disco");
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _f_lineno = Shiboken::String::createStaticString("f_lineno");
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ static PyObject *const _co_filename = Shiboken::String::createStaticString("co_filename");
+ AutoDecRef ignore{};
+ auto *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+ if (frame == nullptr) {
+ fprintf(stdout, "\n%s BEGIN no frame END\n\n", marker);
+ } else {
+ AutoDecRef f_lasti(PyObject_GetAttr(frame, _f_lasti));
+ AutoDecRef f_lineno(PyObject_GetAttr(frame, _f_lineno));
+ AutoDecRef f_code(PyObject_GetAttr(frame, _f_code));
+ AutoDecRef co_filename(PyObject_GetAttr(f_code, _co_filename));
+ long line = PyLong_AsLong(f_lineno);
+ const char *fname = String::toCString(co_filename);
+ fprintf(stdout, "\n%s BEGIN line=%ld %s\n", marker, line, fname);
+ ignore.reset(PyObject_CallFunctionObjArgs(disco, f_code.object(), f_lasti.object(), nullptr));
+ fprintf(stdout, "%s END line=%ld %s\n\n", marker, line, fname);
+ }
+#if PY_VERSION_HEX >= 0x030C0000 && !Py_LIMITED_API
+ if (error_type)
+ PyErr_DisplayException(error_value);
+#endif
+ static PyObject *stdout_file = PySys_GetObject("stdout");
+ ignore.reset(PyObject_CallMethod(stdout_file, "flush", nullptr));
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+// python 3.12
+static int const CALL = 171;
+// Python 3.11
+static int const PRECALL = 166;
+// we have "big instructions" with gaps after them
+static int const LOAD_METHOD_GAP_311 = 10 * 2;
+static int const LOAD_ATTR_GAP_311 = 4 * 2;
+static int const LOAD_ATTR_GAP = 9 * 2;
+// Python 3.7 - 3.10
+static int const LOAD_METHOD = 160;
+static int const CALL_METHOD = 161;
+// Python 3.6
+static int const CALL_FUNCTION = 131;
+static int const LOAD_ATTR = 106;
+// NoGil (how long will this exist in this form?)
+static int const LOAD_METHOD_NOGIL = 55;
+static int const CALL_METHOD_NOGIL = 72;
+
+static bool currentOpcode_Is_CallMethNoArgs()
+{
+ // PYSIDE-2221: Special case for the NoGil version:
+ // Find out if we have such a version.
+ // We could also ask the variable `Py_NOGIL`.
+ static PyObject *flags = PySys_GetObject("flags");
+ static bool isNoGil = PyObject_HasAttrString(flags, "nogil");
+ // We look into the currently active operation if we are going to call
+ // a method with zero arguments.
+ auto *frame = PyEval_GetFrame();
+#if !Py_LIMITED_API && !defined(PYPY_VERSION)
+ auto *f_code = PyFrame_GetCode(frame);
+#else
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ AutoDecRef dec_f_code(PyObject_GetAttr(reinterpret_cast<PyObject *>(frame), _f_code));
+ auto *f_code = dec_f_code.object();
+#endif
+#if PY_VERSION_HEX >= 0x030B0000 && !Py_LIMITED_API
+ AutoDecRef dec_co_code(PyCode_GetCode(f_code));
+ Py_ssize_t f_lasti = PyFrame_GetLasti(frame);
+#else
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _co_code = Shiboken::String::createStaticString("co_code");
+ AutoDecRef dec_co_code(PyObject_GetAttr(reinterpret_cast<PyObject *>(f_code), _co_code));
+ AutoDecRef dec_f_lasti(PyObject_GetAttr(reinterpret_cast<PyObject *>(frame), _f_lasti));
+ Py_ssize_t f_lasti = PyLong_AsSsize_t(dec_f_lasti);
+#endif
+ Py_ssize_t code_len;
+ char *co_code{};
+ PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
+ uint8_t opcode1 = co_code[f_lasti];
+ if (isNoGil) {
+ uint8_t opcode2 = co_code[f_lasti + 4];
+ uint8_t oparg2 = co_code[f_lasti + 6];
+ return opcode1 == LOAD_METHOD_NOGIL && opcode2 == CALL_METHOD_NOGIL && oparg2 == 1;
+ }
+ uint8_t opcode2 = co_code[f_lasti + 2];
+ uint8_t oparg2 = co_code[f_lasti + 3];
+ static auto number = _PepRuntimeVersion();
+ if (number < 0x030B00)
+ return opcode1 == LOAD_METHOD && opcode2 == CALL_METHOD && oparg2 == 0;
+
+ if (number < 0x030C00) {
+ // With Python 3.11, the opcodes get bigger and change a bit.
+ // Note: The new adaptive opcodes are elegantly hidden and we
+ // don't need to take care of them.
+ if (opcode1 == LOAD_METHOD)
+ f_lasti += LOAD_METHOD_GAP_311;
+ else if (opcode1 == LOAD_ATTR)
+ f_lasti += LOAD_ATTR_GAP_311;
+ else
+ return false;
+
+ opcode2 = co_code[f_lasti + 2];
+ oparg2 = co_code[f_lasti + 3];
+
+ return opcode2 == PRECALL && oparg2 == 0;
+ }
+ // With Python 3.12, the opcodes get again bigger and change a bit.
+ // Note: The new adaptive opcodes are elegantly hidden and we
+ // don't need to take care of them.
+ if (opcode1 == LOAD_ATTR)
+ f_lasti += LOAD_ATTR_GAP;
+ else
+ return false;
+
+ opcode2 = co_code[f_lasti + 2];
+ oparg2 = co_code[f_lasti + 3];
+
+ return opcode2 == CALL && oparg2 == 0;
+}
+
+void initEnumFlagsDict(PyTypeObject *type)
+{
+ // We create a dict for all flag enums that holds the original C++ name
+ // and a dict that gives every enum/flag type name.
+ static PyObject *const split = Shiboken::String::createStaticString("split");
+ static PyObject *const colon = Shiboken::String::createStaticString(":");
+ auto sotp = PepType_SOTP(type);
+ auto **enumFlagInfo = sotp->enumFlagInfo;
+ auto *dict = PyDict_New();
+ auto *typeDict = PyDict_New();
+ for (; *enumFlagInfo; ++enumFlagInfo) {
+ AutoDecRef line(PyUnicode_FromString(*enumFlagInfo));
+ AutoDecRef parts(PyObject_CallMethodObjArgs(line, split, colon, nullptr));
+ auto *name = PyList_GetItem(parts, 0);
+ if (PyList_Size(parts) == 3) {
+ auto *key = PyList_GetItem(parts, 2);
+ auto *value = name;
+ PyDict_SetItem(dict, key, value);
+ }
+ auto *typeName = PyList_GetItem(parts, 1);
+ PyDict_SetItem(typeDict, name, typeName);
+ }
+ sotp->enumFlagsDict = dict;
+ sotp->enumTypeDict = typeDict;
+}
+
+static PyObject *replaceNoArgWithZero(PyObject *callable)
+{
+ static auto *partial = Pep_GetPartialFunction();
+ static auto *zero = PyLong_FromLong(0);
+ return PyObject_CallFunctionObjArgs(partial, callable, zero, nullptr);
+}
+
+static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name)
+{
+ // MRO has been observed to be 0 in case of errors with QML decorators
+ if (type == nullptr || type->tp_mro == nullptr)
+ return nullptr;
+ // Quick Check: Avoid "__..", "_slots", etc.
+ if (std::isalpha(Shiboken::String::toCString(name)[0]) == 0)
+ return nullptr;
+ static PyTypeObject *const EnumMeta = getPyEnumMeta();
+ static PyObject *const _member_map_ = String::createStaticString("_member_map_");
+ // This is similar to `find_name_in_mro`, but instead of looking directly into
+ // tp_dict, we also search for the attribute in local classes of that dict (Part 2).
+ PyObject *mro = type->tp_mro;
+ PyObject *result{};
+ assert(PyTuple_Check(mro));
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ for (idx = 0; idx < n; ++idx) {
+ auto *base = PyTuple_GET_ITEM(mro, idx);
+ auto *type_base = reinterpret_cast<PyTypeObject *>(base);
+ if (!SbkObjectType_Check(type_base))
+ continue;
+ auto sotp = PepType_SOTP(type_base);
+ // The EnumFlagInfo structure tells us if there are Enums at all.
+ const char **enumFlagInfo = sotp->enumFlagInfo;
+ if (!(enumFlagInfo))
+ continue;
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type_base);
+ bool useFakeRenames = !(Enum::enumOption & Enum::ENOPT_NO_FAKERENAMES);
+ if (useFakeRenames) {
+ auto *rename = PyDict_GetItem(sotp->enumFlagsDict, name);
+ if (rename) {
+ /*
+ * Part 1: Look into the enumFlagsDict if we have an old flags name.
+ * -------------------------------------------------------------
+ * We need to replace the parameterless
+
+ QtCore.Qt.Alignment()
+
+ * by the one-parameter call
+
+ QtCore.Qt.AlignmentFlag(0)
+
+ * That means: We need to bind the zero as default into a wrapper and
+ * return that to be called.
+ *
+ * Addendum:
+ * ---------
+ * We first need to look into the current opcode of the bytecode to find
+ * out if we have a call like above or just a type lookup.
+ */
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *flagType = PyDict_GetItem(tpDict.object(), rename);
+ if (currentOpcode_Is_CallMethNoArgs())
+ return replaceNoArgWithZero(flagType);
+ Py_INCREF(flagType);
+ return flagType;
+ }
+ }
+ bool useFakeShortcuts = !(Enum::enumOption & Enum::ENOPT_NO_FAKESHORTCUT);
+ if (useFakeShortcuts) {
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *dict = tpDict.object();
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ /*
+ * Part 2: Check for a duplication into outer scope.
+ * -------------------------------------------------
+ * We need to replace the shortcut
+
+ QtCore.Qt.AlignLeft
+
+ * by the correct call
+
+ QtCore.Qt.AlignmentFlag.AlignLeft
+
+ * That means: We need to search all Enums of the class.
+ */
+ if (Py_TYPE(value) == EnumMeta) {
+ auto *valtype = reinterpret_cast<PyTypeObject *>(value);
+ AutoDecRef valtypeDict(PepType_GetDict(valtype));
+ auto *member_map = PyDict_GetItem(valtypeDict.object(), _member_map_);
+ if (member_map && PyDict_Check(member_map)) {
+ result = PyDict_GetItem(member_map, name);
+ Py_XINCREF(result);
+ if (result)
+ return result;
+ }
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
+{
+ /*
+ * Note: This `type_getattro` version is only the default that comes
+ * from `PyType_Type.tp_getattro`. This does *not* interfere in any way
+ * with the complex `tp_getattro` of `QObject` and other instances.
+ * What we change here is the meta class of `QObject`.
+ */
+ static getattrofunc const type_getattro = PepExt_Type_GetGetAttroSlot(&PyType_Type);
+ static PyObject *const ignAttr1 = PyName::qtStaticMetaObject();
+ static PyObject *const ignAttr2 = PyMagicName::get();
+ static PyTypeObject *const EnumMeta = getPyEnumMeta();
+
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ auto *ret = type_getattro(reinterpret_cast<PyObject *>(type), name);
+
+ // PYSIDE-1735: Be forgiving with strict enums and fetch the enum, silently.
+ // The PYI files now look correct, but the old duplication is
+ // emulated here. This should be removed in Qt 7, see `parser.py`.
+ //
+ // FIXME PYSIDE7 should remove this forgiveness:
+ //
+ // The duplication of enum values into the enclosing scope, allowing to write
+ // Qt.AlignLeft instead of Qt.Alignment.AlignLeft, is still implemented but
+ // no longer advertized in PYI files or line completion.
+
+ if (ret && Py_TYPE(ret) == EnumMeta && currentOpcode_Is_CallMethNoArgs()) {
+ bool useZeroDefault = !(Enum::enumOption & Enum::ENOPT_NO_ZERODEFAULT);
+ if (useZeroDefault) {
+ // We provide a zero argument for compatibility if it is a call with no args.
+ auto *hold = replaceNoArgWithZero(ret);
+ Py_DECREF(ret);
+ ret = hold;
+ }
+ }
+
+ if (!ret && name != ignAttr1 && name != ignAttr2) {
+ PyObject *error_type{}, *error_value{}, *error_traceback{};
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ ret = lookupUnqualifiedOrOldEnum(type, name);
+ if (ret) {
+ Py_DECREF(error_type);
+ Py_XDECREF(error_value);
+ Py_XDECREF(error_traceback);
+ } else {
+ PyErr_Restore(error_type, error_value, error_traceback);
+ }
+ }
+ return ret;
+}
+
+PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void * /* context */)
+{
+ /*
+ * This is the override for getting a dict.
+ */
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();;
+ if (dict == nullptr)
+ Py_RETURN_NONE;
+ if (SelectFeatureSet != nullptr) {
+ SelectFeatureSet(type);
+ tpDict.reset(PepType_GetDict(type));
+ dict = tpDict.object();
+ }
+ return PyDictProxy_New(dict);
+}
+
+// These functions replace the standard PyObject_Generic(Get|Set)Attr functions.
+// They provide the default that "object" inherits.
+// Everything else is directly handled by cppgenerator that calls `Feature::Select`.
+PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ return PyObject_GenericGetAttr(obj, name);
+}
+
+int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ return PyObject_GenericSetAttr(obj, name, value);
+}
+
+const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->propertyStrings;
+}
+
+void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings)
+{
+ PepType_SOTP(type)->propertyStrings = strings;
+}
+
+void SbkObjectType_SetEnumFlagInfo(PyTypeObject *type, const char **strings)
+{
+ PepType_SOTP(type)->enumFlagInfo = strings;
+}
+
+// PYSIDE-1626: Enforcing a context switch without further action.
+void SbkObjectType_UpdateFeature(PyTypeObject *type)
+{
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.h b/sources/shiboken6/libshiboken/sbkfeature_base.h
new file mode 100644
index 000000000..290884062
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKFEATURE_BASE_H
+#define SBKFEATURE_BASE_H
+
+extern "C"
+{
+
+LIBSHIBOKEN_API int currentSelectId(PyTypeObject *type);
+LIBSHIBOKEN_API PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name);
+LIBSHIBOKEN_API PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context);
+LIBSHIBOKEN_API PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name);
+LIBSHIBOKEN_API int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value);
+
+} // extern "C"
+
+#endif // SBKFEATURE_BASE_H
diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp
new file mode 100644
index 000000000..f0136148b
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkmodule.cpp
@@ -0,0 +1,526 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkmodule.h"
+#include "autodecref.h"
+#include "basewrapper.h"
+#include "bindingmanager.h"
+#include "sbkstring.h"
+#include "sbkcppstring.h"
+#include "sbkconverter_p.h"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <cstring>
+
+/// This hash maps module objects to arrays of converters.
+using ModuleConvertersMap = std::unordered_map<PyObject *, SbkConverter **> ;
+
+/// This hash maps module objects to arrays of Python types.
+using ModuleTypesMap = std::unordered_map<PyObject *, Shiboken::Module::TypeInitStruct *> ;
+
+struct TypeCreationStruct
+{
+ Shiboken::Module::TypeCreationFunction func;
+ std::vector<std::string> subtypeNames;
+};
+
+/// This hash maps type names to type creation structs.
+using NameToTypeFunctionMap = std::unordered_map<std::string, TypeCreationStruct> ;
+
+/// This hash maps module objects to maps of names to functions.
+using ModuleToFuncsMap = std::unordered_map<PyObject *, NameToTypeFunctionMap> ;
+
+/// All types produced in imported modules are mapped here.
+static ModuleTypesMap moduleTypes;
+static ModuleConvertersMap moduleConverters;
+static ModuleToFuncsMap moduleToFuncs;
+
+namespace Shiboken
+{
+namespace Module
+{
+
+// PYSIDE-2404: Replacing the arguments generated by cpythonTypeNameExt
+// by a function call.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct)
+{
+ if (typeStruct.type != nullptr)
+ return typeStruct.type;
+
+ static PyObject *sysModules = PyImport_GetModuleDict();
+
+ // The slow path for initialization.
+ // We get the type by following the chain from the module.
+ // As soon as types[index] gets filled, we can stop.
+
+ std::string_view names(typeStruct.fullName);
+ const bool usePySide = names.compare(0, 8, "PySide6.") == 0;
+ auto dotPos = usePySide ? names.find('.', 8) : names.find('.');
+ auto startPos = dotPos + 1;
+ AutoDecRef modName(String::fromCppStringView(names.substr(0, dotPos)));
+ auto *modOrType = PyDict_GetItem(sysModules, modName);
+ if (modOrType == nullptr) {
+ PyErr_Format(PyExc_SystemError, "Module \"%U\" should already be in sys.modules",
+ modName.object());
+ return nullptr;
+ }
+
+ do {
+ dotPos = names.find('.', startPos);
+ auto typeName = dotPos != std::string::npos
+ ? names.substr(startPos, dotPos - startPos)
+ : names.substr(startPos);
+ startPos = dotPos + 1;
+ AutoDecRef obTypeName(String::fromCppStringView(typeName));
+ modOrType = PyObject_GetAttr(modOrType, obTypeName);
+ } while (typeStruct.type == nullptr && dotPos != std::string::npos);
+
+ return typeStruct.type;
+}
+
+static void incarnateHelper(PyObject *module, const std::string_view names,
+ const NameToTypeFunctionMap &nameToFunc)
+{
+ auto dotPos = names.find('.');
+ std::string::size_type startPos = 0;
+ auto *modOrType{module};
+ while (dotPos != std::string::npos) {
+ auto typeName = names.substr(startPos, dotPos - startPos);
+ AutoDecRef obTypeName(String::fromCppStringView(typeName));
+ modOrType = PyObject_GetAttr(modOrType, obTypeName);
+ startPos = dotPos + 1;
+ dotPos = names.find('.', startPos);
+ }
+ // now we have the type to create.
+ auto funcIter = nameToFunc.find(std::string(names));
+ // - call this function that returns a PyTypeObject
+ auto tcStruct = funcIter->second;
+ auto initFunc = tcStruct.func;
+ PyTypeObject *type = initFunc(modOrType);
+ auto name = names.substr(startPos);
+ PyObject_SetAttrString(modOrType, name.data(), reinterpret_cast<PyObject *>(type));
+}
+
+static void incarnateSubtypes(PyObject *module,
+ const std::vector<std::string> &nameList,
+ NameToTypeFunctionMap &nameToFunc)
+{
+ for (auto const & tableIter : nameList) {
+ std::string_view names(tableIter);
+ incarnateHelper(module, names, nameToFunc);
+ }
+}
+
+static PyTypeObject *incarnateType(PyObject *module, const char *name,
+ NameToTypeFunctionMap &nameToFunc)
+{
+ // - locate the name and retrieve the generating function
+ auto funcIter = nameToFunc.find(name);
+ if (funcIter == nameToFunc.end()) {
+ // attribute does really not exist.
+ PyErr_SetNone(PyExc_AttributeError);
+ return nullptr;
+ }
+ // - call this function that returns a PyTypeObject
+ auto tcStruct = funcIter->second;
+ auto initFunc = tcStruct.func;
+ auto *modOrType{module};
+
+ // PYSIDE-2404: Make sure that no switching happens during type creation.
+ auto saveFeature = initSelectableFeature(nullptr);
+ PyTypeObject *type = initFunc(modOrType);
+ if (!tcStruct.subtypeNames.empty())
+ incarnateSubtypes(module, tcStruct.subtypeNames, nameToFunc);
+ initSelectableFeature(saveFeature);
+
+ // - assign this object to the name in the module
+ auto *res = reinterpret_cast<PyObject *>(type);
+ Py_INCREF(res);
+ PyModule_AddObject(module, name, res); // steals reference
+ // - remove the entry, if not by something cleared.
+ if (!nameToFunc.empty())
+ nameToFunc.erase(funcIter);
+ // - return the PyTypeObject.
+ return type;
+}
+
+// PYSIDE-2404: Make sure that the mentioned classes really exist.
+// Used in `Pyside::typeName`. Because the result will be cached by
+// the creation of the type(s), this is efficient.
+void loadLazyClassesWithName(const char *name)
+{
+ for (auto const & tableIter : moduleToFuncs) {
+ auto nameToFunc = tableIter.second;
+ auto funcIter = nameToFunc.find(name);
+ if (funcIter != nameToFunc.end()) {
+ // attribute exists in the lazy types.
+ auto *module = tableIter.first;
+ incarnateType(module, name, nameToFunc);
+ }
+ }
+}
+
+// PYSIDE-2404: Completely load all not yet loaded classes.
+// This is needed to resolve a star import.
+void resolveLazyClasses(PyObject *module)
+{
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ if (tableIter == moduleToFuncs.end())
+ return;
+
+ // - see if there are still unloaded elements
+ auto &nameToFunc = tableIter->second;
+
+ // - incarnate all types.
+ while (!nameToFunc.empty()) {
+ auto it = nameToFunc.begin();
+ auto attrNameStr = it->first;
+ incarnateType(module, attrNameStr.c_str(), nameToFunc);
+ }
+}
+
+// PYSIDE-2404: Override the gettattr function of modules.
+static getattrofunc origModuleGetattro{};
+
+// PYSIDE-2404: Use the patched module getattr to do on-demand initialization.
+// This modifies _all_ modules but should have no impact.
+static PyObject *PyModule_lazyGetAttro(PyObject *module, PyObject *name)
+{
+ // - check if the attribute is present and return it.
+ auto *attr = PyObject_GenericGetAttr(module, name);
+ // - we handle AttributeError, only.
+ if (!(attr == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)))
+ return attr;
+
+ PyErr_Clear();
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ // - if this is not our module, use the original
+ if (tableIter == moduleToFuncs.end())
+ return origModuleGetattro(module, name);
+
+ // - locate the name and retrieve the generating function
+ const char *attrNameStr = Shiboken::String::toCString(name);
+ auto &nameToFunc = tableIter->second;
+ // - create the real type and handle subtypes
+ auto *type = incarnateType(module, attrNameStr, nameToFunc);
+ auto *ret = reinterpret_cast<PyObject *>(type);
+ // - if attribute does really not exist use the original
+ if (ret == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ return origModuleGetattro(module, name);
+ }
+ return ret;
+}
+
+// PYSIDE-2404: Supply a new module dir for not yet visible entries.
+// This modification is only for "our" modules.
+static PyObject *_module_dir_template(PyObject * /* self */, PyObject *args)
+{
+ static PyObject *const _dict = Shiboken::String::createStaticString("__dict__");
+ // The dir function must replace all of the builtin function.
+ PyObject *module{};
+ if (!PyArg_ParseTuple(args, "O", &module))
+ return nullptr;
+
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ Shiboken::AutoDecRef dict(PyObject_GetAttr(module, _dict));
+ auto *ret = PyDict_Keys(dict);
+ // Now add all elements that were not yet in the dict.
+ auto &nameToFunc = tableIter->second;
+ for (const auto &funcIter : nameToFunc) {
+ const char *name = funcIter.first.c_str();
+ Shiboken::AutoDecRef pyName(PyUnicode_FromString(name));
+ PyList_Append(ret, pyName);
+ }
+ return ret;
+}
+
+static PyMethodDef module_methods[] = {
+ {"__dir__", (PyCFunction)_module_dir_template, METH_VARARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+// Python 3.8 - 3.12
+static int const LOAD_CONST_312 = 100;
+static int const IMPORT_NAME_312 = 108;
+
+static bool isImportStar(PyObject *module)
+{
+ // Find out whether we have a star import. This must work even
+ // when we have no import support from feature.
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _f_back = Shiboken::String::createStaticString("f_back");
+ static PyObject *const _co_code = Shiboken::String::createStaticString("co_code");
+ static PyObject *const _co_consts = Shiboken::String::createStaticString("co_consts");
+ static PyObject *const _co_names = Shiboken::String::createStaticString("co_names");
+
+ auto *obFrame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+ if (obFrame == nullptr)
+ return true; // better assume worst-case.
+
+ Py_INCREF(obFrame);
+ AutoDecRef dec_frame(obFrame);
+
+ // Calculate the offset of the running import_name opcode on the stack.
+ // Right before that there must be a load_const with the tuple `("*",)`.
+ while (dec_frame.object() != Py_None) {
+ AutoDecRef dec_f_code(PyObject_GetAttr(dec_frame, _f_code));
+ AutoDecRef dec_co_code(PyObject_GetAttr(dec_f_code, _co_code));
+ AutoDecRef dec_f_lasti(PyObject_GetAttr(dec_frame, _f_lasti));
+ Py_ssize_t f_lasti = PyLong_AsSsize_t(dec_f_lasti);
+ Py_ssize_t code_len;
+ char *co_code{};
+ PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
+ uint8_t opcode2 = co_code[f_lasti];
+ uint8_t opcode1 = co_code[f_lasti - 2];
+ if (opcode1 == LOAD_CONST_312 && opcode2 == IMPORT_NAME_312) {
+ uint8_t oparg1 = co_code[f_lasti - 1];
+ uint8_t oparg2 = co_code[f_lasti + 1];
+ AutoDecRef dec_co_consts(PyObject_GetAttr(dec_f_code, _co_consts));
+ auto *fromlist = PyTuple_GetItem(dec_co_consts, oparg1);
+ if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+ && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*') {
+ AutoDecRef dec_co_names(PyObject_GetAttr(dec_f_code, _co_names));
+ const char *name = String::toCString(PyTuple_GetItem(dec_co_names, oparg2));
+ const char *modName = PyModule_GetName(module);
+ if (std::strcmp(name, modName) == 0)
+ return true;
+ }
+ }
+ dec_frame.reset(PyObject_GetAttr(dec_frame, _f_back));
+ }
+ return false;
+}
+
+// PYSIDE-2404: These modules produce ambiguous names which we cannot handle, yet.
+static std::unordered_set<std::string> dontLazyLoad{
+ "testbinding"
+};
+
+static const std::unordered_set<std::string> knownModules{
+ "shiboken6.Shiboken",
+ "minimal",
+ "other",
+ "sample",
+ "smart",
+ "scriptableapplication",
+ "testbinding"
+};
+
+static bool canNotLazyLoad(PyObject *module)
+{
+ const char *modName = PyModule_GetName(module);
+
+ // There are no more things that must be disabled :-D
+ return dontLazyLoad.find(modName) != dontLazyLoad.end();
+}
+
+static bool shouldLazyLoad(PyObject *module)
+{
+ const char *modName = PyModule_GetName(module);
+
+ if (knownModules.find(modName) != knownModules.end())
+ return true;
+ return std::strncmp(modName, "PySide6.", 8) == 0;
+}
+
+static int lazyLoadDefault()
+{
+#ifndef PYPY_VERSION
+ int result = 1;
+#else
+ int result = 0;
+#endif
+ if (auto *flag = getenv("PYSIDE6_OPTION_LAZY"))
+ result = std::atoi(flag);
+ return result;
+}
+
+void checkIfShouldLoadImmediately(PyObject *module, const std::string &name,
+ const NameToTypeFunctionMap &nameToFunc)
+{
+ static const int value = lazyLoadDefault();
+
+ // PYSIDE-2404: Lazy Loading
+ //
+ // Options:
+ // 0 - switch lazy loading off.
+ // 1 - lazy loading for all known modules.
+ // 3 - lazy loading for any module.
+ //
+ // By default we lazy load all known modules (option = 1).
+ if (value == 0 // completely disabled
+ || canNotLazyLoad(module) // for some reason we cannot lazy load
+ || (value == 1 && !shouldLazyLoad(module)) // not a known module
+ ) {
+ incarnateHelper(module, name, nameToFunc);
+ }
+}
+
+void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func)
+{
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ // - Assign the name/generating function tcStruct.
+ auto &nameToFunc = tableIter->second;
+ TypeCreationStruct tcStruct{func, {}};
+ auto nit = nameToFunc.find(name);
+ if (nit == nameToFunc.end())
+ nameToFunc.insert(std::make_pair(name, tcStruct));
+ else
+ nit->second = tcStruct;
+
+ checkIfShouldLoadImmediately(module, name, nameToFunc);
+}
+
+void AddTypeCreationFunction(PyObject *module,
+ const char *containerName,
+ TypeCreationFunction func,
+ const char *namePath)
+{
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ // - Assign the name/generating function tcStruct.
+ auto &nameToFunc = tableIter->second;
+ auto nit = nameToFunc.find(containerName);
+
+ // - insert namePath into the subtype vector of the main type.
+ nit->second.subtypeNames.push_back(namePath);
+ // - insert it also as its own entry.
+ nit = nameToFunc.find(namePath);
+ TypeCreationStruct tcStruct{func, {}};
+ if (nit == nameToFunc.end())
+ nameToFunc.insert(std::make_pair(namePath, tcStruct));
+ else
+ nit->second = tcStruct;
+
+ checkIfShouldLoadImmediately(module, namePath, nameToFunc);
+}
+
+PyObject *import(const char *moduleName)
+{
+ PyObject *sysModules = PyImport_GetModuleDict();
+ PyObject *module = PyDict_GetItemString(sysModules, moduleName);
+ if (module != nullptr)
+ Py_INCREF(module);
+ else
+ module = PyImport_ImportModule(moduleName);
+
+ if (module == nullptr)
+ PyErr_Format(PyExc_ImportError, "could not import module '%s'", moduleName);
+
+ return module;
+}
+
+// PYSIDE-2404: Redirecting import for "import *" support.
+//
+// The first import will be handled by the isImportStar function.
+// But the same module might be imported twice, which would give no
+// introspection due to module caching.
+
+static PyObject *origImportFunc{};
+
+static PyObject *lazy_import(PyObject * /* self */, PyObject *args, PyObject *kwds)
+{
+ auto *ret = PyObject_Call(origImportFunc, args, kwds);
+ if (ret != nullptr) {
+ // PYSIDE-2404: Support star import when lazy loading.
+ if (PyTuple_Size(args) >= 4) {
+ auto *fromlist = PyTuple_GetItem(args, 3);
+ if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+ && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*')
+ Shiboken::Module::resolveLazyClasses(ret);
+ }
+ }
+ return ret;
+}
+
+static PyMethodDef lazy_methods[] = {
+ {"__lazy_import__", (PyCFunction)lazy_import, METH_VARARGS | METH_KEYWORDS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+PyObject *create(const char * /* modName */, void *moduleData)
+{
+ static auto *sysModules = PyImport_GetModuleDict();
+ static auto *builtins = PyEval_GetBuiltins();
+ static auto *partial = Pep_GetPartialFunction();
+ static bool lazy_init{};
+
+ Shiboken::init();
+ auto *module = PyModule_Create(reinterpret_cast<PyModuleDef *>(moduleData));
+
+ // Setup of a dir function for "missing" classes.
+ auto *moduleDirTemplate = PyCFunction_NewEx(module_methods, nullptr, nullptr);
+ // Turn this function into a bound object, so we have access to the module.
+ auto *moduleDir = PyObject_CallFunctionObjArgs(partial, moduleDirTemplate, module, nullptr);
+ PyModule_AddObject(module, module_methods->ml_name, moduleDir); // steals reference
+ // Insert an initial empty table for the module.
+ NameToTypeFunctionMap empty;
+ moduleToFuncs.insert(std::make_pair(module, empty));
+
+ // A star import must be done unconditionally. Use the complete name.
+ if (isImportStar(module))
+ dontLazyLoad.insert(PyModule_GetName(module));
+
+ if (!lazy_init) {
+ // Install the getattr patch.
+ origModuleGetattro = PyModule_Type.tp_getattro;
+ PyModule_Type.tp_getattro = PyModule_lazyGetAttro;
+ // Add the lazy import redirection, keeping a reference.
+ origImportFunc = PyDict_GetItemString(builtins, "__import__");
+ Py_INCREF(origImportFunc);
+ AutoDecRef func(PyCFunction_NewEx(lazy_methods, nullptr, nullptr));
+ PyDict_SetItemString(builtins, "__import__", func);
+ // Everything is set.
+ lazy_init = true;
+ }
+ // PYSIDE-2404: Nuitka inserts some additional code in standalone mode
+ // in an invisible virtual module (i.e. `QtCore-postLoad`)
+ // that gets imported before the running import can call
+ // `_PyImport_FixupExtensionObject` which does the insertion
+ // into `sys.modules`. This can cause a race condition.
+ // Insert the module early into the module dict to prevend recursion.
+ PyDict_SetItemString(sysModules, PyModule_GetName(module), module);
+ // Clear the non-existing name cache because we have a new module.
+ Shiboken::Conversions::clearNegativeLazyCache();
+ return module;
+}
+
+void registerTypes(PyObject *module, TypeInitStruct *types)
+{
+ auto iter = moduleTypes.find(module);
+ if (iter == moduleTypes.end())
+ moduleTypes.insert(std::make_pair(module, types));
+}
+
+TypeInitStruct *getTypes(PyObject *module)
+{
+ auto iter = moduleTypes.find(module);
+ return (iter == moduleTypes.end()) ? 0 : iter->second;
+}
+
+void registerTypeConverters(PyObject *module, SbkConverter **converters)
+{
+ auto iter = moduleConverters.find(module);
+ if (iter == moduleConverters.end())
+ moduleConverters.insert(std::make_pair(module, converters));
+}
+
+SbkConverter **getTypeConverters(PyObject *module)
+{
+ auto iter = moduleConverters.find(module);
+ return (iter == moduleConverters.end()) ? 0 : iter->second;
+}
+
+} } // namespace Shiboken::Module
diff --git a/sources/shiboken6/libshiboken/sbkmodule.h b/sources/shiboken6/libshiboken/sbkmodule.h
new file mode 100644
index 000000000..2c407e09d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkmodule.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_MODULE_H
+#define SBK_MODULE_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C"
+{
+struct SbkConverter;
+}
+
+namespace Shiboken::Module {
+
+struct TypeInitStruct
+{
+ PyTypeObject *type;
+ const char *fullName;
+};
+
+/// PYSIDE-2404: Replacing the arguments in cpythonTypeNameExt by a function.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct);
+
+/// PYSIDE-2404: Make sure that mentioned classes really exist.
+LIBSHIBOKEN_API void loadLazyClassesWithName(const char *name);
+
+/// PYSIDE-2404: incarnate all classes for star imports.
+LIBSHIBOKEN_API void resolveLazyClasses(PyObject *module);
+
+/**
+ * Imports and returns the module named \p moduleName, or a NULL pointer in case of failure.
+ * If the module is already imported, it increments its reference count before returning it.
+ * \returns the module specified in \p moduleName or NULL if an error occurs.
+ */
+LIBSHIBOKEN_API PyObject *import(const char *moduleName);
+
+/**
+ * Creates a new Python module named \p moduleName using the information passed in \p moduleData.
+ * In fact, \p moduleData expects a "PyMethodDef *" object, but that's for Python 2. A "void*"
+ * was preferred to make this work with future Python 3 support.
+ * \returns a newly created module.
+ */
+LIBSHIBOKEN_API PyObject *create(const char *moduleName, void *moduleData);
+
+using TypeCreationFunction = PyTypeObject *(*)(PyObject *module);
+
+/// Adds a type creation function to the module.
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func);
+
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func,
+ const char *containerName);
+
+/**
+ * Registers the list of types created by \p module.
+ * \param module Module where the types were created.
+ * \param types Array of PyTypeObject *objects representing the types created on \p module.
+ */
+LIBSHIBOKEN_API void registerTypes(PyObject *module, TypeInitStruct *types);
+
+/**
+ * Retrieves the array of types.
+ * \param module Module where the types were created.
+ * \returns A pointer to the PyTypeObject *array of types.
+ */
+LIBSHIBOKEN_API TypeInitStruct *getTypes(PyObject *module);
+
+/**
+ * Registers the list of converters created by \p module for non-wrapper types.
+ * \param module Module where the converters were created.
+ * \param converters Array of SbkConverter *objects representing the converters created on \p module.
+ */
+LIBSHIBOKEN_API void registerTypeConverters(PyObject *module, SbkConverter **converters);
+
+/**
+ * Retrieves the array of converters.
+ * \param module Module where the converters were created.
+ * \returns A pointer to the SbkConverter *array of converters.
+ */
+LIBSHIBOKEN_API SbkConverter **getTypeConverters(PyObject *module);
+
+} // namespace Shiboken::Module
+
+#endif // SBK_MODULE_H
diff --git a/sources/shiboken6/libshiboken/sbknumpy.cpp b/sources/shiboken6/libshiboken/sbknumpy.cpp
new file mode 100644
index 000000000..b6422e73f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpy.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#ifdef HAVE_NUMPY
+// Include numpy first to get the proper PyArray_Check
+# include <numpy/arrayobject.h>
+#endif
+
+#include "helper.h"
+#include "sbknumpycheck.h"
+#include "sbkcpptonumpy.h"
+#include "sbknumpyview.h"
+
+#include <algorithm>
+
+namespace Shiboken::Numpy
+{
+
+#ifdef HAVE_NUMPY
+static void initNumPy()
+{
+ // PYSIDE-2404: Delay-initialize numpy from check() as it causes a
+ // significant startup delay (~770 allocations in memray)
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+ // Expanded from macro "import_array" in __multiarray_api.h
+ // Make sure to read about the magic defines PY_ARRAY_UNIQUE_SYMBOL etc.,
+ // when changing this or spreading the code over several source files.
+ if (_import_array() < 0)
+ PyErr_Print();
+}
+#endif // HAVE_NUMPY
+
+bool check(PyObject *pyIn)
+{
+#ifdef HAVE_NUMPY
+ initNumPy();
+ return PyArray_Check(pyIn);
+#else
+ SBK_UNUSED(pyIn);
+ return false;
+#endif
+}
+
+} //namespace Shiboken::Numpy
+
+// Include all sources files using numpy so that they are in the same
+// translation unit (see comment at initNumPyArrayConverters()).
+
+#include "sbknumpyview.cpp"
+#include "sbkcpptonumpy.cpp"
+#ifdef HAVE_NUMPY
+# include "sbknumpyarrayconverter.cpp"
+#endif
diff --git a/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp b/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp
new file mode 100644
index 000000000..835a97524
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp
@@ -0,0 +1,270 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+#include "sbkarrayconverter.h"
+#include "helper.h"
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+#include "sbkarrayconverter_p.h"
+
+#include <algorithm>
+#include <iostream>
+#include <cstdint>
+
+enum { debugNumPy = 0 };
+
+struct TypeCharMapping
+{
+ NPY_TYPES type;
+ const char *name;
+};
+
+static const TypeCharMapping typeCharMappings[] = {
+{NPY_BYTE, "NPY_BYTE"},
+{NPY_UBYTE, "NPY_UBYTE"},
+{NPY_SHORT, "NPY_SHORT"},
+{NPY_USHORT, "NPY_USHORT"},
+{NPY_INT, "NPY_INT"},
+{NPY_UINT, "NPY_UINT"},
+{NPY_LONG, "NPY_LONG"},
+{NPY_ULONG, "NPY_ULONG"},
+{NPY_LONGLONG, "NPY_LONGLONG"},
+{NPY_ULONGLONG, "NPY_ULONGLONG"},
+{NPY_FLOAT, "NPY_FLOAT"},
+{NPY_DOUBLE, "NPY_DOUBLE"}
+};
+
+const char *npTypeName(npy_intp t)
+{
+ const TypeCharMapping *end = typeCharMappings + sizeof(typeCharMappings) / sizeof(typeCharMappings[0]);
+ const TypeCharMapping *result =
+ std::find_if(typeCharMappings, end,
+ [t] (const TypeCharMapping &m) { return m.type == t; });
+ return result != end ? result->name : nullptr;
+}
+
+std::ostream &operator<<(std::ostream &str, PyArrayObject *o)
+{
+ str << "PyArrayObject(";
+ if (o) {
+ const npy_intp npType = PyArray_TYPE(o);
+ if (const char *name = npTypeName(npType))
+ str << name;
+ else
+ str << "type=" << npType;
+ const int nDim = PyArray_NDIM(o);
+ const npy_intp *dims = PyArray_DIMS(o);
+ for (int d = 0; d < nDim; ++d)
+ str << '[' << dims[d] << ']';
+ str << ", ";
+ const int flags = PyArray_FLAGS(o);
+ if ((flags & NPY_ARRAY_C_CONTIGUOUS) != 0)
+ str << " NPY_ARRAY_C_CONTIGUOUS";
+ if ((flags & NPY_ARRAY_F_CONTIGUOUS) != 0)
+ str << " NPY_ARRAY_F_CONTIGUOUS";
+ if ((flags & NPY_ARRAY_OWNDATA) != 0)
+ str << " NPY_ARRAY_OWNDATA";
+ if ((flags & NPY_ARRAY_FORCECAST) != 0)
+ str << " NPY_ARRAY_FORCECAST";
+ if ((flags & NPY_ARRAY_ENSURECOPY) != 0)
+ str << " NPY_ARRAY_ENSURECOPY";
+ if ((flags & NPY_ARRAY_ENSUREARRAY) != 0)
+ str << " NPY_ARRAY_ENSUREARRAY";
+ if ((flags & NPY_ARRAY_ELEMENTSTRIDES) != 0)
+ str << " NPY_ARRAY_ELEMENTSTRIDES";
+ if ((flags & NPY_ARRAY_ALIGNED) != 0)
+ str << " NPY_ARRAY_ALIGNED";
+ if ((flags & NPY_ARRAY_NOTSWAPPED) != 0)
+ str << " NPY_ARRAY_NOTSWAPPED";
+ if ((flags & NPY_ARRAY_WRITEABLE) != 0)
+ str << " NPY_ARRAY_WRITEABLE";
+#if NPY_VERSION >= 0x00000010 // NPY_1_23_API_VERSION
+ if ((flags & NPY_ARRAY_WRITEBACKIFCOPY) != 0)
+ str << " NPY_ARRAY_WRITEBACKIFCOPY";
+#else
+ if ((flags & NPY_ARRAY_UPDATEIFCOPY) != 0)
+ str << " NPY_ARRAY_UPDATEIFCOPY";
+#endif
+ } else {
+ str << '0';
+ }
+ str << ')';
+ return str;
+}
+
+namespace Shiboken::Conversions {
+
+// Internals from sbkarrayconverter.cpp
+SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc);
+void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c);
+SbkArrayConverter *unimplementedArrayConverter();
+
+template <int dimension>
+static bool isPrimitiveArray(PyObject *pyIn, int expectedNpType)
+{
+ Shiboken::Numpy::initNumPy();
+ if (!PyArray_Check(pyIn))
+ return false;
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ if (debugNumPy) {
+ std::cerr << __FUNCTION__ << "(expectedNpType=" << expectedNpType;
+ if (const char *name = npTypeName(expectedNpType))
+ std::cerr << " (" << name << ')';
+ std::cerr << ' ' << pya << '\n';
+ }
+
+ const int dim = PyArray_NDIM(pya);
+ if (dim != dimension) {
+ warning(PyExc_RuntimeWarning, 0,
+ "%d dimensional numpy array passed to a function expecting a %d dimensional array.",
+ dim, dimension);
+ return false;
+ }
+ if ((PyArray_FLAGS(pya) & NPY_ARRAY_C_CONTIGUOUS) == 0) {
+ warning(PyExc_RuntimeWarning, 0,
+ "Cannot handle numpy arrays that do not have NPY_ARRAY_C_CONTIGUOUS set.");
+ return false;
+ }
+ const int actualNpType = PyArray_TYPE(pya);
+ if (actualNpType != expectedNpType) {
+ const char *actualName = npTypeName(actualNpType);
+ const char *expectedName = npTypeName(expectedNpType);
+ warning(PyExc_RuntimeWarning, 0,
+ "A numpy array of type %d (%s) was passed to a function expecting type %d (%s).",
+ actualNpType, actualName ? actualName : "",
+ expectedNpType, expectedName ? expectedName : "");
+ return false;
+ }
+ return true;
+}
+
+static inline bool primitiveArrayCheck1(PyObject *pyIn, int expectedNpType, int expectedSize)
+{
+ if (!isPrimitiveArray<1>(pyIn, expectedNpType))
+ return false;
+ if (expectedSize >= 0) {
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const int size = int(PyArray_DIMS(pya)[0]);
+ if (size < expectedSize) {
+ warning(PyExc_RuntimeWarning, 0, "A numpy array of size %d was passed to a function expects %d.",
+ size, expectedSize);
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert one-dimensional array
+template <class T>
+static void convertArray1(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<T> *>(cppOut);
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const npy_intp size = PyArray_DIMS(pya)[0];
+ if (debugNumPy)
+ std::cerr << __FUNCTION__ << ' ' << size << '\n';
+ handle->setData(reinterpret_cast<T *>(PyArray_DATA(pya)), size_t(size));
+}
+
+// Convert 2 dimensional array
+template <class T>
+static void convertArray2(PyObject *pyIn, void *cppOut)
+{
+ typedef typename Array2Handle<T, 1>::RowType RowType;
+ auto *handle = reinterpret_cast<Array2Handle<T, 1> *>(cppOut);
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ handle->setData(reinterpret_cast<RowType *>(PyArray_DATA(pya)));
+}
+
+template <class T, int NumPyType>
+static PythonToCppFunc checkArray1(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return primitiveArrayCheck1(pyIn, NumPyType, dim1) ? convertArray1<T> : nullptr;
+}
+
+static inline bool primitiveArrayCheck2(PyObject *pyIn, int expectedNpType, int expectedDim1, int expectedDim2)
+{
+ if (!isPrimitiveArray<2>(pyIn, expectedNpType))
+ return false;
+ if (expectedDim2 >= 0) {
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const int dim1 = int(PyArray_DIMS(pya)[0]);
+ const int dim2 = int(PyArray_DIMS(pya)[1]);
+ if (dim1 != expectedDim1 || dim2 != expectedDim2) {
+ warning(PyExc_RuntimeWarning, 0, "A numpy array of size %dx%d was passed to a function that expects %dx%d.",
+ dim1, dim2, expectedDim1, expectedDim2);
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class T, int NumPyType>
+static PythonToCppFunc checkArray2(PyObject *pyIn, int dim1, int dim2)
+{
+ return primitiveArrayCheck2(pyIn, NumPyType, dim1, dim2) ? convertArray2<T> : nullptr;
+}
+
+template <class T>
+static void setOrExtendArrayConverter(int dimension, IsArrayConvertibleToCppFunc toCppCheckFunc)
+{
+ // PYSIDE-2404/FIXME: When adding a C++ -> Python conversion, be sure
+ // to delay-initialize numpy in the converter (similar to the
+ // initialization in check() for the Python -> C++ conversion).
+ SbkArrayConverter *arrayConverter = ArrayTypeConverter<T>(dimension);
+ if (arrayConverter == unimplementedArrayConverter()) {
+ arrayConverter = createArrayConverter(toCppCheckFunc);
+ setArrayTypeConverter(ArrayTypeIndex<T>::index, dimension, arrayConverter);
+ } else {
+ arrayConverter->toCppConversions.push_back(toCppCheckFunc);
+ }
+}
+
+// Extend the converters for primitive type one-dimensional arrays by NumPy ones.
+template <class T, int NumPyType>
+static inline void extendArrayConverter1()
+{
+ setOrExtendArrayConverter<T>(1, checkArray1<T, NumPyType>);
+}
+
+// Extend the converters for primitive type one-dimensional arrays by NumPy ones.
+template <class T, int NumPyType>
+static inline void extendArrayConverter2()
+{
+ setOrExtendArrayConverter<T>(2, checkArray2<T, NumPyType>);
+}
+
+void initNumPyArrayConverters()
+{
+ // Extend the converters for primitive types by NumPy ones.
+ extendArrayConverter1<short, NPY_SHORT>();
+ extendArrayConverter2<short, NPY_SHORT>();
+ extendArrayConverter1<unsigned short, NPY_SHORT>();
+ extendArrayConverter2<unsigned short, NPY_SHORT>();
+ extendArrayConverter1<int, NPY_INT>();
+ extendArrayConverter2<int, NPY_INT>();
+ extendArrayConverter1<unsigned int, NPY_UINT>();
+ extendArrayConverter2<unsigned int, NPY_UINT>();
+ extendArrayConverter1<long long, NPY_LONGLONG>();
+ extendArrayConverter2<long long, NPY_LONGLONG>();
+ extendArrayConverter1<unsigned long long, NPY_ULONGLONG>();
+ if (sizeof(long) == 8) { // UNIX/LP64: ints typically come as long
+ extendArrayConverter1<long long, NPY_LONG>();
+ extendArrayConverter2<long long, NPY_LONG>();
+ extendArrayConverter1<unsigned long long, NPY_ULONG>();
+ extendArrayConverter2<unsigned long long, NPY_ULONG>();
+ } else if (sizeof(long) == sizeof(int)) {
+ extendArrayConverter1<int, NPY_LONG>();
+ extendArrayConverter1<unsigned, NPY_ULONG>();
+ extendArrayConverter2<int, NPY_LONG>();
+ extendArrayConverter2<unsigned, NPY_ULONG>();
+ }
+ extendArrayConverter1<float, NPY_FLOAT>();
+ extendArrayConverter2<float, NPY_FLOAT>();
+ extendArrayConverter1<double, NPY_DOUBLE>();
+ extendArrayConverter2<double, NPY_DOUBLE>();
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbknumpycheck.h b/sources/shiboken6/libshiboken/sbknumpycheck.h
new file mode 100644
index 000000000..cfe65372c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpycheck.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKNUMPYCHECK_H
+#define SBKNUMPYCHECK_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+
+// This header provides a PyArray_Check() definition that can be used to avoid
+// having to include the numpy headers. When using numpy headers, make sure
+// to include this header after them to skip the definition. Also remember
+// that import_array() must then be called to initialize numpy.
+
+namespace Shiboken::Numpy
+{
+
+/// Check whether the object is a PyArrayObject
+/// \param pyIn object
+/// \return Whether it is a PyArrayObject
+LIBSHIBOKEN_API bool check(PyObject *pyIn);
+
+} //namespace Shiboken::Numpy
+
+#ifndef PyArray_Check
+# define PyArray_Check(op) Shiboken::Numpy::check(op)
+#endif
+
+#endif // SBKNUMPYCHECK_H
diff --git a/sources/shiboken6/libshiboken/sbknumpyview.cpp b/sources/shiboken6/libshiboken/sbknumpyview.cpp
new file mode 100644
index 000000000..bafbf8038
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyview.cpp
@@ -0,0 +1,265 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+#include "helper.h"
+#include <iostream>
+#include <iomanip>
+#include <optional>
+
+#ifdef HAVE_NUMPY
+
+namespace Shiboken {
+namespace Numpy {
+
+static std::optional<View::Type> viewTypeFromNumPy(int npt)
+{
+ switch (npt) {
+ case NPY_SHORT:
+ return View::Int16;
+ case NPY_USHORT:
+ return View::Unsigned16;
+ case NPY_INT:
+ return View::Int;
+ case NPY_UINT:
+ return View::Unsigned;
+ case NPY_LONG:
+ if constexpr (sizeof(long) == sizeof(int))
+ return View::Int;
+ if constexpr (sizeof(long) == sizeof(int64_t))
+ return View::Int64;
+ break;
+ case NPY_ULONG:
+ if constexpr (sizeof(long) == sizeof(int))
+ return View::Unsigned;
+ if constexpr (sizeof(long) == sizeof(int64_t))
+ return View::Unsigned64;
+ break;
+ case NPY_LONGLONG:
+ if constexpr (sizeof(long long) == 8)
+ return View::Int64;
+ break;
+ case NPY_ULONGLONG:
+ if constexpr (sizeof(long long) == 8)
+ return View::Unsigned64;
+ break;
+ case NPY_FLOAT:
+ return View::Float;
+ case NPY_DOUBLE:
+ return View::Double;
+ default:
+ break;
+ }
+ return {};
+}
+
+View View::fromPyObject(PyObject *pyIn)
+{
+ if (pyIn == nullptr || PyArray_Check(pyIn) == 0)
+ return {};
+ auto *ar = reinterpret_cast<PyArrayObject *>(pyIn);
+ if ((PyArray_FLAGS(ar) & NPY_ARRAY_C_CONTIGUOUS) == 0)
+ return {};
+ const int ndim = PyArray_NDIM(ar);
+ if (ndim > 2)
+ return {};
+
+ const auto typeO = viewTypeFromNumPy(PyArray_TYPE(ar));
+ if (!typeO.has_value())
+ return {};
+
+ View result;
+ result.ndim = ndim;
+ result.type = typeO.value();
+ result.data = PyArray_DATA(ar);
+ result.dimensions[0] = PyArray_DIMS(ar)[0];
+ result.stride[0] = PyArray_STRIDES(ar)[0];
+ if (ndim > 1) {
+ result.dimensions[1] = PyArray_DIMS(ar)[1];
+ result.stride[1] = PyArray_STRIDES(ar)[1];
+ } else {
+ result.dimensions[1] = result.stride[1] = 0;
+ }
+ return result;
+}
+
+} // namespace Numpy
+
+template <class T>
+static void debugArray(std::ostream &str, const T *data, int n)
+{
+ static const int maxData = 10;
+ str << " = ";
+ auto *end = data + std::min(n, maxData);
+ for (auto *d = data; d != end; ++d) {
+ if (d != data)
+ str << ", ";
+ str << *d;
+ }
+ if (n > maxData)
+ str << "...";
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &a)
+{
+ str << "PyArrayObject(";
+ if (a.m_object == nullptr) {
+ str << '0';
+ } else if (PyArray_Check(a.m_object) != 0) {
+ auto *ar = reinterpret_cast<PyArrayObject *>(a.m_object);
+ const int ndim = PyArray_NDIM(ar);
+ const int type = PyArray_TYPE(ar);
+ const int flags = PyArray_FLAGS(ar);
+ str << "ndim=" << ndim << " [";
+ for (int d = 0; d < ndim; ++d) {
+ if (d)
+ str << ", ";
+ str << PyArray_DIMS(ar)[d];
+ }
+ str << "], type=";
+ switch (type) {
+ case NPY_SHORT:
+ str << "short";
+ break;
+ case NPY_USHORT:
+ str << "ushort";
+ break;
+ case NPY_INT:
+ str << "int32";
+ break;
+ case NPY_UINT:
+ str << "uint32";
+ break;
+ case NPY_LONG:
+ str << "long";
+ break;
+ case NPY_ULONG:
+ str << "ulong";
+ break;
+ case NPY_LONGLONG:
+ str << "long long";
+ break;
+ case NPY_ULONGLONG:
+ str << "ulong long";
+ break;
+ case NPY_FLOAT:
+ str << "float";
+ break;
+ case NPY_DOUBLE:
+ str << "double";
+ break;
+ default:
+ str << '(' << type << ')';
+ break;
+ }
+ str << ", flags=0x" << std::hex << flags << std::dec;
+ if ((flags & NPY_ARRAY_C_CONTIGUOUS) != 0)
+ str << " [C-contiguous]";
+ if ((flags & NPY_ARRAY_F_CONTIGUOUS) != 0)
+ str << " [Fortran-contiguous]";
+ if ((flags & NPY_ARRAY_ALIGNED) != 0)
+ str << " [aligned]";
+ if ((flags & NPY_ARRAY_OWNDATA) != 0)
+ str << " [owndata]";
+ if ((flags & NPY_ARRAY_WRITEABLE) != 0)
+ str << " [writeable]";
+
+ if (const int dim0 = PyArray_DIMS(ar)[0]) {
+ auto *data = PyArray_DATA(ar);
+ switch (type) {
+ case NPY_SHORT:
+ debugArray(str, reinterpret_cast<const short *>(data), dim0);
+ break;
+ case NPY_USHORT:
+ debugArray(str, reinterpret_cast<const unsigned short *>(data), dim0);
+ break;
+ case NPY_INT:
+ debugArray(str, reinterpret_cast<const int *>(data), dim0);
+ break;
+ case NPY_UINT:
+ debugArray(str, reinterpret_cast<const unsigned *>(data), dim0);
+ break;
+ case NPY_LONG:
+ debugArray(str, reinterpret_cast<const long *>(data), dim0);
+ break;
+ case NPY_ULONG:
+ debugArray(str, reinterpret_cast<const unsigned long*>(data), dim0);
+ break;
+ case NPY_LONGLONG:
+ debugArray(str, reinterpret_cast<const long long *>(data), dim0);
+ break;
+ case NPY_ULONGLONG:
+ debugArray(str, reinterpret_cast<const unsigned long long *>(data), dim0);
+ break;
+ case NPY_FLOAT:
+ debugArray(str, reinterpret_cast<const float *>(data), dim0);
+ break;
+ case NPY_DOUBLE:
+ debugArray(str, reinterpret_cast<const double *>(data), dim0);
+ break;
+ }
+ }
+ } else {
+ str << "Invalid";
+ }
+ str << ')';
+ return str;
+}
+
+} //namespace Shiboken
+
+#else // HAVE_NUMPY
+
+namespace Shiboken::Numpy
+{
+
+View View::fromPyObject(PyObject *)
+{
+ return {};
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &)
+{
+ str << "Unimplemented function " << __FUNCTION__ << ", (numpy was not found).";
+ return str;
+}
+
+} //namespace Shiboken::Numpy
+
+#endif // !HAVE_NUMPY
+
+namespace Shiboken::Numpy
+{
+
+bool View::sameLayout(const View &rhs) const
+{
+ return rhs && *this && ndim == rhs.ndim && type == rhs.type;
+}
+
+bool View::sameSize(const View &rhs) const
+{
+ return sameLayout(rhs)
+ && dimensions[0] == rhs.dimensions[0] && dimensions[1] == rhs.dimensions[1];
+}
+
+std::ostream &operator<<(std::ostream &str, const View &v)
+{
+ str << "Shiboken::Numpy::View(";
+ if (v) {
+ str << "type=" << v.type << ", ndim=" << v.ndim << " ["
+ << v.dimensions[0];
+ if (v.ndim > 1)
+ str << ", " << v.dimensions[1];
+ str << "], stride=[" << v.stride[0];
+ if (v.ndim > 1)
+ str << ", " << v.stride[1];
+ str << "], data=" << v.data;
+ } else {
+ str << "invalid";
+ }
+ str << ')';
+ return str;
+}
+
+} //namespace Shiboken::Numpy
diff --git a/sources/shiboken6/libshiboken/sbknumpyview.h b/sources/shiboken6/libshiboken/sbknumpyview.h
new file mode 100644
index 000000000..918913b78
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyview.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKNUMPYVIEW_H
+#define SBKNUMPYVIEW_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+#include <iosfwd>
+
+namespace Shiboken::Numpy
+{
+
+/// Check whether the object is a PyArrayObject
+/// \param pyIn object
+/// \return Whether it is a PyArrayObject
+LIBSHIBOKEN_API bool check(PyObject *pyIn);
+
+/// A simple view of an up to 2 dimensional, C-contiguous array of a standard
+/// type. It can be passed to compilation units that do not include the
+/// numpy headers.
+struct LIBSHIBOKEN_API View
+{
+ enum Type { Int, Unsigned, Float, Double, Int16, Unsigned16, Int64, Unsigned64 };
+
+ static View fromPyObject(PyObject *pyIn);
+
+ operator bool() const { return ndim > 0; }
+
+ /// Return whether rhs is of the same type and dimensionality
+ bool sameLayout(const View &rhs) const;
+ /// Return whether rhs is of the same type dimensionality and size
+ bool sameSize(const View &rhs) const;
+
+ int ndim = 0;
+ Py_ssize_t dimensions[2];
+ Py_ssize_t stride[2];
+ void *data = nullptr;
+ Type type = Int;
+};
+
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &, const View &v);
+
+} //namespace Shiboken::Numpy
+
+#endif // SBKNUMPYVIEW_H
diff --git a/sources/shiboken6/libshiboken/sbkpython.h b/sources/shiboken6/libshiboken/sbkpython.h
new file mode 100644
index 000000000..e62fa13ae
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkpython.h
@@ -0,0 +1,75 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKPYTHON_H
+#define SBKPYTHON_H
+
+#include "sbkversion.h"
+
+// Qt's "slots" macro collides with the "slots" member variables
+// used in some Python structs. For compilers that support push_macro,
+// temporarily undefine it.
+#if defined(slots) && (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__))
+# pragma push_macro("slots")
+# undef slots
+/*
+ * Python 2 has function _Py_Mangle directly in Python.h .
+ * This creates wrong language binding unless we define 'extern "C"' here.
+ */
+extern "C" {
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
+}
+# include <structmember.h>
+// Now we have the usual variables from Python.h .
+# include "shibokenmacros.h"
+// "pep384impl.h" may nowhere be included but in this file.
+# include "pep384impl.h"
+# pragma pop_macro("slots")
+
+#else
+
+extern "C" {
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
+}
+# include <structmember.h>
+// Now we have the usual variables from Python.h .
+# include "shibokenmacros.h"
+// "pep384impl.h" may nowhere be included but in this file.
+# include "pep384impl.h"
+#endif
+
+// In Python 3, Py_TPFLAGS_DEFAULT contains Py_TPFLAGS_HAVE_VERSION_TAG,
+// which will trigger the attribute cache, which is not intended in Qt for Python.
+// Use a customized Py_TPFLAGS_DEFAULT by defining Py_TPFLAGS_HAVE_VERSION_TAG = 0.
+#undef Py_TPFLAGS_HAVE_VERSION_TAG
+#define Py_TPFLAGS_HAVE_VERSION_TAG (0)
+
+using SbkObjectType [[deprecated]] = PyTypeObject; // FIXME PYSIDE 7 remove
+
+#endif
diff --git a/sources/shiboken6/libshiboken/sbksmartpointer.cpp b/sources/shiboken6/libshiboken/sbksmartpointer.cpp
new file mode 100644
index 000000000..ee28f7db8
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbksmartpointer.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbksmartpointer.h"
+#include "sbkstring.h"
+#include "autodecref.h"
+
+#include <unordered_set>
+
+namespace Shiboken::SmartPointer
+{
+
+PyObject *repr(PyObject *pointer, PyObject *pointee)
+{
+ Shiboken::AutoDecRef pointerRepr(Shiboken::String::repr(pointer));
+ if (pointer == nullptr)
+ return pointerRepr.release();
+
+ Shiboken::AutoDecRef pointeeRepr(pointee != nullptr
+ ? PyObject_Repr(pointee)
+ : Shiboken::String::repr(pointee));
+
+ return PyUnicode_FromFormat("%U (%U)", pointerRepr.object(), pointeeRepr.object());
+}
+
+// __dir__ for a smart pointer. Add the __dir__ entries of the pointee to the list.
+PyObject *dir(PyObject *pointer, PyObject *pointee)
+{
+ if (pointer == nullptr)
+ return PyList_New(0);
+ // Get the pointer's dir entries. Note: PyObject_Dir() cannot be called on
+ // self, will crash. Work around by using the type dict keys.
+ AutoDecRef tpDict(PepType_GetDict(Py_TYPE(pointer)));
+ auto *result = PyMapping_Keys(tpDict);
+
+ if (pointee != nullptr && pointee != Py_None) {
+ // Add the entries of the pointee that do not exist in the pointer's list.
+ // Since Python internally caches strings; we can use a set of PyObject *.
+ std::unordered_set<PyObject *> knownStrings;
+ for (Py_ssize_t i = 0, size = PySequence_Size(result); i < size; ++i) {
+ Shiboken::AutoDecRef item(PySequence_GetItem(result, i));
+ knownStrings.insert(item.object());
+ }
+ const auto knownEnd = knownStrings.end();
+
+ Shiboken::AutoDecRef pointeeDir(PyObject_Dir(pointee));
+ for (Py_ssize_t i = 0, size = PySequence_Size(pointeeDir.object()); i < size; ++i) {
+ Shiboken::AutoDecRef item(PySequence_GetItem(pointeeDir, i));
+ if (knownStrings.find(item.object()) == knownEnd)
+ PyList_Append(result, item.object());
+ }
+ }
+
+ PyList_Sort(result);
+ return result;
+}
+
+} // namespace Shiboken::SmartPointer
diff --git a/sources/shiboken6/libshiboken/sbksmartpointer.h b/sources/shiboken6/libshiboken/sbksmartpointer.h
new file mode 100644
index 000000000..5e2022722
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbksmartpointer.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_SBKSMARTPOINTER_H
+#define SBK_SBKSMARTPOINTER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken::SmartPointer
+{
+
+LIBSHIBOKEN_API PyObject *repr(PyObject *pointer, PyObject *pointee);
+LIBSHIBOKEN_API PyObject *dir(PyObject *pointer, PyObject *pointee);
+
+} // namespace Shiboken::SmartPointer
+
+#endif // SBK_SBKSMARTPOINTER_H
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.cpp b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp
new file mode 100644
index 000000000..023de0ea4
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkstring.h"
+
+#define STATIC_STRING_IMPL(funcName, value) \
+PyObject *funcName() \
+{ \
+ static PyObject *const s = Shiboken::String::createStaticString(value); \
+ return s; \
+}
+
+namespace Shiboken
+{
+namespace PyName {
+// exported:
+STATIC_STRING_IMPL(dumps, "dumps")
+STATIC_STRING_IMPL(fget, "fget")
+STATIC_STRING_IMPL(fset, "fset")
+STATIC_STRING_IMPL(im_func, "im_func")
+STATIC_STRING_IMPL(im_self, "im_self")
+STATIC_STRING_IMPL(loads, "loads")
+STATIC_STRING_IMPL(multi, "multi")
+STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(orig_dict, "orig_dict")
+STATIC_STRING_IMPL(qApp, "qApp")
+STATIC_STRING_IMPL(result, "result")
+STATIC_STRING_IMPL(select_id, "select_id")
+STATIC_STRING_IMPL(value, "value")
+STATIC_STRING_IMPL(values, "values")
+STATIC_STRING_IMPL(qtStaticMetaObject, "staticMetaObject")
+
+// Internal:
+STATIC_STRING_IMPL(classmethod, "classmethod")
+STATIC_STRING_IMPL(co_name, "co_name")
+STATIC_STRING_IMPL(compile, "compile");
+STATIC_STRING_IMPL(f_code, "f_code")
+STATIC_STRING_IMPL(f_lineno, "f_lineno")
+STATIC_STRING_IMPL(function, "function")
+STATIC_STRING_IMPL(marshal, "marshal")
+STATIC_STRING_IMPL(method, "method")
+STATIC_STRING_IMPL(mro, "mro")
+STATIC_STRING_IMPL(overload, "overload")
+STATIC_STRING_IMPL(staticmethod, "staticmethod")
+} // namespace PyName
+
+namespace PyMagicName {
+// exported:
+STATIC_STRING_IMPL(class_, "__class__")
+STATIC_STRING_IMPL(dict, "__dict__")
+STATIC_STRING_IMPL(doc, "__doc__")
+STATIC_STRING_IMPL(ecf, "__ecf__")
+STATIC_STRING_IMPL(file, "__file__")
+STATIC_STRING_IMPL(get, "__get__")
+STATIC_STRING_IMPL(members, "__members__")
+STATIC_STRING_IMPL(module, "__module__")
+STATIC_STRING_IMPL(name, "__name__")
+STATIC_STRING_IMPL(property_methods, "__property_methods__")
+STATIC_STRING_IMPL(qualname, "__qualname__")
+STATIC_STRING_IMPL(self, "__self__")
+STATIC_STRING_IMPL(select_i, "__self__")
+STATIC_STRING_IMPL(code, "__code__")
+STATIC_STRING_IMPL(rlshift, "__rlshift__")
+STATIC_STRING_IMPL(rrshift, "__rrshift__")
+
+// Internal:
+STATIC_STRING_IMPL(base, "__base__")
+STATIC_STRING_IMPL(bases, "__bases__")
+STATIC_STRING_IMPL(builtins, "__builtins__")
+STATIC_STRING_IMPL(dictoffset, "__dictoffset__")
+STATIC_STRING_IMPL(func, "__func__")
+STATIC_STRING_IMPL(func_kind, "__func_kind__")
+STATIC_STRING_IMPL(iter, "__iter__")
+STATIC_STRING_IMPL(mro, "__mro__")
+STATIC_STRING_IMPL(new_, "__new__")
+STATIC_STRING_IMPL(objclass, "__objclass__")
+STATIC_STRING_IMPL(weakrefoffset, "__weakrefoffset__")
+STATIC_STRING_IMPL(opaque_container, "__opaque_container__")
+} // namespace PyMagicName
+
+namespace Messages
+{
+STATIC_STRING_IMPL(unknownException, "An unknown exception was caught")
+}
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.h b/sources/shiboken6/libshiboken/sbkstaticstrings.h
new file mode 100644
index 000000000..017790ee3
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKSTATICSTRINGS_H
+#define SBKSTATICSTRINGS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+// Some often-used strings
+namespace PyName
+{
+LIBSHIBOKEN_API PyObject *co_name();
+LIBSHIBOKEN_API PyObject *dumps();
+LIBSHIBOKEN_API PyObject *fget();
+LIBSHIBOKEN_API PyObject *fset();
+LIBSHIBOKEN_API PyObject *f_code();
+LIBSHIBOKEN_API PyObject *f_lineno();
+LIBSHIBOKEN_API PyObject *im_func();
+LIBSHIBOKEN_API PyObject *im_self();
+LIBSHIBOKEN_API PyObject *loads();
+LIBSHIBOKEN_API PyObject *multi();
+LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *orig_dict();
+LIBSHIBOKEN_API PyObject *result();
+LIBSHIBOKEN_API PyObject *select_id();
+LIBSHIBOKEN_API PyObject *value();
+LIBSHIBOKEN_API PyObject *values();
+LIBSHIBOKEN_API PyObject *qtStaticMetaObject();
+} // namespace PyName
+
+namespace PyMagicName
+{
+LIBSHIBOKEN_API PyObject *class_();
+LIBSHIBOKEN_API PyObject *dict();
+LIBSHIBOKEN_API PyObject *doc();
+LIBSHIBOKEN_API PyObject *ecf();
+LIBSHIBOKEN_API PyObject *file();
+LIBSHIBOKEN_API PyObject *func();
+LIBSHIBOKEN_API PyObject *get();
+LIBSHIBOKEN_API PyObject *members();
+LIBSHIBOKEN_API PyObject *module();
+LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *property_methods();
+LIBSHIBOKEN_API PyObject *qualname();
+LIBSHIBOKEN_API PyObject *self();
+LIBSHIBOKEN_API PyObject *opaque_container();
+LIBSHIBOKEN_API PyObject *code();
+LIBSHIBOKEN_API PyObject *rlshift();
+LIBSHIBOKEN_API PyObject *rrshift();
+} // namespace PyMagicName
+
+namespace Messages
+{
+LIBSHIBOKEN_API PyObject *unknownException();
+} // Messages
+} // namespace Shiboken
+
+#endif // SBKSTATICSTRINGS_H
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings_p.h b/sources/shiboken6/libshiboken/sbkstaticstrings_p.h
new file mode 100644
index 000000000..2a337bf7e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings_p.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+namespace PyName
+{
+PyObject *classmethod();
+PyObject *compile();
+PyObject *function();
+PyObject *marshal();
+PyObject *method();
+PyObject *mro();
+PyObject *overload();
+PyObject *qApp();
+PyObject *staticmethod();
+} // namespace PyName
+namespace PyMagicName
+{
+PyObject *base();
+PyObject *bases();
+PyObject *builtins();
+PyObject *code();
+PyObject *dictoffset();
+PyObject *func_kind();
+PyObject *iter();
+PyObject *module();
+PyObject *mro();
+PyObject *new_();
+PyObject *objclass();
+PyObject *signature();
+PyObject *weakrefoffset();
+} // namespace PyMagicName
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkstring.cpp b/sources/shiboken6/libshiboken/sbkstring.cpp
new file mode 100644
index 000000000..b5e87ca5a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstring.cpp
@@ -0,0 +1,254 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkstring.h"
+#include "sbkenum.h"
+#include "sbkstaticstrings_p.h"
+#include "autodecref.h"
+
+namespace Shiboken::String
+{
+
+// PYSIDE-795: Redirecting PySequence to Iterable
+bool checkIterable(PyObject *obj)
+{
+ return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter());
+}
+
+bool checkIterableArgument(PyObject *obj)
+{
+ return checkIterable(obj) && !Shiboken::Enum::check(obj);
+}
+
+static PyObject *initPathLike()
+{
+ PyObject *PathLike{};
+ auto osmodule = PyImport_ImportModule("os");
+ if (osmodule == nullptr
+ || (PathLike = PyObject_GetAttrString(osmodule, "PathLike")) == nullptr) {
+ PyErr_Print();
+ Py_FatalError("cannot import os.PathLike");
+ }
+ return PathLike;
+}
+
+// PYSIDE-1499: Migrate to pathlib.Path and support __fspath__ in PySide
+bool checkPath(PyObject *path)
+{
+ // Let normal strings through, unchanged.
+ if (PyUnicode_Check(path) || PyBytes_Check(path))
+ return true;
+ // Without the Limited API, we could look up an `__fspath__` class attribute.
+ // But we use `isinstance(os.PathLike)`, instead.
+ static PyObject *PathLike = initPathLike();
+ return PyObject_IsInstance(path, PathLike);
+}
+
+bool checkType(PyTypeObject *type)
+{
+ return type == &PyUnicode_Type;
+}
+
+bool check(PyObject *obj)
+{
+ return obj == Py_None || PyUnicode_Check(obj);
+}
+
+bool checkChar(PyObject *pyobj)
+{
+ return check(pyobj) && (len(pyobj) == 1);
+}
+
+bool isConvertible(PyObject *obj)
+{
+ return check(obj);
+}
+
+PyObject *fromCString(const char *value)
+{
+ return PyUnicode_FromString(value);
+}
+
+PyObject *fromCString(const char *value, int len)
+{
+ return PyUnicode_FromStringAndSize(value, len);
+}
+
+const char *toCString(PyObject *str)
+{
+ if (str == Py_None)
+ return nullptr;
+ if (PyUnicode_Check(str))
+ return _PepUnicode_AsString(str);
+ if (PyBytes_Check(str))
+ return PyBytes_AS_STRING(str);
+ return nullptr;
+}
+
+const char *toCString(PyObject *str, Py_ssize_t *len)
+{
+ if (str == Py_None) {
+ *len = 0;
+ return nullptr;
+ }
+ if (PyUnicode_Check(str)) {
+ // We need to encode the unicode string into utf8 to know the size of returned char *.
+ Shiboken::AutoDecRef uniStr(PyUnicode_AsUTF8String(str));
+ *len = PyBytes_GET_SIZE(uniStr.object());
+ // Return unicode from str instead of uniStr, because the lifetime of the returned pointer
+ // depends on the lifetime of str.
+ return _PepUnicode_AsString(str);
+ }
+ if (PyBytes_Check(str)) {
+ *len = PyBytes_GET_SIZE(str);
+ return PyBytes_AS_STRING(str);
+ }
+ return nullptr;
+}
+
+bool concat(PyObject **val1, PyObject *val2)
+{
+ if (PyUnicode_Check(*val1) && PyUnicode_Check(val2)) {
+ PyObject *result = PyUnicode_Concat(*val1, val2);
+ Py_DECREF(*val1);
+ *val1 = result;
+ return true;
+ }
+
+ if (PyBytes_Check(*val1) && PyBytes_Check(val2)) {
+ PyBytes_Concat(val1, val2);
+ return true;
+ }
+
+ return false;
+}
+
+PyObject *fromFormat(const char *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ PyObject *result = nullptr;
+ result = PyUnicode_FromFormatV(format, argp);
+ va_end(argp);
+ return result;
+}
+
+PyObject *fromStringAndSize(const char *str, Py_ssize_t size)
+{
+ return PyUnicode_FromStringAndSize(str, size);
+}
+
+int compare(PyObject *val1, const char *val2)
+{
+ if (PyUnicode_Check(val1))
+ return PyUnicode_CompareWithASCIIString(val1, val2);
+ return 0;
+
+}
+
+Py_ssize_t len(PyObject *str)
+{
+ if (str == Py_None)
+ return 0;
+
+ if (PyUnicode_Check(str))
+ return PepUnicode_GetLength(str);
+
+ if (PyBytes_Check(str))
+ return PyBytes_GET_SIZE(str);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Implementation of efficient Python strings
+// ------------------------------------------
+//
+// Instead of repetitively executing
+//
+// PyObject *attr = PyObject_GetAttrString(obj, "__name__");
+//
+// a helper of the form
+//
+// PyObject *name()
+// {
+// static PyObject *const s = Shiboken::String::createStaticString("__name__");
+// return result;
+// }
+//
+// can now be implemented, which registers the string into a static set avoiding
+// repetitive string creation. The resulting code looks like:
+//
+// PyObject *attr = PyObject_GetAttr(obj, name());
+//
+
+PyObject *createStaticString(const char *str)
+{
+ return PyUnicode_InternFromString(str);
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Helper function for snake_case vs. camelCase names
+// ---------------------------------------------------------------
+//
+// When renaming dict entries, `BindingManager::getOverride` must
+// use adapted names.
+//
+// This might become more complex when we need to register
+// exceptions from this rule.
+//
+
+PyObject *getSnakeCaseName(const char *name, bool lower)
+{
+ /*
+ * Convert `camelCase` to `snake_case`.
+ * Gives up when there are two consecutive upper chars.
+ *
+ * Also functions beginning with `gl` followed by upper case stay
+ * unchanged since that are the special OpenGL functions.
+ */
+ if (!lower
+ || strlen(name) < 3
+ || (name[0] == 'g' && name[1] == 'l' && isupper(name[2])))
+ return createStaticString(name);
+
+ char new_name[200 + 1] = {};
+ const char *p = name;
+ char *q = new_name;
+ for (; *p && q - new_name < 200; ++p, ++q) {
+ if (isupper(*p)) {
+ if (p != name && isupper(*(p - 1)))
+ return createStaticString(name);
+ *q = '_';
+ ++q;
+ *q = tolower(*p);
+ }
+ else {
+ *q = *p;
+ }
+ }
+ return createStaticString(new_name);
+}
+
+PyObject *getSnakeCaseName(PyObject *name, bool lower)
+{
+ // This is all static strings, not refcounted.
+ if (lower)
+ return getSnakeCaseName(toCString(name), lower);
+ return name;
+}
+
+// Return a generic representation of a PyObject as does PyObject_Repr().
+// Note: PyObject_Repr() may not be called on self from __repr__() as this
+// causes a recursion.
+PyObject *repr(PyObject *o)
+{
+ if (o == nullptr)
+ return PyUnicode_FromString("<NULL>");
+ if (o == Py_None)
+ return PyUnicode_FromString("None");
+ return PyUnicode_FromFormat("<%s object at %p>", Py_TYPE(o)->tp_name, o);
+}
+
+} // namespace Shiboken::String
diff --git a/sources/shiboken6/libshiboken/sbkstring.h b/sources/shiboken6/libshiboken/sbkstring.h
new file mode 100644
index 000000000..ebc5428c7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstring.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKSTRING_H
+#define SBKSTRING_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+namespace String
+{
+ LIBSHIBOKEN_API bool check(PyObject *obj);
+ LIBSHIBOKEN_API bool checkIterable(PyObject *obj);
+ /// Check for iterable function arguments (excluding enumerations)
+ LIBSHIBOKEN_API bool checkIterableArgument(PyObject *obj);
+ LIBSHIBOKEN_API bool checkPath(PyObject *path);
+ LIBSHIBOKEN_API bool checkType(PyTypeObject *obj);
+ LIBSHIBOKEN_API bool checkChar(PyObject *obj);
+ LIBSHIBOKEN_API bool isConvertible(PyObject *obj);
+ LIBSHIBOKEN_API PyObject *fromCString(const char *value);
+ LIBSHIBOKEN_API PyObject *fromCString(const char *value, int len);
+ LIBSHIBOKEN_API const char *toCString(PyObject *str);
+ LIBSHIBOKEN_API const char *toCString(PyObject *str, Py_ssize_t *len);
+ LIBSHIBOKEN_API bool concat(PyObject **val1, PyObject *val2);
+ LIBSHIBOKEN_API PyObject *fromFormat(const char *format, ...);
+ LIBSHIBOKEN_API PyObject *fromStringAndSize(const char *str, Py_ssize_t size);
+ LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2);
+ LIBSHIBOKEN_API Py_ssize_t len(PyObject *str);
+ LIBSHIBOKEN_API PyObject *createStaticString(const char *str);
+ LIBSHIBOKEN_API PyObject *getSnakeCaseName(const char *name, bool lower);
+ LIBSHIBOKEN_API PyObject *getSnakeCaseName(PyObject *name, bool lower);
+ LIBSHIBOKEN_API PyObject *repr(PyObject *o);
+
+} // namespace String
+} // namespace Shiboken
+
+
+#endif
+
+
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp
new file mode 100644
index 000000000..079548eed
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp
@@ -0,0 +1,407 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbktypefactory.h"
+#include "shiboken.h"
+
+extern "C"
+{
+
+using Shiboken::AutoDecRef;
+
+PyTypeObject *SbkType_FromSpec(PyType_Spec *spec)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *spec, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, meta, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *spec, PyObject *bases, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, meta, 0, 0, nullptr);
+}
+
+#ifdef PYPY_VERSION
+
+static PyObject *_PyType_FromSpecWithBases(PyType_Spec *, PyObject *);
+
+#else
+
+#define _PyType_FromSpecWithBases PyType_FromSpecWithBases
+
+#endif // PYPY_VERSION
+
+// PYSIDE-2230: Not so temporary fix for Python 3.12.
+// A tp_new is no longer allowed in a meta class.
+// Hopefully, the Python devs will supply the missing support.
+// It turned out that they will not fix that, as expected.
+// Note: Python 3.12 is the first version that grabs the metaclass from base classes.
+static PyObject *_PyType_FromSpecWithBasesHack(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta)
+{
+ PyTypeObject *keepMeta{};
+ newfunc keepNew{};
+ AutoDecRef basesPatch{};
+
+ if (bases) {
+ if (bases == Py_None) {
+ // PYSIDE-2230: This is the SbkObject entry which has no base to provide
+ // the metaclass. We patch it in by modifying `object`s class.
+ assert(meta);
+ auto *base = reinterpret_cast<PyObject *>(&PyBaseObject_Type);
+ base->ob_type = meta;
+ basesPatch.reset(Py_BuildValue("(O)", &PyBaseObject_Type));
+ bases = basesPatch.object();
+ }
+
+ Py_ssize_t n = PyTuple_GET_SIZE(bases);
+ for (auto idx = 0; idx < n; ++idx) {
+ PyTypeObject *base = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, idx));
+ PyTypeObject *meta = Py_TYPE(base);
+ if (meta->tp_new != PyType_Type.tp_new) {
+ // make sure there is no second meta class
+ assert(keepMeta == nullptr);
+ keepMeta = meta;
+ keepNew = meta->tp_new;
+ meta->tp_new = PyType_Type.tp_new;
+ }
+ }
+ }
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+ auto *ret = PyType_FromMetaclass(meta, nullptr /*module*/, spec, bases);
+#else
+ auto *ret = _PyType_FromSpecWithBases(spec, bases);
+#endif
+
+ if (keepMeta)
+ keepMeta->tp_new = keepNew;
+ if (basesPatch.object()) {
+ // undo the metaclass patch.
+ auto *base = PyTuple_GET_ITEM(basesPatch.object(), 0);
+ base->ob_type = &PyType_Type;
+ }
+ return ret;
+}
+
+PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs)
+{
+ // PYSIDE-1286: Generate correct __module__ and __qualname__
+ // The name field can now be extended by an "n:" prefix which is
+ // the number of modules in the name. The default is 1.
+ //
+ // Example:
+ // "2:mainmod.submod.mainclass.subclass"
+ // results in
+ // __module__ : "mainmod.submod"
+ // __qualname__ : "mainclass.subclass"
+ // __name__ : "subclass"
+
+ PyType_Spec new_spec = *spec;
+ const char *colon = strchr(spec->name, ':');
+ assert(colon);
+ int package_level = atoi(spec->name);
+ const char *mod = new_spec.name = colon + 1;
+
+ PyObject *obType = _PyType_FromSpecWithBasesHack(&new_spec, bases, meta);
+ if (obType == nullptr)
+ return nullptr;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ AutoDecRef qualname(Shiboken::String::fromCString(qual));
+
+ auto *type = reinterpret_cast<PyTypeObject *>(obType);
+
+ if (meta) {
+ PyTypeObject *hold = Py_TYPE(type);
+ obType->ob_type = meta;
+ Py_INCREF(Py_TYPE(type));
+ if (hold->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ Py_DECREF(hold);
+ }
+
+ if (dictoffset)
+ type->tp_dictoffset = dictoffset;
+ if (weaklistoffset)
+ type->tp_weaklistoffset = weaklistoffset;
+ if (bufferprocs)
+ PepType_AS_BUFFER(type) = bufferprocs;
+
+#ifdef PYPY_VERSION
+ // PYSIDE-535: Careful: Using PyObject_SetAttr would have the side-effect of calling
+ // PyType_Ready too early. (at least in PyPy, which caused pretty long debugging.)
+ auto *ht = reinterpret_cast<PyHeapTypeObject *>(type);
+ ht->ht_qualname = qualname;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::qualname(), qualname))
+ return nullptr;
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::module(), module))
+ return nullptr;
+ PyType_Ready(type);
+#else
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::module(), module) < 0)
+ return nullptr;
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::qualname(), qualname) < 0)
+ return nullptr;
+ PyType_Modified(type);
+#endif
+ return type;
+}
+
+#ifdef PYPY_VERSION
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Reimplementation of `PyType_FromSpecWithBases`
+//
+// This is almost the original code from Python 3.7 with a few changes.
+// Especially the call to `PyType_Ready` is deferred until the needed
+// post-actions are carried out in `SbkType_FromSpec_BMDWBD`.
+//
+// FIXME remove ASAP.
+// Version is not clear, yet. Current version == 7.3.6
+//
+
+static const short slotoffsets[] = {
+ -1, /* invalid slot */
+/* Generated by typeslots.py */
+0,
+0,
+offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript),
+offsetof(PyHeapTypeObject, as_mapping.mp_length),
+offsetof(PyHeapTypeObject, as_mapping.mp_subscript),
+offsetof(PyHeapTypeObject, as_number.nb_absolute),
+offsetof(PyHeapTypeObject, as_number.nb_add),
+offsetof(PyHeapTypeObject, as_number.nb_and),
+offsetof(PyHeapTypeObject, as_number.nb_bool),
+offsetof(PyHeapTypeObject, as_number.nb_divmod),
+offsetof(PyHeapTypeObject, as_number.nb_float),
+offsetof(PyHeapTypeObject, as_number.nb_floor_divide),
+offsetof(PyHeapTypeObject, as_number.nb_index),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_add),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_and),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_or),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_power),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_xor),
+offsetof(PyHeapTypeObject, as_number.nb_int),
+offsetof(PyHeapTypeObject, as_number.nb_invert),
+offsetof(PyHeapTypeObject, as_number.nb_lshift),
+offsetof(PyHeapTypeObject, as_number.nb_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_negative),
+offsetof(PyHeapTypeObject, as_number.nb_or),
+offsetof(PyHeapTypeObject, as_number.nb_positive),
+offsetof(PyHeapTypeObject, as_number.nb_power),
+offsetof(PyHeapTypeObject, as_number.nb_remainder),
+offsetof(PyHeapTypeObject, as_number.nb_rshift),
+offsetof(PyHeapTypeObject, as_number.nb_subtract),
+offsetof(PyHeapTypeObject, as_number.nb_true_divide),
+offsetof(PyHeapTypeObject, as_number.nb_xor),
+offsetof(PyHeapTypeObject, as_sequence.sq_ass_item),
+offsetof(PyHeapTypeObject, as_sequence.sq_concat),
+offsetof(PyHeapTypeObject, as_sequence.sq_contains),
+offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat),
+offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat),
+offsetof(PyHeapTypeObject, as_sequence.sq_item),
+offsetof(PyHeapTypeObject, as_sequence.sq_length),
+offsetof(PyHeapTypeObject, as_sequence.sq_repeat),
+offsetof(PyHeapTypeObject, ht_type.tp_alloc),
+offsetof(PyHeapTypeObject, ht_type.tp_base),
+offsetof(PyHeapTypeObject, ht_type.tp_bases),
+offsetof(PyHeapTypeObject, ht_type.tp_call),
+offsetof(PyHeapTypeObject, ht_type.tp_clear),
+offsetof(PyHeapTypeObject, ht_type.tp_dealloc),
+offsetof(PyHeapTypeObject, ht_type.tp_del),
+offsetof(PyHeapTypeObject, ht_type.tp_descr_get),
+offsetof(PyHeapTypeObject, ht_type.tp_descr_set),
+offsetof(PyHeapTypeObject, ht_type.tp_doc),
+offsetof(PyHeapTypeObject, ht_type.tp_getattr),
+offsetof(PyHeapTypeObject, ht_type.tp_getattro),
+offsetof(PyHeapTypeObject, ht_type.tp_hash),
+offsetof(PyHeapTypeObject, ht_type.tp_init),
+offsetof(PyHeapTypeObject, ht_type.tp_is_gc),
+offsetof(PyHeapTypeObject, ht_type.tp_iter),
+offsetof(PyHeapTypeObject, ht_type.tp_iternext),
+offsetof(PyHeapTypeObject, ht_type.tp_methods),
+offsetof(PyHeapTypeObject, ht_type.tp_new),
+offsetof(PyHeapTypeObject, ht_type.tp_repr),
+offsetof(PyHeapTypeObject, ht_type.tp_richcompare),
+offsetof(PyHeapTypeObject, ht_type.tp_setattr),
+offsetof(PyHeapTypeObject, ht_type.tp_setattro),
+offsetof(PyHeapTypeObject, ht_type.tp_str),
+offsetof(PyHeapTypeObject, ht_type.tp_traverse),
+offsetof(PyHeapTypeObject, ht_type.tp_members),
+offsetof(PyHeapTypeObject, ht_type.tp_getset),
+offsetof(PyHeapTypeObject, ht_type.tp_free),
+offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply),
+offsetof(PyHeapTypeObject, as_async.am_await),
+offsetof(PyHeapTypeObject, as_async.am_aiter),
+offsetof(PyHeapTypeObject, as_async.am_anext),
+offsetof(PyHeapTypeObject, ht_type.tp_finalize),
+};
+
+static PyTypeObject *
+best_base(PyObject *bases)
+{
+ // We always have only one base
+ return reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, 0));
+}
+
+static PyObject *
+_PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
+{
+ PyHeapTypeObject *res = reinterpret_cast<PyHeapTypeObject *>(
+ PyType_GenericAlloc(&PyType_Type, 0));
+ PyTypeObject *type, *base;
+ PyObject *modname;
+ char *s;
+ char *res_start = reinterpret_cast<char *>(res);
+ PyType_Slot *slot;
+
+ if (res == nullptr)
+ return nullptr;
+
+ if (spec->name == nullptr) {
+ PyErr_SetString(PyExc_SystemError,
+ "Type spec does not define the name field.");
+ goto fail;
+ }
+
+ /* Set the type name and qualname */
+ s = strrchr(const_cast<char *>(spec->name), '.');
+ if (s == nullptr)
+ s = (char*)spec->name;
+ else
+ s++;
+
+ type = &res->ht_type;
+ /* The flags must be initialized early, before the GC traverses us */
+ type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
+ res->ht_name = PyUnicode_FromString(s);
+ if (!res->ht_name)
+ goto fail;
+ res->ht_qualname = res->ht_name;
+ Py_INCREF(res->ht_qualname);
+ type->tp_name = spec->name;
+
+ /* Adjust for empty tuple bases */
+ if (!bases) {
+ base = &PyBaseObject_Type;
+ /* See whether Py_tp_base(s) was specified */
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base)
+ base = reinterpret_cast<PyTypeObject *>(slot->pfunc);
+ else if (slot->slot == Py_tp_bases) {
+ bases = reinterpret_cast<PyObject *>(slot->pfunc);
+ Py_INCREF(bases);
+ }
+ }
+ if (!bases)
+ bases = PyTuple_Pack(1, base);
+ if (!bases)
+ goto fail;
+ }
+ else
+ Py_INCREF(bases);
+
+ /* Calculate best base, and check that all bases are type objects */
+ base = best_base(bases);
+ if (base == nullptr) {
+ goto fail;
+ }
+
+ /* Initialize essential fields */
+ type->tp_as_async = &res->as_async;
+ type->tp_as_number = &res->as_number;
+ type->tp_as_sequence = &res->as_sequence;
+ type->tp_as_mapping = &res->as_mapping;
+ type->tp_as_buffer = &res->as_buffer;
+ /* Set tp_base and tp_bases */
+ type->tp_bases = bases;
+ bases = nullptr;
+ Py_INCREF(base);
+ type->tp_base = base;
+
+ type->tp_basicsize = spec->basicsize;
+ type->tp_itemsize = spec->itemsize;
+
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases)
+ /* Processed above */
+ continue;
+ *reinterpret_cast<void **>(res_start + slotoffsets[slot->slot]) = slot->pfunc;
+
+ /* need to make a copy of the docstring slot, which usually
+ points to a static string literal */
+ if (slot->slot == Py_tp_doc) {
+ const char *old_doc = reinterpret_cast<char *>(slot->pfunc);
+ //_PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
+ size_t len = strlen(old_doc)+1;
+ char *tp_doc = reinterpret_cast<char *>(PyObject_MALLOC(len));
+ if (tp_doc == nullptr) {
+ type->tp_doc = nullptr;
+ PyErr_NoMemory();
+ goto fail;
+ }
+ memcpy(tp_doc, old_doc, len);
+ type->tp_doc = tp_doc;
+ }
+ }
+ if (type->tp_dealloc == nullptr) {
+ /* It's a heap type, so needs the heap types' dealloc.
+ subtype_dealloc will call the base type's tp_dealloc, if
+ necessary. */
+ type->tp_dealloc = _PyPy_subtype_dealloc;
+ }
+
+ /// Here is the only change needed: Do not finalize type creation.
+ // if (PyType_Ready(type) < 0)
+ // goto fail;
+ PepType_SetDict(type, PyDict_New());
+ /// This is not found in PyPy:
+ // if (type->tp_dictoffset) {
+ // res->ht_cached_keys = _PyDict_NewKeysForClass();
+ // }
+
+ /* Set type.__module__ */
+ /// Removed __module__ handling, already implemented.
+
+ return (PyObject*)res;
+
+ fail:
+ Py_DECREF(res);
+ return nullptr;
+}
+
+#endif // PYPY_VERSION
+
+} //extern "C"
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.h b/sources/shiboken6/libshiboken/sbktypefactory.h
new file mode 100644
index 000000000..81cb32d41
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKTYPEFACTORY_H
+#define SBKTYPEFACTORY_H
+
+#include "sbkpython.h"
+
+extern "C"
+{
+
+// PYSIDE-535: Encapsulation of PyType_FromSpec special-cased for PyPy
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec(PyType_Spec *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *, PyObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *, PyObject *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs);
+
+} //extern "C"
+
+#endif // SBKTYPEFACTORY_H
diff --git a/sources/shiboken6/libshiboken/sbkversion.h.in b/sources/shiboken6/libshiboken/sbkversion.h.in
new file mode 100644
index 000000000..5c0b38fdb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkversion.h.in
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKVERSION_H
+#define SBKVERSION_H
+
+#define SHIBOKEN_VERSION "@shiboken_MAJOR_VERSION@.@shiboken_MINOR_VERSION@.@shiboken_MICRO_VERSION@"
+#define SHIBOKEN_MAJOR_VERSION @shiboken_MAJOR_VERSION@
+#define SHIBOKEN_MINOR_VERSION @shiboken_MINOR_VERSION@
+#define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@
+#define SHIBOKEN_RELEASE_LEVEL "final"
+#define SHIBOKEN_SERIAL 0
+#define PYTHON_VERSION_MAJOR @Python_VERSION_MAJOR@
+#define PYTHON_VERSION_MINOR @Python_VERSION_MINOR@
+#define PYTHON_VERSION_PATCH @Python_VERSION_PATCH@
+
+#endif
diff --git a/sources/shiboken6/libshiboken/sbkwindows.h b/sources/shiboken6/libshiboken/sbkwindows.h
new file mode 100644
index 000000000..9e753fa5e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkwindows.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKWINDOWS_H
+#define SBKWINDOWS_H
+
+#ifdef _WIN32
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#endif
+
+#endif // SBKWINDOWS_H
diff --git a/sources/shiboken6/libshiboken/shiboken.h b/sources/shiboken6/libshiboken/shiboken.h
new file mode 100644
index 000000000..fcf777ae0
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shiboken.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKEN_H
+#define SHIBOKEN_H
+
+#include "sbkpython.h"
+#include "autodecref.h"
+#include "basewrapper.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+#include "threadstatesaver.h"
+#include "helper.h"
+#include "pyobjectholder.h"
+#include "sbkarrayconverter.h"
+#include "sbkconverter.h"
+#include "sbkenum.h"
+#include "sbkerrors.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "shibokenmacros.h"
+#include "shibokenbuffer.h"
+#include "signature.h"
+
+#endif // SHIBOKEN_H
+
diff --git a/sources/shiboken6/libshiboken/shibokenbuffer.cpp b/sources/shiboken6/libshiboken/shibokenbuffer.cpp
new file mode 100644
index 000000000..d04613895
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenbuffer.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "shibokenbuffer.h"
+#include <cstdlib>
+#include <cstring>
+
+bool Shiboken::Buffer::checkType(PyObject *pyObj)
+{
+ return PyObject_CheckBuffer(pyObj) != 0;
+}
+
+void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size)
+{
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ if (size)
+ *size = view.len;
+ PyBuffer_Release(&view);
+ return view.buf;
+ }
+ return nullptr;
+}
+
+void *Shiboken::Buffer::copyData(PyObject *pyObj, Py_ssize_t *sizeIn)
+{
+ void *result = nullptr;
+ Py_ssize_t size = 0;
+
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ size = view.len;
+ if (size) {
+ result = std::malloc(size);
+ if (result != nullptr)
+ std::memcpy(result, view.buf, size);
+ else
+ size = 0;
+ }
+ PyBuffer_Release(&view);
+ }
+
+ if (sizeIn != nullptr)
+ *sizeIn = size;
+ return result;
+}
+
+PyObject *Shiboken::Buffer::newObject(void *memory, Py_ssize_t size, Type type)
+{
+ if (size == 0)
+ Py_RETURN_NONE;
+ Py_buffer view;
+ memset(&view, 0, sizeof(Py_buffer));
+ view.buf = memory;
+ view.len = size;
+ view.readonly = type == Shiboken::Buffer::ReadOnly;
+ view.ndim = 1;
+ view.itemsize = sizeof(char);
+ Py_ssize_t shape[] = { size };
+ view.shape = shape;
+ // Pep384: This is way too complicated and impossible with the limited api:
+ //return PyMemoryView_FromBuffer(&view);
+ return PyMemoryView_FromMemory(reinterpret_cast<char *>(view.buf),
+ size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
+}
+
+PyObject *Shiboken::Buffer::newObject(const void *memory, Py_ssize_t size)
+{
+ return newObject(const_cast<void *>(memory), size, ReadOnly);
+}
diff --git a/sources/shiboken6/libshiboken/shibokenbuffer.h b/sources/shiboken6/libshiboken/shibokenbuffer.h
new file mode 100644
index 000000000..6b17eb6eb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenbuffer.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKEN_BUFFER_H
+#define SHIBOKEN_BUFFER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+
+namespace Buffer
+{
+ enum Type {
+ ReadOnly,
+ WriteOnly,
+ ReadWrite
+ };
+
+ /**
+ * Creates a new Python buffer pointing to a contiguous memory block at
+ * \p memory of size \p size.
+ */
+ LIBSHIBOKEN_API PyObject *newObject(void *memory, Py_ssize_t size, Type type);
+
+ /**
+ * Creates a new <b>read only</b> Python buffer pointing to a contiguous memory block at
+ * \p memory of size \p size.
+ */
+ LIBSHIBOKEN_API PyObject *newObject(const void *memory, Py_ssize_t size);
+
+ /**
+ * Check if is ok to use \p pyObj as argument in all function under Shiboken::Buffer namespace.
+ */
+ LIBSHIBOKEN_API bool checkType(PyObject *pyObj);
+
+ /**
+ * Returns a pointer to the memory pointed by the buffer \p pyObj, \p size is filled with the buffer
+ * size if not null.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ */
+ LIBSHIBOKEN_API void *getPointer(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
+ /**
+ * Returns a copy of the buffer data which should be free'd.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ * nullptr is returned for empty buffers.
+ */
+ LIBSHIBOKEN_API void *copyData(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
+} // namespace Buffer
+} // namespace Shiboken
+
+#endif
diff --git a/sources/shiboken6/libshiboken/shibokenmacros.h b/sources/shiboken6/libshiboken/shibokenmacros.h
new file mode 100644
index 000000000..3c083c5bb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenmacros.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKENMACROS_H
+#define SHIBOKENMACROS_H
+
+// LIBSHIBOKEN_API macro is used for the public API symbols.
+#if defined _WIN32
+# define LIBSHIBOKEN_EXPORT __declspec(dllexport)
+# ifdef _MSC_VER
+# define LIBSHIBOKEN_IMPORT __declspec(dllimport)
+# else
+# define LIBSHIBOKEN_IMPORT
+# endif
+#else
+# define LIBSHIBOKEN_EXPORT __attribute__ ((visibility("default")))
+# define LIBSHIBOKEN_IMPORT
+#endif
+
+#ifdef BUILD_LIBSHIBOKEN
+# define LIBSHIBOKEN_API LIBSHIBOKEN_EXPORT
+#else
+# define LIBSHIBOKEN_API LIBSHIBOKEN_IMPORT
+#endif
+
+#endif // SHIBOKENMACROS_H
diff --git a/sources/shiboken6/libshiboken/signature.h b/sources/shiboken6/libshiboken/signature.h
new file mode 100644
index 000000000..e0130b5a6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SIGNATURE_H
+#define SIGNATURE_H
+
+#include "shibokenmacros.h"
+#include "sbkpython.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API int InitSignatureStrings(PyTypeObject *, const char *[]);
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]);
+LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *, PyObject *);
+LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *);
+LIBSHIBOKEN_API PyObject *GetFeatureDict();
+
+} // extern "C"
+
+#endif // SIGNATURE_H
diff --git a/sources/shiboken6/libshiboken/signature/signature.cpp b/sources/shiboken6/libshiboken/signature/signature.cpp
new file mode 100644
index 000000000..3255cb56d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature.cpp
@@ -0,0 +1,640 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature.cpp
+// -------------
+//
+// This is the main file of the signature module.
+// It contains the most important functions and avoids confusion
+// by moving many helper functions elsewhere.
+//
+// General documentation can be found in `signature_doc.rst`.
+//
+
+#include "signature.h"
+#include "signature_p.h"
+
+#include "basewrapper.h"
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkfeature_base.h"
+
+#include <structmember.h>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+static PyObject *CreateSignature(PyObject *props, PyObject *key)
+{
+ /*
+ * Here is the new function to create all signatures. It simply calls
+ * into Python and creates a signature object directly.
+ * This is so much simpler than using all the attributes explicitly
+ * to support '_signature_is_functionlike()'.
+ */
+ return PyObject_CallFunction(pyside_globals->create_signature_func,
+ "(OO)", props, key);
+}
+
+PyObject *GetClassOrModOf(PyObject *ob)
+{
+ /*
+ * Return the type or module of a function or type.
+ * The purpose is finally to use the name of the object.
+ */
+ if (PyType_Check(ob)) {
+ // PySide-928: The type case must do refcounting like the others as well.
+ Py_INCREF(ob);
+ return ob;
+ }
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr)
+ return _get_class_of_bm(ob);
+#endif
+ if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
+ return _get_class_of_cf(ob);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return _get_class_of_sm(ob);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return _get_class_of_descr(ob);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return _get_class_of_descr(ob);
+ Py_FatalError("unexpected type in GetClassOrModOf");
+ return nullptr;
+}
+
+PyObject *GetTypeKey(PyObject *ob)
+{
+ assert(PyType_Check(ob) || PyModule_Check(ob));
+ /*
+ * Obtain a unique key using the module name and the type name.
+ *
+ * PYSIDE-1286: We use correct __module__ and __qualname__, now.
+ */
+ AutoDecRef module_name(PyObject_GetAttr(ob, PyMagicName::module()));
+ if (module_name.isNull()) {
+ // We have no module_name because this is a module ;-)
+ PyErr_Clear();
+ module_name.reset(PyObject_GetAttr(ob, PyMagicName::name()));
+ return Py_BuildValue("O", module_name.object());
+ }
+ AutoDecRef class_name(PyObject_GetAttr(ob, PyMagicName::qualname()));
+ if (class_name.isNull()) {
+ Py_FatalError("Signature: missing class name in GetTypeKey");
+ return nullptr;
+ }
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
+}
+
+static PyObject *empty_dict = nullptr;
+
+PyObject *TypeKey_to_PropsDict(PyObject *type_key)
+{
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ if (dict == nullptr) {
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ dict = empty_dict;
+ }
+ if (!PyDict_Check(dict))
+ dict = PySide_BuildSignatureProps(type_key);
+ return dict;
+}
+
+static PyObject *_GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier)
+{
+ // Special case: We want to know the func_kind.
+ if (modifier) {
+ PyUnicode_InternInPlace(&modifier);
+ if (modifier == PyMagicName::func_kind())
+ return Py_BuildValue("O", func_kind);
+ }
+
+ AutoDecRef key(modifier == nullptr ? Py_BuildValue("O", func_kind)
+ : Py_BuildValue("(OO)", func_kind, modifier));
+ PyObject *value = PyDict_GetItem(props, key);
+ if (value == nullptr) {
+ // we need to compute a signature object
+ value = CreateSignature(props, key);
+ if (value != nullptr) {
+ if (PyDict_SetItem(props, key, value) < 0)
+ // this is an error
+ return nullptr;
+ }
+ else {
+ // key not found
+ Py_RETURN_NONE;
+ }
+ }
+ return Py_INCREF(value), value;
+}
+
+#ifdef PYPY_VERSION
+PyObject *GetSignature_Method(PyObject *obfunc, PyObject *modifier)
+{
+ AutoDecRef obtype_mod(GetClassOrModOf(obfunc));
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ if (type_key.isNull())
+ Py_RETURN_NONE;
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
+ if (dict == nullptr)
+ return nullptr;
+ AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+#endif
+
+PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
+{
+ // make sure that we look into PyCFunction, only...
+ if (Py_TYPE(obfunc) == PepFunction_TypePtr)
+ Py_RETURN_NONE;
+ AutoDecRef obtype_mod(GetClassOrModOf(obfunc));
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ if (type_key.isNull())
+ Py_RETURN_NONE;
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
+ if (dict == nullptr)
+ return nullptr;
+ AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
+ if (props == nullptr)
+ Py_RETURN_NONE;
+
+ int flags = PyCFunction_GET_FLAGS(obfunc);
+ PyObject *func_kind;
+ if (PyModule_Check(obtype_mod.object()))
+ func_kind = PyName::function();
+ else if (flags & METH_CLASS)
+ func_kind = PyName::classmethod();
+ else if (flags & METH_STATIC)
+ func_kind = PyName::staticmethod();
+ else
+ func_kind = PyName::method();
+ return _GetSignature_Cached(props, func_kind, modifier);
+}
+
+PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
+{
+ AutoDecRef func_name(PyObject_GetAttr(ob, PyMagicName::name()));
+ AutoDecRef objclass(PyObject_GetAttr(ob, PyMagicName::objclass()));
+ AutoDecRef class_key(GetTypeKey(objclass));
+ if (func_name.isNull() || objclass.isNull() || class_key.isNull())
+ return nullptr;
+ PyObject *dict = TypeKey_to_PropsDict(class_key);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, func_name);
+ if (props == nullptr) {
+ // handle `__init__` like the class itself
+ if (PyUnicode_CompareWithASCIIString(func_name, "__init__") == 0)
+ return GetSignature_TypeMod(objclass, modifier);
+ Py_RETURN_NONE;
+ }
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier)
+{
+ AutoDecRef ob_name(PyObject_GetAttr(ob, PyMagicName::name()));
+ AutoDecRef ob_key(GetTypeKey(ob));
+
+ PyObject *dict = TypeKey_to_PropsDict(ob_key);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, ob_name);
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additional to the interface via `__signature__`, we also provide
+// a general function, which allows for different signature layouts.
+// The `modifier` argument is a string that is passed in from `loader.py`.
+// Configuration what the modifiers mean is completely in Python.
+//
+// PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+//
+
+PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
+{
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr) {
+ return pyside_bm_get___signature__(ob, modifier);
+ }
+#endif
+ if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
+ return pyside_cf_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return pyside_sm_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return pyside_md_get___signature__(ob, modifier);
+ if (PyType_Check(ob))
+ return pyside_tp_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ // For classmethods we use the simple wrapper description implementation.
+ if (Py_TYPE(ob) == &PyClassMethodDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ return nullptr;
+}
+
+static PyObject *get_signature(PyObject * /* self */, PyObject *args)
+{
+ PyObject *ob;
+ PyObject *modifier = nullptr;
+
+ if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier))
+ return nullptr;
+ if (Py_TYPE(ob) == PepFunction_TypePtr)
+ Py_RETURN_NONE;
+ PyObject *ret = get_signature_intern(ob, modifier);
+ if (ret != nullptr)
+ return ret;
+ Py_RETURN_NONE;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// feature_import -- special handling for `from __feature__ import ...`
+//
+// The actual function is implemented in Python.
+// When no features are involved, we redirect to the original import.
+// This avoids an extra function level in tracebacks that is irritating.
+//
+
+static PyObject *feature_import(PyObject * /* self */, PyObject *args, PyObject *kwds)
+{
+ PyObject *ret = PyObject_Call(pyside_globals->feature_import_func, args, kwds);
+ if (ret != Py_None)
+ return ret;
+ // feature_import did not handle it, so call the normal import.
+ Py_DECREF(ret);
+ static PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *import_func = PyDict_GetItemString(builtins, "__orig_import__");
+ if (import_func == nullptr) {
+ Py_FatalError("builtins has no \"__orig_import__\" function");
+ }
+ ret = PyObject_Call(import_func, args, kwds);
+ if (ret) {
+ // PYSIDE-2029: Intercept after the import to search for PySide usage.
+ PyObject *post = PyObject_CallFunctionObjArgs(pyside_globals->feature_imported_func,
+ ret, nullptr);
+ Py_XDECREF(post);
+ if (post == nullptr) {
+ Py_DECREF(ret);
+ return nullptr;
+ }
+ }
+ return ret;
+}
+
+PyMethodDef signature_methods[] = {
+ {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS, nullptr},
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the signature, passing an optional string parameter"},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Argument Handling
+// -----------------
+//
+// * PySide_BuildSignatureArgs
+//
+// Called during class or module initialization.
+// The signature strings from the C modules are stored in a dict for
+// later use.
+//
+// * PySide_BuildSignatureProps
+//
+// Called on demand during signature retieval. This function calls all the way
+// through `parser.py` and prepares all properties for the functions of the class.
+// The parsed properties can then be used to create signature objects.
+//
+
+static int PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures[])
+{
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ /*
+ * PYSIDE-996: Avoid string overflow in MSVC, which has a limit of
+ * 2**15 unicode characters (64 K memory).
+ * Instead of one huge string, we take a ssize_t that is the
+ * address of a string array. It will not be turned into a real
+ * string list until really used by Python. This is quite optimal.
+ */
+ AutoDecRef numkey(Py_BuildValue("n", signatures));
+ if (type_key.isNull() || numkey.isNull()
+ || PyDict_SetItem(pyside_globals->arg_dict, type_key, numkey) < 0)
+ return -1;
+ /*
+ * We record also a mapping from type key to type/module. This helps to
+ * lazily initialize the Py_LIMITED_API in name_key_to_func().
+ */
+ return PyDict_SetItem(pyside_globals->map_dict, type_key, obtype_mod) == 0 ? 0 : -1;
+}
+
+PyObject *PySide_BuildSignatureProps(PyObject *type_key)
+{
+ /*
+ * Here is the second part of the function.
+ * This part will be called on-demand when needed by some attribute.
+ * We simply pick up the arguments that we stored here and replace
+ * them by the function result.
+ */
+ if (type_key == nullptr)
+ return nullptr;
+ PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ AutoDecRef strings(_address_to_stringlist(numkey));
+ if (strings.isNull())
+ return nullptr;
+ AutoDecRef arg_tup(Py_BuildValue("(OO)", type_key, strings.object()));
+ if (arg_tup.isNull())
+ return nullptr;
+ PyObject *dict = PyObject_CallObject(pyside_globals->pyside_type_init_func, arg_tup);
+ if (dict == nullptr) {
+ if (PyErr_Occurred())
+ return nullptr;
+ // No error: return an empty dict.
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ return empty_dict;
+ }
+ // PYSIDE-1019: Build snake case versions of the functions.
+ if (insert_snake_case_variants(dict) < 0)
+ return nullptr;
+ // We replace the arguments by the result dict.
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
+ return nullptr;
+ return dict;
+}
+//
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef PYPY_VERSION
+static bool get_lldebug_flag()
+{
+ auto *dic = PySys_GetObject("pypy_translation_info");
+ int lldebug = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug"));
+ int lldebug0 = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug0"));
+ return lldebug || lldebug0;
+}
+
+#endif
+
+static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
+{
+#ifdef PYPY_VERSION
+ static const bool have_problem = get_lldebug_flag();
+ if (have_problem)
+ return 0; // crash with lldebug at `PyDict_Next`
+#endif
+ /*
+ * Initialization of module functions and resolving of static methods.
+ */
+ const char *name = PyModule_GetName(module);
+ if (name == nullptr)
+ return -1;
+
+ // we abuse the call for types, since they both have a __name__ attribute.
+ if (PySide_BuildSignatureArgs(module, signatures) < 0)
+ return -1;
+
+ /*
+ * Note: This function crashed when called from PySide_BuildSignatureArgs.
+ * Probably this was an import timing problem.
+ *
+ * Pep384: We need to switch this always on since we have no access
+ * to the PyCFunction attributes. Therefore I simplified things
+ * and always use our own mapping.
+ */
+ PyObject *key, *func, *obdict = PyModule_GetDict(module);
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(obdict, &pos, &key, &func))
+ if (PyCFunction_Check(func))
+ if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0)
+ return -1;
+ // The finish_import function will not work the first time since phase 2
+ // was not yet run. But that is ok, because the first import is always for
+ // the shiboken module (or a test module).
+ if (pyside_globals->finish_import_func == nullptr) {
+ assert(strncmp(name, "PySide6.", 8) != 0);
+ return 0;
+ }
+ AutoDecRef ret(PyObject_CallFunction(
+ pyside_globals->finish_import_func, "(O)", module));
+ return ret.isNull() ? -1 : 0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// External functions interface
+//
+// These are exactly the supported functions from `signature.h`.
+//
+
+int InitSignatureStrings(PyTypeObject *type, const char *signatures[])
+{
+ // PYSIDE-2404: This function now also builds the mapping for static methods.
+ // It was one missing spot to let Lazy import work.
+ init_shibokensupport_module();
+ auto *ob_type = reinterpret_cast<PyObject *>(type);
+ int ret = PySide_BuildSignatureArgs(ob_type, signatures);
+ if (ret < 0 || _build_func_to_type(ob_type) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+ return ret;
+}
+
+void FinishSignatureInitialization(PyObject *module, const char *signatures[])
+{
+ /*
+ * This function is called at the very end of a module initialization.
+ * We now patch certain types to support the __signature__ attribute,
+ * initialize module functions and resolve static methods.
+ *
+ * Still, it is not possible to call init phase 2 from here,
+ * because the import is still running. Do it from Python!
+ */
+ init_shibokensupport_module();
+
+#ifndef PYPY_VERSION
+ static const bool patch_types = true;
+#else
+ // PYSIDE-535: On PyPy we cannot patch builtin types. This can be
+ // re-implemented later. For now, we use `get_signature`, instead.
+ static const bool patch_types = false;
+#endif
+
+ if ((patch_types && PySide_PatchTypes() < 0)
+ || PySide_FinishSignatures(module, signatures) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+}
+
+static PyObject *adjustFuncName(const char *func_name)
+{
+ /*
+ * PYSIDE-1019: Modify the function name expression according to feature.
+ *
+ * - snake_case
+ * The function name must be converted.
+ * - full_property
+ * The property name must be used and "fset" appended.
+ *
+ * modname.subname.classsname.propname.fset
+ *
+ * Class properties must use the expression
+ *
+ * modname.subname.classsname.__dict__['propname'].fset
+ *
+ * Note that fget is impossible because there are no parameters.
+ */
+ static const char mapping_name[] = "shibokensupport.signature.mapping";
+ static PyObject *sys_modules = PySys_GetObject("modules");
+ static PyObject *mapping = PyDict_GetItemString(sys_modules, mapping_name);
+ static PyObject *ns = PyModule_GetDict(mapping);
+
+ char _path[200 + 1] = {};
+ const char *_name = strrchr(func_name, '.');
+ strncat(_path, func_name, _name - func_name);
+ ++_name;
+
+ // This is a very cheap call into `mapping.py`.
+ PyObject *update_mapping = PyDict_GetItemString(ns, "update_mapping");
+ AutoDecRef res(PyObject_CallFunctionObjArgs(update_mapping, nullptr));
+ if (res.isNull())
+ return nullptr;
+
+ // Run `eval` on the type string to get the object.
+ // PYSIDE-1710: If the eval does not work, return the given string.
+ AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns));
+ if (obtype.isNull())
+ return String::fromCString(func_name);
+
+ if (PyModule_Check(obtype.object())) {
+ // This is a plain function. Return the unmangled name.
+ return String::fromCString(func_name);
+ }
+ assert(PyType_Check(obtype)); // This was not true for __init__!
+
+ // Find the feature flags
+ auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
+ AutoDecRef dict(PepType_GetDict(type));
+ int id = currentSelectId(type);
+ id = id < 0 ? 0 : id; // if undefined, set to zero
+ auto lower = id & 0x01;
+ auto is_prop = id & 0x02;
+ bool is_class_prop = false;
+
+ // Compute all needed info.
+ PyObject *name = String::getSnakeCaseName(_name, lower);
+ PyObject *prop_name{};
+ if (is_prop) {
+ PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods());
+ prop_name = PyDict_GetItem(prop_methods, name);
+ if (prop_name != nullptr) {
+ PyObject *prop = PyDict_GetItem(dict, prop_name);
+ is_class_prop = Py_TYPE(prop) != &PyProperty_Type;
+ }
+ }
+
+ // Finally, generate the correct path expression.
+ char _buf[250 + 1] = {};
+ if (prop_name) {
+ auto _prop_name = String::toCString(prop_name);
+ if (is_class_prop)
+ snprintf(_buf, sizeof(_buf), "%s.__dict__['%s'].fset", _path, _prop_name);
+ else
+ snprintf(_buf, sizeof(_buf), "%s.%s.fset", _path, _prop_name);
+ }
+ else {
+ auto _name = String::toCString(name);
+ snprintf(_buf, sizeof(_buf), "%s.%s", _path, _name);
+ }
+ return String::fromCString(_buf);
+}
+
+void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
+{
+ init_shibokensupport_module();
+ /*
+ * This function replaces the type error construction with extra
+ * overloads parameter in favor of using the signature module.
+ * Error messages are rare, so we do it completely in Python.
+ */
+
+ // PYSIDE-1305: Handle errors set by fillQtProperties.
+ if (PyErr_Occurred()) {
+ PyObject *e, *v, *t;
+ // Note: These references are all borrowed.
+ PyErr_Fetch(&e, &v, &t);
+ Py_DECREF(e);
+ info = v;
+ Py_XDECREF(t);
+ }
+ // PYSIDE-1019: Modify the function name expression according to feature.
+ AutoDecRef new_func_name(adjustFuncName(func_name));
+ if (new_func_name.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument failed to call update_mapping");
+ }
+ if (info == nullptr)
+ info = Py_None;
+ AutoDecRef res(PyObject_CallFunctionObjArgs(pyside_globals->seterror_argument_func,
+ args, new_func_name.object(), info, nullptr));
+ if (res.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument did not receive a result");
+ }
+ PyObject *err, *msg;
+ if (!PyArg_UnpackTuple(res, func_name, 2, 2, &err, &msg)) {
+ PyErr_Print();
+ Py_FatalError("unexpected failure in seterror_argument");
+ }
+ PyErr_SetObject(err, msg);
+}
+
+/*
+ * Support for the metatype SbkObjectType_Type's tp_getset.
+ *
+ * This was not necessary for __signature__, because PyType_Type inherited it.
+ * But the __doc__ attribute existed already by inheritance, and calling
+ * PyType_Modified() is not supported. So we added the getsets explicitly
+ * to the metatype.
+ *
+ * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+ */
+
+PyObject *Sbk_TypeGet___doc__(PyObject *ob)
+{
+ init_shibokensupport_module();
+ return pyside_tp_get___doc__(ob);
+}
+
+PyObject *GetFeatureDict()
+{
+ init_shibokensupport_module();
+ return pyside_globals->feature_dict;
+}
+
+} //extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_extend.cpp b/sources/shiboken6/libshiboken/signature/signature_extend.cpp
new file mode 100644
index 000000000..7292f8216
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_extend.cpp
@@ -0,0 +1,230 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_extend.cpp
+// --------------------
+//
+// This file contains the additions and changes to the following
+// Python types:
+//
+// PyMethodDescr_Type
+// PyCFunction_Type
+// PyStaticMethod_Type
+// (*) PyType_Type
+// PyWrapperDescr_Type
+//
+// Their `tp_getset` fields are modified to support the `__signature__`
+// attribute and additions to the `__doc__` attribute.
+//
+// PYSIDE-535: PyType_Type patching is removed,
+// Shiboken.ObjectType and Shiboken.EnumMeta have new getsets, instead.
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+using signaturefunc = PyObject *(*)(PyObject *, PyObject *);
+
+static PyObject *_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier)
+{
+ /*
+ * Be a writable Attribute, but have a computed value.
+ *
+ * If a signature has not been written, call the signature function.
+ * If it has been written, return the written value.
+ * After __del__ was called, the function value re-appears.
+ *
+ * Note: This serves also for the new version that does not allow any
+ * assignment if we have a computed value. We only need to check if
+ * a computed value exists and then forbid writing.
+ * See pyside_set___signature
+ */
+ PyObject *ret = PyDict_GetItem(pyside_globals->value_dict, ob);
+ if (ret == nullptr)
+ return ob == nullptr ? nullptr : sf(ob, modifier);
+ Py_INCREF(ret);
+ return ret;
+}
+
+#ifdef PYPY_VERSION
+PyObject *pyside_bm_get___signature__(PyObject *func, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Method, func, modifier);
+}
+#endif
+
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier)
+{
+ AutoDecRef func(PyObject_GetAttr(sm, PyMagicName::func()));
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
+{
+ AutoDecRef func(name_key_to_func(ob_md));
+ if (func.object() == Py_None)
+ Py_RETURN_NONE;
+ if (func.isNull())
+ Py_FatalError("missing mapping in MethodDescriptor");
+ return pyside_cf_get___signature__(func, modifier);
+}
+
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Wrapper, ob, modifier);
+}
+
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Augmenting builtin types with a __signature__ attribute.
+//
+// This is a harmless change to Python, similar like __text_signature__.
+// We could avoid it, but then we would need to copy quite some module
+// initialization functions which are pretty version- and word size
+// dependent. I think this little patch is the lesser of the two evils.
+//
+// Please note that in fact we are modifying 'type', the metaclass of all
+// objects, because we add new functionality.
+//
+// Addendum 2019-01-12: We now also compute a docstring from the signature.
+//
+
+// keep the original __doc__ functions
+static PyObject *old_cf_doc_descr = nullptr;
+static PyObject *old_sm_doc_descr = nullptr;
+static PyObject *old_md_doc_descr = nullptr;
+static PyObject *old_tp_doc_descr = nullptr;
+static PyObject *old_wd_doc_descr = nullptr;
+
+static int handle_doc_in_progress = 0;
+
+static PyObject *handle_doc(PyObject *ob, PyObject *old_descr)
+{
+ AutoDecRef ob_type_mod(GetClassOrModOf(ob));
+ const char *name;
+ bool isModule = PyModule_Check(ob_type_mod.object());
+ if (isModule)
+ name = PyModule_GetName(ob_type_mod.object());
+ else
+ name = reinterpret_cast<PyTypeObject *>(ob_type_mod.object())->tp_name;
+ PyObject *res{};
+
+ if (handle_doc_in_progress || name == nullptr
+ || (isModule && strncmp(name, "PySide6.", 8) != 0)) {
+ res = PyObject_CallMethodObjArgs(old_descr, PyMagicName::get(), ob, nullptr);
+ } else {
+ handle_doc_in_progress++;
+ res = PyObject_CallFunction(pyside_globals->make_helptext_func, "(O)", ob);
+ handle_doc_in_progress--;
+ }
+
+ if (res)
+ return res;
+
+ PyErr_Clear();
+ Py_RETURN_NONE;
+}
+
+static PyObject *pyside_cf_get___doc__(PyObject *cf)
+{
+ return handle_doc(cf, old_cf_doc_descr);
+}
+
+static PyObject *pyside_sm_get___doc__(PyObject *sm)
+{
+ return handle_doc(sm, old_sm_doc_descr);
+}
+
+static PyObject *pyside_md_get___doc__(PyObject *md)
+{
+ return handle_doc(md, old_md_doc_descr);
+}
+
+PyObject *pyside_tp_get___doc__(PyObject *tp)
+{
+ return handle_doc(tp, old_tp_doc_descr);
+}
+
+static PyObject *pyside_wd_get___doc__(PyObject *wd)
+{
+ return handle_doc(wd, old_wd_doc_descr);
+}
+
+// PYSIDE-535: We cannot patch types easily in PyPy.
+// Let's use the `get_signature` function, instead.
+static PyGetSetDef new_PyCFunction_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_cf_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyStaticMethod_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_sm_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyMethodDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_md_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_wd_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+int PySide_PatchTypes(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ AutoDecRef meth_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(&PyUnicode_Type), "split"));
+ AutoDecRef wrap_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(Py_TYPE(Py_True)), "__add__"));
+ // abbreviations for readability
+ auto md_gs = new_PyMethodDescr_getsets;
+ auto md_doc = &old_md_doc_descr;
+ auto cf_gs = new_PyCFunction_getsets;
+ auto cf_doc = &old_cf_doc_descr;
+ auto sm_gs = new_PyStaticMethod_getsets;
+ auto sm_doc = &old_sm_doc_descr;
+ auto wd_gs = new_PyWrapperDescr_getsets;
+ auto wd_doc = &old_wd_doc_descr;
+
+ if (meth_descr.isNull() || wrap_descr.isNull()
+ || PyType_Ready(Py_TYPE(meth_descr)) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, md_gs, md_doc) < 0
+ || add_more_getsets(&PyCFunction_Type, cf_gs, cf_doc) < 0
+ || add_more_getsets(PepStaticMethod_TypePtr, sm_gs, sm_doc) < 0
+ || add_more_getsets(Py_TYPE(wrap_descr), wd_gs, wd_doc) < 0
+ )
+ return -1;
+ init_done = 1;
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_globals.cpp b/sources/shiboken6/libshiboken/signature/signature_globals.cpp
new file mode 100644
index 000000000..3a79a12d5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_globals.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_global.cpp
+//
+// This file contains the global data structures and init code.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkenum.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+static const char *PySide_CompressedSignaturePackage[] = {
+#include "embed/signature_inc.h"
+ };
+
+static const unsigned char PySide_SignatureLoader[] = {
+#include "embed/signature_bootstrap_inc.h"
+ };
+
+static safe_globals_struc *init_phase_1()
+{
+ do {
+ auto *p = reinterpret_cast<safe_globals_struc *>
+ (malloc(sizeof(safe_globals_struc)));
+ if (p == nullptr)
+ break;
+ /*
+ * Initializing module signature_bootstrap.
+ * Since we now have an embedding script, we can do this without any
+ * Python strings in the C code.
+ */
+#if defined(Py_LIMITED_API) || defined(SHIBOKEN_NO_EMBEDDING_PYC)
+ // We must work for multiple versions or we are cross-building for a different
+ // Python version interpreter, so use source code.
+#else
+ AutoDecRef marshal_module(PyImport_Import(PyName::marshal())); // builtin
+ AutoDecRef loads(PyObject_GetAttr(marshal_module, PyName::loads()));
+ if (loads.isNull())
+ break;
+#endif
+ char *bytes_cast = reinterpret_cast<char *>(
+ const_cast<unsigned char *>(PySide_SignatureLoader));
+ AutoDecRef bytes(PyBytes_FromStringAndSize(bytes_cast, sizeof(PySide_SignatureLoader)));
+ if (bytes.isNull())
+ break;
+#if defined(Py_LIMITED_API) || defined(SHIBOKEN_NO_EMBEDDING_PYC)
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *compile = PyDict_GetItem(builtins, PyName::compile());
+ if (compile == nullptr)
+ break;
+ AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
+ bytes.object(), "signature_bootstrap.py", "exec"));
+#else
+ AutoDecRef code_obj(PyObject_CallFunctionObjArgs(
+ loads, bytes.object(), nullptr));
+#endif
+ if (code_obj.isNull())
+ break;
+ p->helper_module = PyImport_ExecCodeModule("signature_bootstrap", code_obj);
+ if (p->helper_module == nullptr)
+ break;
+ // Initialize the module
+ PyObject *mdict = PyModule_GetDict(p->helper_module);
+ if (PyDict_SetItem(mdict, PyMagicName::builtins(), PyEval_GetBuiltins()) < 0)
+ break;
+
+ /*********************************************************************
+ *
+ * Attention!
+ * ----------
+ *
+ * We are unpacking an embedded ZIP file with more signature modules.
+ * They will be loaded later with the zipimporter.
+ * The file `signature_bootstrap.py` does the unpacking and starts the
+ * loader. See `init_phase_2`.
+ *
+ * Due to MSVC's limitation to 64k strings, we needed to assemble pieces.
+ */
+ auto **block_ptr = reinterpret_cast<const char **>(PySide_CompressedSignaturePackage);
+ PyObject *piece{};
+ AutoDecRef zipped_string_sequence(PyList_New(0));
+ for (; **block_ptr != 0; ++block_ptr) {
+ // we avoid the string/unicode dilemma by not using PyString_XXX:
+ piece = Py_BuildValue("s", *block_ptr);
+ if (piece == nullptr || PyList_Append(zipped_string_sequence, piece) < 0)
+ break;
+ }
+ if (PyDict_SetItemString(mdict, "zipstring_sequence", zipped_string_sequence) < 0)
+ break;
+
+ // build a dict for diverse mappings
+ p->map_dict = PyDict_New();
+
+ // build a dict for the prepared arguments
+ p->arg_dict = PyDict_New();
+ if (PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0)
+ break;
+
+ // build a dict for assigned signature values
+ p->value_dict = PyDict_New();
+
+ // PYSIDE-1019: build a __feature__ dict
+ p->feature_dict = PyDict_New();
+ if (PyObject_SetAttrString(p->helper_module, "pyside_feature_dict", p->feature_dict) < 0)
+ break;
+
+ // This function will be disabled until phase 2 is done.
+ p->finish_import_func = nullptr;
+
+ return p;
+
+ } while (0);
+
+ PyErr_Print();
+ Py_FatalError("could not initialize part 1");
+ return nullptr;
+}
+
+static int init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
+{
+ do {
+ PyMethodDef *ml;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != nullptr; ml++) {
+ PyObject *v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr
+ || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
+ break;
+ Py_DECREF(v);
+ }
+ // The first entry is __feature_import__, add documentation.
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *imp_func = PyDict_GetItemString(builtins, "__import__");
+ PyObject *imp_doc = PyObject_GetAttrString(imp_func, "__doc__");
+ signature_methods[0].ml_doc = String::toCString(imp_doc);
+
+ PyObject *bootstrap_func = PyObject_GetAttrString(p->helper_module, "bootstrap");
+ if (bootstrap_func == nullptr)
+ break;
+
+ /*********************************************************************
+ *
+ * Attention!
+ * ----------
+ *
+ * This is the entry point where everything in folder
+ * `shibokensupport` becomes initialized. It starts with
+ * `signature_bootstrap.py` and continues from there to `loader.py`.
+ *
+ * The return value of the bootstrap function is the loader module.
+ */
+ PyObject *loader = PyObject_CallFunctionObjArgs(bootstrap_func, nullptr);
+ if (loader == nullptr)
+ break;
+
+ // now the loader should be initialized
+ p->pyside_type_init_func = PyObject_GetAttrString(loader, "pyside_type_init");
+ if (p->pyside_type_init_func == nullptr)
+ break;
+ p->create_signature_func = PyObject_GetAttrString(loader, "create_signature");
+ if (p->create_signature_func == nullptr)
+ break;
+ p->seterror_argument_func = PyObject_GetAttrString(loader, "seterror_argument");
+ if (p->seterror_argument_func == nullptr)
+ break;
+ p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext");
+ if (p->make_helptext_func == nullptr)
+ break;
+ p->finish_import_func = PyObject_GetAttrString(loader, "finish_import");
+ if (p->finish_import_func == nullptr)
+ break;
+ p->feature_import_func = PyObject_GetAttrString(loader, "feature_import");
+ if (p->feature_import_func == nullptr)
+ break;
+ p->feature_imported_func = PyObject_GetAttrString(loader, "feature_imported");
+ if (p->feature_imported_func == nullptr)
+ break;
+
+ // We call stuff like the feature initialization late,
+ // after all the function pointers are in place.
+ PyObject *post_init_func = PyObject_GetAttrString(loader, "post_init");
+ if (post_init_func == nullptr)
+ break;
+ PyObject *ret = PyObject_CallFunctionObjArgs(post_init_func, nullptr);
+ if (ret == nullptr)
+ break;
+
+ return 0;
+
+ } while (0);
+
+ PyErr_Print();
+ Py_FatalError("could not initialize part 2");
+ return -1;
+}
+
+#ifndef _WIN32
+////////////////////////////////////////////////////////////////////////////
+// a stack trace for linux-like platforms
+#include <cstdio>
+#if defined(__GLIBC__)
+# include <execinfo.h>
+#endif
+#include <signal.h>
+#include <cstdlib>
+#include <unistd.h>
+
+static void handler(int sig) {
+#if defined(__GLIBC__)
+ void *array[30];
+ size_t size;
+
+ // get void *'s for all entries on the stack
+ size = backtrace(array, 30);
+
+ // print out all the frames to stderr
+#endif
+ std::fprintf(stderr, "Error: signal %d:\n", sig);
+#if defined(__GLIBC__)
+ backtrace_symbols_fd(array, size, STDERR_FILENO);
+#endif
+ exit(1);
+}
+
+////////////////////////////////////////////////////////////////////////////
+#endif // _WIN32
+
+safe_globals_struc *pyside_globals = nullptr;
+
+void init_shibokensupport_module(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals != nullptr)
+ init_done = 1;
+
+#ifndef _WIN32
+ // We enable the stack trace in CI, only.
+ const char *testEnv = getenv("QTEST_ENVIRONMENT");
+ if (testEnv && strstr(testEnv, "ci"))
+ signal(SIGSEGV, handler); // install our handler
+#endif // _WIN32
+
+ init_phase_2(pyside_globals, signature_methods);
+ // Enum must be initialized when signatures exist, not earlier.
+ init_enum();
+ }
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_helper.cpp b/sources/shiboken6/libshiboken/signature/signature_helper.cpp
new file mode 100644
index 000000000..cf84cfa13
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_helper.cpp
@@ -0,0 +1,389 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_helper.cpp
+// --------------------
+//
+// This file contains assoerted helper functions that are needed,
+// but it is not helpful to see them all the time.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+static int _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp)
+{
+ /*
+ * This function pre-fills all fields of the new gsp. We then
+ * insert the changed values.
+ */
+ PyGetSetDef *gsp = type->tp_getset;
+ if (gsp != nullptr) {
+ for (; gsp->name != nullptr; gsp++) {
+ if (strcmp(gsp->name, name) == 0) {
+ new_gsp->set = gsp->set;
+ new_gsp->doc = gsp->doc;
+ new_gsp->closure = gsp->closure;
+ return 1; // success
+ }
+ }
+ }
+ PyMemberDef *md = type->tp_members;
+ if (md != nullptr)
+ for (; md->name != nullptr; md++)
+ if (strcmp(md->name, name) == 0)
+ return 1;
+ return 0;
+}
+
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
+{
+ /*
+ * This function is used to assign a new `__signature__` attribute,
+ * and also to override a `__doc__` or `__name__` attribute.
+ *
+ * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+ */
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();
+ for (; gsp->name != nullptr; gsp++) {
+ PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
+ if (have_descr != nullptr) {
+ Py_INCREF(have_descr);
+ if (strcmp(gsp->name, "__doc__") == 0)
+ *doc_descr = have_descr;
+ else
+ assert(false);
+ if (!_fixup_getset(type, gsp->name, gsp))
+ continue;
+ }
+ AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
+ return -1;
+ // PYSIDE-535: We cannot set the attribute. For simplicity, we use
+ // get_signature in PyPy, instead. This can be re-implemented
+ // later by deriving extra heap types.
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return -1;
+ }
+ PyType_Modified(type);
+ return 0;
+}
+
+static PyObject *get_funcname(PyObject *ob)
+{
+ PyObject *func = ob;
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ func = PyObject_GetAttr(ob, PyMagicName::func());
+ else
+ Py_INCREF(func);
+ PyObject *func_name = PyObject_GetAttr(func, PyMagicName::name());
+ Py_DECREF(func);
+ if (func_name == nullptr)
+ Py_FatalError("unexpected name problem in compute_name_key");
+ return func_name;
+}
+
+static PyObject *compute_name_key(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return GetTypeKey(ob);
+ AutoDecRef func_name(get_funcname(ob));
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
+ return Py_BuildValue("(OO)", type_key.object(), func_name.object());
+}
+
+static PyObject *_func_with_new_name(PyTypeObject *type,
+ PyMethodDef *meth,
+ const char *new_name)
+{
+ /*
+ * Create a function with a lower case name.
+ * Note: This is similar to feature_select's methodWithNewName,
+ * but does not create a descriptor.
+ * XXX Maybe we can get rid of this, completely?
+ */
+ auto obtype = reinterpret_cast<PyObject *>(type);
+ int len = strlen(new_name);
+ auto name = new char[len + 1];
+ strcpy(name, new_name);
+ auto new_meth = new PyMethodDef;
+ new_meth->ml_name = name;
+ new_meth->ml_meth = meth->ml_meth;
+ new_meth->ml_flags = meth->ml_flags;
+ new_meth->ml_doc = meth->ml_doc;
+ return PyCFunction_NewEx(new_meth, obtype, nullptr);
+}
+
+static int build_name_key_to_func(PyObject *obtype)
+{
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ AutoDecRef type_key(GetTypeKey(obtype));
+ for (; meth->ml_name != nullptr; meth++) {
+ AutoDecRef func(PyCFunction_NewEx(meth, obtype, nullptr));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
+ // PYSIDE-1019: Now we repeat the same for snake case names.
+ meth = type->tp_methods;
+ for (; meth->ml_name != nullptr; meth++) {
+ const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
+ AutoDecRef func(_func_with_new_name(type, meth, name));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+PyObject *name_key_to_func(PyObject *ob)
+{
+ /*
+ * We build a mapping from name_key to function.
+ * This could also be computed directly, but the Limited API
+ * makes this impossible. So we always build our own mapping.
+ */
+ AutoDecRef name_key(compute_name_key(ob));
+ if (name_key.isNull())
+ Py_RETURN_NONE;
+
+ PyObject *ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ if (ret == nullptr) {
+ // do a lazy initialization
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
+ PyObject *type = PyDict_GetItem(pyside_globals->map_dict,
+ type_key);
+ if (type == nullptr)
+ Py_RETURN_NONE;
+ assert(PyType_Check(type));
+ if (build_name_key_to_func(type) < 0)
+ return nullptr;
+ ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ }
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *_build_new_entry(PyObject *new_name, PyObject *value)
+{
+ PyObject *new_value = PyDict_Copy(value);
+ PyObject *multi = PyDict_GetItem(value, PyName::multi());
+ if (multi != nullptr && Py_TYPE(multi) == &PyList_Type) {
+ Py_ssize_t len = PyList_Size(multi);
+ AutoDecRef list(PyList_New(len));
+ if (list.isNull())
+ return nullptr;
+ for (int idx = 0; idx < len; ++idx) {
+ auto multi_entry = PyList_GetItem(multi, idx);
+ auto dup = PyDict_Copy(multi_entry);
+ if (PyDict_SetItem(dup, PyName::name(), new_name) < 0)
+ return nullptr;
+ if (PyList_SetItem(list, idx, dup) < 0)
+ return nullptr;
+ }
+ if (PyDict_SetItem(new_value, PyName::multi(), list) < 0)
+ return nullptr;
+ } else {
+ if (PyDict_SetItem(new_value, PyName::name(), new_name) < 0)
+ return nullptr;
+ }
+ return new_value;
+}
+
+int insert_snake_case_variants(PyObject *dict)
+{
+ AutoDecRef snake_dict(PyDict_New());
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ AutoDecRef name(String::getSnakeCaseName(key, true));
+ AutoDecRef new_value(_build_new_entry(name, value));
+ if (PyDict_SetItem(snake_dict, name, new_value) < 0)
+ return -1;
+ }
+ return PyDict_Merge(dict, snake_dict, 0);
+}
+
+#ifdef PYPY_VERSION
+PyObject *_get_class_of_bm(PyObject *ob_bm)
+{
+ AutoDecRef self(PyObject_GetAttr(ob_bm, PyMagicName::self()));
+ auto *klass = PyObject_GetAttr(self, PyMagicName::class_());
+ return klass;
+}
+#endif
+
+PyObject *_get_class_of_cf(PyObject *ob_cf)
+{
+ PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
+ if (selftype == nullptr) {
+ selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf);
+ if (selftype == nullptr) {
+ // This must be an overloaded function that we handled special.
+ AutoDecRef special(Py_BuildValue("(OO)", ob_cf, PyName::overload()));
+ selftype = PyDict_GetItem(pyside_globals->map_dict, special);
+ if (selftype == nullptr) {
+ // This is probably a module function. We will return type(None).
+ selftype = Py_None;
+ }
+ }
+ }
+
+ PyObject *obtype_mod = (PyType_Check(selftype) || PyModule_Check(selftype))
+ ? selftype
+ : reinterpret_cast<PyObject *>(Py_TYPE(selftype));
+ Py_INCREF(obtype_mod);
+ return obtype_mod;
+}
+
+PyObject *_get_class_of_sm(PyObject *ob_sm)
+{
+ AutoDecRef func(PyObject_GetAttr(ob_sm, PyMagicName::func()));
+ return _get_class_of_cf(func);
+}
+
+PyObject *_get_class_of_descr(PyObject *ob)
+{
+ return PyObject_GetAttr(ob, PyMagicName::objclass());
+}
+
+PyObject *_address_to_stringlist(PyObject *numkey)
+{
+ /*
+ * This is a tiny optimization that saves initialization time.
+ * Instead of creating all Python strings during the call to
+ * `PySide_BuildSignatureArgs`, we store the address of the stringlist.
+ * When needed in `PySide_BuildSignatureProps`, the strings are
+ * finally materialized.
+ */
+ Py_ssize_t address = PyNumber_AsSsize_t(numkey, PyExc_ValueError);
+ if (address == -1 && PyErr_Occurred())
+ return nullptr;
+ char **sig_strings = reinterpret_cast<char **>(address);
+ PyObject *res_list = PyList_New(0);
+ if (res_list == nullptr)
+ return nullptr;
+ for (; *sig_strings != nullptr; ++sig_strings) {
+ char *sig_str = *sig_strings;
+ AutoDecRef pystr(Py_BuildValue("s", sig_str));
+ if (pystr.isNull() || PyList_Append(res_list, pystr) < 0)
+ return nullptr;
+ }
+ return res_list;
+}
+
+int _build_func_to_type(PyObject *obtype)
+{
+ /*
+ * There is no general way to directly get the type of a static method.
+ * On Python 3, the type is hidden in an unused pointer in the
+ * PyCFunction structure, but the Limited API does not allow to access
+ * this, either.
+ *
+ * In the end, it was easier to avoid such tricks and build an explicit
+ * mapping from function to type.
+ *
+ * We walk through the method list of the type
+ * and record the mapping from static method to this type in a dict.
+ * We also check for hidden methods, see below.
+ */
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();
+
+ // PYSIDE-2404: Get the original dict for late initialization.
+ // The dict might have been switched before signature init.
+ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
+ if (Py_TYPE(dict) != Py_TYPE(pyTypeType_tp_dict)) {
+ tpDict.reset(PyObject_GetAttr(dict, PyName::orig_dict()));
+ dict = tpDict.object();
+ }
+
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ for (; meth->ml_name != nullptr; meth++) {
+ /*
+ * It is possible that a method is overwritten by another
+ * attribute with the same name. This case was obviously provoked
+ * explicitly in "testbinding.TestObject.staticMethodDouble",
+ * where instead of the method a "PySide6.QtCore.Signal" object
+ * was in the dict.
+ * This overlap is also found in regular PySide under
+ * "PySide6.QtCore.QProcess.error" where again a signal object is
+ * returned. These hidden methods will be opened for the
+ * signature module by adding them under the name
+ * "{name}.overload".
+ */
+ PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
+ PyObject *look_attr = meth->ml_flags & METH_STATIC ? PyMagicName::func()
+ : PyMagicName::name();
+ int check_name = meth->ml_flags & METH_STATIC ? 0 : 1;
+ if (descr == nullptr)
+ return -1;
+
+ // We first check all methods if one is hidden by something else.
+ AutoDecRef look(PyObject_GetAttr(descr, look_attr));
+ AutoDecRef given(Py_BuildValue("s", meth->ml_name));
+ if (look.isNull()
+ || (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) {
+ PyErr_Clear();
+ AutoDecRef cfunc(PyCFunction_NewEx(
+ meth, reinterpret_cast<PyObject *>(type), nullptr));
+ if (cfunc.isNull())
+ return -1;
+ if (meth->ml_flags & METH_STATIC)
+ descr = PyStaticMethod_New(cfunc);
+ else
+ descr = PyDescr_NewMethod(type, meth);
+ if (descr == nullptr)
+ return -1;
+ char mangled_name[200];
+ strcpy(mangled_name, meth->ml_name);
+ strcat(mangled_name, ".overload");
+ if (PyDict_SetItemString(dict, mangled_name, descr) < 0)
+ return -1;
+ if (meth->ml_flags & METH_STATIC) {
+ // This is the special case where a static method is hidden.
+ AutoDecRef special(Py_BuildValue("(Os)", cfunc.object(), "overload"));
+ if (PyDict_SetItem(pyside_globals->map_dict, special, obtype) < 0)
+ return -1;
+ }
+ if (PyDict_SetItemString(pyside_globals->map_dict, mangled_name, obtype) < 0)
+ return -1;
+ continue;
+ }
+ // Then we insert the mapping for static methods.
+ if (meth->ml_flags & METH_STATIC) {
+ if (PyDict_SetItem(pyside_globals->map_dict, look, obtype) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature_p.h b/sources/shiboken6/libshiboken/signature_p.h
new file mode 100644
index 000000000..d0c4ee537
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature_p.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SIGNATURE_IMPL_H
+#define SIGNATURE_IMPL_H
+
+#include "signature.h"
+
+extern "C" {
+
+// signature_globals.cpp
+
+struct safe_globals_struc {
+ // init part 1: get arg_dict
+ PyObject *helper_module;
+ PyObject *arg_dict;
+ PyObject *map_dict;
+ PyObject *value_dict; // for writing signatures
+ PyObject *feature_dict; // registry for PySide.support.__feature__
+ // init part 2: run module
+ PyObject *pyside_type_init_func;
+ PyObject *create_signature_func;
+ PyObject *seterror_argument_func;
+ PyObject *make_helptext_func;
+ PyObject *finish_import_func;
+ PyObject *feature_import_func;
+ PyObject *feature_imported_func;
+};
+
+extern safe_globals_struc *pyside_globals;
+extern PyMethodDef signature_methods[];
+
+void init_shibokensupport_module(void);
+
+// signature.cpp
+
+PyObject *GetTypeKey(PyObject *ob);
+
+PyObject *GetSignature_Function(PyObject *, PyObject *);
+PyObject *GetSignature_TypeMod(PyObject *, PyObject *);
+PyObject *GetSignature_Wrapper(PyObject *, PyObject *);
+
+LIBSHIBOKEN_API PyObject *get_signature_intern(PyObject *ob, PyObject *modifier);
+PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+PyObject *GetClassOrModOf(PyObject *ob);
+
+// signature_extend.cpp
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier);
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier);
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier);
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier);
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier);
+
+int PySide_PatchTypes(void);
+PyObject *pyside_tp_get___doc__(PyObject *tp);
+
+// signature_helper.cpp
+
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr);
+PyObject *name_key_to_func(PyObject *ob);
+int insert_snake_case_variants(PyObject *dict);
+PyObject *_get_class_of_cf(PyObject *ob_cf);
+PyObject *_get_class_of_sm(PyObject *ob_sm);
+PyObject *_get_class_of_descr(PyObject *ob);
+PyObject *_address_to_stringlist(PyObject *numkey);
+int _build_func_to_type(PyObject *obtype);
+int _finish_nested_classes(PyObject *dict);
+
+#ifdef PYPY_VERSION
+// PyPy has a special builtin method.
+PyObject *GetSignature_Method(PyObject *, PyObject *);
+PyObject *pyside_bm_get___signature__(PyObject *func, PyObject *modifier);
+PyObject *_get_class_of_bm(PyObject *ob_cf);
+#endif
+
+} // extern "C"
+
+#endif // SIGNATURE_IMPL_H
diff --git a/sources/shiboken6/libshiboken/threadstatesaver.cpp b/sources/shiboken6/libshiboken/threadstatesaver.cpp
new file mode 100644
index 000000000..9f74ed442
--- /dev/null
+++ b/sources/shiboken6/libshiboken/threadstatesaver.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "threadstatesaver.h"
+
+namespace Shiboken
+{
+
+ThreadStateSaver::ThreadStateSaver() = default;
+
+ThreadStateSaver::~ThreadStateSaver()
+{
+ restore();
+}
+
+void ThreadStateSaver::save()
+{
+ if (Py_IsInitialized())
+ m_threadState = PyEval_SaveThread();
+}
+
+void ThreadStateSaver::restore()
+{
+ if (m_threadState) {
+ PyEval_RestoreThread(m_threadState);
+ m_threadState = nullptr;
+ }
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/threadstatesaver.h b/sources/shiboken6/libshiboken/threadstatesaver.h
new file mode 100644
index 000000000..4289f6726
--- /dev/null
+++ b/sources/shiboken6/libshiboken/threadstatesaver.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef THREADSTATESAVER_H
+#define THREADSTATESAVER_H
+
+#include "sbkpython.h"
+#include <shibokenmacros.h>
+
+namespace Shiboken
+{
+
+class LIBSHIBOKEN_API ThreadStateSaver
+{
+public:
+ ThreadStateSaver(const ThreadStateSaver &) = delete;
+ ThreadStateSaver(ThreadStateSaver &&) = delete;
+ ThreadStateSaver &operator=(const ThreadStateSaver &) = delete;
+ ThreadStateSaver &operator=(ThreadStateSaver &&) = delete;
+
+ ThreadStateSaver();
+ ~ThreadStateSaver();
+ void save();
+ void restore();
+private:
+ PyThreadState *m_threadState = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // THREADSTATESAVER_H
+
diff --git a/sources/shiboken6/libshiboken/voidptr.cpp b/sources/shiboken6/libshiboken/voidptr.cpp
new file mode 100644
index 000000000..8bb3f6ac8
--- /dev/null
+++ b/sources/shiboken6/libshiboken/voidptr.cpp
@@ -0,0 +1,434 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "voidptr.h"
+#include "pep384ext.h"
+#include "sbkconverter.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+
+extern "C"
+{
+
+// Void pointer object definition.
+struct SbkVoidPtrObject {
+ PyObject_HEAD
+ void *cptr;
+ Py_ssize_t size;
+ bool isWritable;
+};
+
+PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
+{
+ // PYSIDE-560: It is much safer to first call a function and then do a
+ // type cast than to do everything in one line. The bad construct looked
+ // like this, actual call forgotten:
+ // SbkVoidPtrObject *self =
+ // reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc);
+ auto *self = PepExt_TypeCallAlloc<SbkVoidPtrObject>(type, 0);
+
+ if (self != nullptr) {
+ self->cptr = nullptr;
+ self->size = -1;
+ self->isWritable = false;
+ }
+
+ return reinterpret_cast<PyObject *>(self);
+}
+
+#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtr_TypeF())
+
+
+int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *addressObject;
+ Py_ssize_t size = -1;
+ int isWritable = 0;
+ auto *sbkSelf = reinterpret_cast<SbkVoidPtrObject *>(self);
+
+ static const char *kwlist[] = {"address", "size", "writeable", nullptr};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ni", const_cast<char **>(kwlist),
+ &addressObject, &size, &isWritable))
+ return -1;
+
+ // Void pointer.
+ if (SbkVoidPtr_Check(addressObject)) {
+ auto *sbkOther = reinterpret_cast<SbkVoidPtrObject *>(addressObject);
+ sbkSelf->cptr = sbkOther->cptr;
+ sbkSelf->size = sbkOther->size;
+ sbkSelf->isWritable = sbkOther->isWritable;
+ }
+ // Python buffer interface.
+ else if (PyObject_CheckBuffer(addressObject)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(addressObject, &bufferView, PyBUF_SIMPLE) < 0)
+ return 0;
+
+ sbkSelf->cptr = bufferView.buf;
+ sbkSelf->size = bufferView.len > 0 ? bufferView.len : size;
+ sbkSelf->isWritable = bufferView.readonly <= 0;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+ }
+ // Shiboken::Object wrapper.
+ else if (Shiboken::Object::checkType(addressObject)) {
+ auto *sbkOther = reinterpret_cast<SbkObject *>(addressObject);
+ sbkSelf->cptr = sbkOther->d->cptr[0];
+ sbkSelf->size = size;
+ sbkSelf->isWritable = isWritable > 0;
+ }
+ // An integer representing an address.
+ else {
+ if (addressObject == Py_None) {
+ sbkSelf->cptr = nullptr;
+ sbkSelf->size = 0;
+ sbkSelf->isWritable = false;
+ }
+
+ else {
+ void *cptr = PyLong_AsVoidPtr(addressObject);
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError,
+ "Creating a VoidPtr object requires an address of a C++ object, "
+ "a wrapped Shiboken Object type, "
+ "an object implementing the Python Buffer interface, "
+ "or another VoidPtr object.");
+ return -1;
+ }
+ sbkSelf->cptr = cptr;
+ sbkSelf->size = size;
+ sbkSelf->isWritable = isWritable > 0;
+ }
+ }
+
+ return 0;
+}
+
+PyObject *SbkVoidPtrObject_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+ PyObject *result = Py_False;
+ void *cptr1 = nullptr;
+ void *cptr2 = nullptr;
+ bool validObjects = true;
+
+ if (SbkVoidPtr_Check(obj1))
+ cptr1 = reinterpret_cast<SbkVoidPtrObject *>(obj1)->cptr;
+ else
+ validObjects = false;
+
+ if (SbkVoidPtr_Check(obj2))
+ cptr2 = reinterpret_cast<SbkVoidPtrObject *>(obj2)->cptr;
+ else
+ validObjects = false;
+
+ if (validObjects) {
+ switch (op) {
+ case Py_EQ:
+ if (cptr1 == cptr2)
+ result = Py_True;
+ break;
+ case Py_NE:
+ if (cptr1 != cptr2)
+ result = Py_True;
+ break;
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ break;
+ }
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+PyObject *SbkVoidPtrObject_int(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ return PyLong_FromVoidPtr(sbkObject->cptr);
+}
+
+PyObject *toBytes(PyObject *self, PyObject * /* args */)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self);
+ if (sbkObject->size < 0)
+ return PyErr_Format(PyExc_IndexError, "VoidPtr does not have a size set.");
+
+ PyObject *bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char *>(sbkObject->cptr),
+ sbkObject->size);
+ Py_XINCREF(bytes);
+ return bytes;
+}
+
+static struct PyMethodDef SbkVoidPtrObject_methods[] = {
+ {"toBytes", toBytes, METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static Py_ssize_t SbkVoidPtrObject_length(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ if (sbkObject->size < 0) {
+ PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set.");
+ return -1;
+ }
+
+ return sbkObject->size;
+}
+
+static const char trueString[] = "True" ;
+static const char falseString[] = "False" ;
+
+PyObject *SbkVoidPtrObject_repr(PyObject *v)
+{
+
+
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ PyObject *s = PyUnicode_FromFormat("%s(%p, %zd, %s)",
+ Py_TYPE(sbkObject)->tp_name,
+ sbkObject->cptr,
+ sbkObject->size,
+ sbkObject->isWritable ? trueString : falseString);
+ Py_XINCREF(s);
+ return s;
+}
+
+PyObject *SbkVoidPtrObject_str(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ PyObject *s = PyUnicode_FromFormat("%s(Address %p, Size %zd, isWritable %s)",
+ Py_TYPE(sbkObject)->tp_name,
+ sbkObject->cptr,
+ sbkObject->size,
+ sbkObject->isWritable ? trueString : falseString);
+ Py_XINCREF(s);
+ return s;
+}
+
+
+static int SbkVoidPtrObject_getbuffer(PyObject *obj, Py_buffer *view, int flags)
+{
+ if (view == nullptr)
+ return -1;
+
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(obj);
+ if (sbkObject->size < 0)
+ return -1;
+
+ int readonly = sbkObject->isWritable ? 0 : 1;
+ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
+ (readonly == 1)) {
+ PyErr_SetString(PyExc_BufferError,
+ "Object is not writable.");
+ return -1;
+ }
+
+ view->obj = obj;
+ if (obj)
+ Py_XINCREF(obj);
+ view->buf = sbkObject->cptr;
+ view->len = sbkObject->size;
+ view->readonly = readonly;
+ view->itemsize = 1;
+ view->format = nullptr;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+ view->format = const_cast<char *>("B");
+ view->ndim = 1;
+ view->shape = nullptr;
+ if ((flags & PyBUF_ND) == PyBUF_ND)
+ view->shape = &(view->len);
+ view->strides = nullptr;
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
+ view->strides = &(view->itemsize);
+ view->suboffsets = nullptr;
+ view->internal = nullptr;
+ return 0;
+}
+
+static PyBufferProcs SbkVoidPtrObjectBufferProc = {
+ (getbufferproc)SbkVoidPtrObject_getbuffer, // bf_getbuffer
+ (releasebufferproc)nullptr // bf_releasebuffer
+};
+
+static PyTypeObject *createVoidPtrType()
+{
+ PyType_Slot SbkVoidPtrType_slots[] = {
+ {Py_tp_repr, reinterpret_cast<void *>(SbkVoidPtrObject_repr)},
+ {Py_nb_int, reinterpret_cast<void *>(SbkVoidPtrObject_int)},
+ {Py_sq_length, reinterpret_cast<void *>(SbkVoidPtrObject_length)},
+ {Py_tp_str, reinterpret_cast<void *>(SbkVoidPtrObject_str)},
+ {Py_tp_richcompare, reinterpret_cast<void *>(SbkVoidPtrObject_richcmp)},
+ {Py_tp_init, reinterpret_cast<void *>(SbkVoidPtrObject_init)},
+ {Py_tp_new, reinterpret_cast<void *>(SbkVoidPtrObject_new)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
+ {Py_tp_methods, reinterpret_cast<void *>(SbkVoidPtrObject_methods)},
+ {0, nullptr}
+ };
+
+ PyType_Spec SbkVoidPtrType_spec = {
+ "2:shiboken6.Shiboken.VoidPtr",
+ sizeof(SbkVoidPtrObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ SbkVoidPtrType_slots,
+ };
+
+ return SbkType_FromSpec_BMDWB(&SbkVoidPtrType_spec,
+ nullptr, nullptr, 0, 0,
+ &SbkVoidPtrObjectBufferProc);
+}
+
+PyTypeObject *SbkVoidPtr_TypeF(void)
+{
+ static auto *type = createVoidPtrType();
+ return type;
+}
+
+} // extern "C"
+
+namespace VoidPtr {
+
+static int voidPointerInitialized = false;
+
+void init()
+{
+ if (PyType_Ready(SbkVoidPtr_TypeF()) < 0)
+ Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type.");
+ else
+ voidPointerInitialized = true;
+}
+
+void addVoidPtrToModule(PyObject *module)
+{
+ if (voidPointerInitialized) {
+ Py_INCREF(SbkVoidPtr_TypeF());
+ PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtr_TypeF()),
+ reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF()));
+ }
+}
+
+static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable = false)
+{
+ if (!cppIn)
+ Py_RETURN_NONE;
+
+ SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtr_TypeF());
+ if (!result)
+ Py_RETURN_NONE;
+
+ result->cptr = cppIn;
+ result->size = size;
+ result->isWritable = isWritable;
+
+ return reinterpret_cast<PyObject *>(result);
+}
+
+static PyObject *toPython(const void *cppIn)
+{
+ return createVoidPtr(const_cast<void *>(cppIn));
+}
+
+static void VoidPtrToCpp(PyObject *pyIn, void *cppOut)
+{
+ auto *sbkIn = reinterpret_cast<SbkVoidPtrObject *>(pyIn);
+ *reinterpret_cast<void **>(cppOut) = sbkIn->cptr;
+}
+
+static PythonToCppFunc VoidPtrToCppIsConvertible(PyObject *pyIn)
+{
+ return SbkVoidPtr_Check(pyIn) ? VoidPtrToCpp : nullptr;
+}
+
+static void SbkObjectToCpp(PyObject *pyIn, void *cppOut)
+{
+ auto *sbkIn = reinterpret_cast<SbkObject *>(pyIn);
+ *reinterpret_cast<void **>(cppOut) = sbkIn->d->cptr[0];
+}
+
+static PythonToCppFunc SbkObjectToCppIsConvertible(PyObject *pyIn)
+{
+ return Shiboken::Object::checkType(pyIn) ? SbkObjectToCpp : nullptr;
+}
+
+static void PythonBufferToCpp(PyObject *pyIn, void *cppOut)
+{
+ if (PyObject_CheckBuffer(pyIn)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0)
+ return;
+
+ *reinterpret_cast<void **>(cppOut) = bufferView.buf;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+ }
+}
+
+static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn)
+{
+ if (PyObject_CheckBuffer(pyIn)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0)
+ return nullptr;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+
+ return PythonBufferToCpp;
+ }
+ return nullptr;
+}
+
+SbkConverter *createConverter()
+{
+ SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtr_TypeF(), toPython);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ VoidPtrToCpp,
+ VoidPtrToCppIsConvertible);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ SbkObjectToCpp,
+ SbkObjectToCppIsConvertible);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ PythonBufferToCpp,
+ PythonBufferToCppIsConvertible);
+ return converter;
+}
+
+void setSize(PyObject *voidPtr, Py_ssize_t size)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ voidPtrObj->size = size;
+}
+
+Py_ssize_t getSize(PyObject *voidPtr)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ return voidPtrObj->size;
+}
+
+bool isWritable(PyObject *voidPtr)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ return voidPtrObj->isWritable;
+}
+
+void setWritable(PyObject *voidPtr, bool isWritable)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ voidPtrObj->isWritable = isWritable;
+}
+
+} // namespace VoidPtr
diff --git a/sources/shiboken6/libshiboken/voidptr.h b/sources/shiboken6/libshiboken/voidptr.h
new file mode 100644
index 000000000..8360bf9c7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/voidptr.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef VOIDPTR_H
+#define VOIDPTR_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "sbkconverter.h"
+
+extern "C"
+{
+
+// Void pointer type declaration.
+extern LIBSHIBOKEN_API PyTypeObject *SbkVoidPtr_TypeF(void);
+
+} // extern "C"
+
+namespace VoidPtr
+{
+
+void init();
+SbkConverter *createConverter();
+LIBSHIBOKEN_API void addVoidPtrToModule(PyObject *module);
+
+LIBSHIBOKEN_API void setSize(PyObject *voidPtr, Py_ssize_t size);
+LIBSHIBOKEN_API Py_ssize_t getSize(PyObject *voidPtr);
+LIBSHIBOKEN_API bool isWritable(PyObject *voidPtr);
+LIBSHIBOKEN_API void setWritable(PyObject *voidPtr, bool isWritable);
+}
+
+
+#endif // VOIDPTR_H