aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/shiboken6/doc/shibokenmodule.rst9
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp107
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.h3
-rw-r--r--sources/shiboken6/shibokenmodule/shibokenmodule.cpp9
-rw-r--r--sources/shiboken6/shibokenmodule/typesystem_shiboken.xml8
5 files changed, 102 insertions, 34 deletions
diff --git a/sources/shiboken6/doc/shibokenmodule.rst b/sources/shiboken6/doc/shibokenmodule.rst
index b31efbcd1..2f1c6d166 100644
--- a/sources/shiboken6/doc/shibokenmodule.rst
+++ b/sources/shiboken6/doc/shibokenmodule.rst
@@ -116,6 +116,15 @@ To import the module:
This method should be used **only** for debug purposes by developers.
+ .. function:: dumpTypeGraph(file_name)
+
+ Dumps the inheritance graph of the types existing in libshiboken
+ to ``.dot`` file for use with `Graphviz <https://graphviz.org/>`_.
+
+.. function:: dumpWrapperMap()
+
+ Dumps the map of wrappers existing in libshiboken to standard error.
+
.. py:class:: VoidPtr(address, size = -1, writeable = 0)
:param address: (PyBuffer, SbkObject, int, VoidPtr)
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index a0acc4e4b..7542e60b8 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -15,8 +15,11 @@
#include <cstddef>
#include <cstring>
#include <fstream>
+#include <iostream>
#include <mutex>
+#include <string_view>
#include <unordered_map>
+#include <unordered_set>
namespace Shiboken
{
@@ -27,6 +30,8 @@ class Graph
{
public:
using NodeList = std::vector<PyTypeObject *>;
+ using NodeSet = std::unordered_set<const PyTypeObject *>;
+
using Edges = std::unordered_map<PyTypeObject *, NodeList>;
Edges m_edges;
@@ -38,25 +43,8 @@ public:
m_edges[from].push_back(to);
}
-#ifndef NDEBUG
- void dumpDotGraph() const
- {
- std::ofstream file("/tmp/shiboken_graph.dot");
-
- file << "digraph D {\n";
-
- for (const auto &p : m_edges) {
- auto *node1 = p.first;
- const NodeList &nodeList = p.second;
- for (const PyTypeObject *o : nodeList) {
- auto *node2 = o;
- file << '"' << node2->tp_name << "\" -> \""
- << node1->tp_name << "\"\n";
- }
- }
- file << "}\n";
- }
-#endif
+ bool dumpTypeGraph(const char *fileName) const;
+ NodeSet nodeSet() const;
PyTypeObject *identifyType(void **cptr, PyTypeObject *type, PyTypeObject *baseType) const
{
@@ -85,24 +73,53 @@ public:
}
};
+static void formatDotNode(const char *nameC, std::ostream &file)
+{
+ std::string_view name(nameC);
+ 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";
+}
-#ifndef NDEBUG
-static void showWrapperMap(const WrapperMap &wrapperMap)
+Graph::NodeSet Graph::nodeSet() const
{
- if (Shiboken::pyVerbose() > 0) {
- fprintf(stderr, "-------------------------------\n");
- fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size());
- for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
- const SbkObject *sbkObj = it->second;
- fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first,
- static_cast<const void *>(sbkObj),
- (Py_TYPE(sbkObj))->tp_name,
- int(Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj))));
- }
- fprintf(stderr, "-------------------------------\n");
+ NodeSet result;
+ for (const auto &p : m_edges) {
+ result.insert(p.first);
+ for (const PyTypeObject *node2 : p.second)
+ result.insert(node2);
}
+ return result;
+}
+
+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->tp_name, file);
+
+ // Write edges
+ for (const auto &p : m_edges) {
+ auto *node1 = p.first;
+ const NodeList &nodeList = p.second;
+ for (const PyTypeObject *node2 : nodeList)
+ file << " \"" << node2->tp_name << "\" -> \"" << node1->tp_name << "\"\n";
+ }
+ file << "}\n";
+ return true;
}
-#endif
struct BindingManager::BindingManagerPrivate {
using DestructorEntries = std::vector<DestructorEntry>;
@@ -189,7 +206,8 @@ BindingManager::~BindingManager()
debugRemoveFreeHook();
#endif
#ifndef NDEBUG
- showWrapperMap(m_d->wrapperMapper);
+ if (Shiboken::pyVerbose() > 0)
+ dumpWrapperMap();
#endif
/* Cleanup hanging references. We just invalidate them as when
* the BindingManager is being destroyed the interpreter is alredy
@@ -395,6 +413,27 @@ void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *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.
diff --git a/sources/shiboken6/libshiboken/bindingmanager.h b/sources/shiboken6/libshiboken/bindingmanager.h
index 4b21ae835..47db14975 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.h
+++ b/sources/shiboken6/libshiboken/bindingmanager.h
@@ -59,6 +59,9 @@ public:
*/
void visitAllPyObjects(ObjectVisitor visitor, void *data);
+ bool dumpTypeGraph(const char *fileName) const;
+ void dumpWrapperMap();
+
private:
~BindingManager();
BindingManager();
diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
index 6feca9ea8..b3adfe78b 100644
--- a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
+++ b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
@@ -91,6 +91,15 @@ for (auto *o : setAll) {
return listAll;
// @snippet getallvalidwrappers
+// @snippet dumptypegraph
+const bool ok = Shiboken::BindingManager::instance().dumpTypeGraph(%1);
+%PYARG_0 = %CONVERTTOPYTHON[bool](ok);
+// @snippet dumptypegraph
+
+// @snippet dumpwrappermap
+Shiboken::BindingManager::instance().dumpWrapperMap();
+// @snippet dumpwrappermap
+
// @snippet init
// Add __version__ and __version_info__ attributes to the module
PyObject* version = PyTuple_New(5);
diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
index 2288ca7a4..aa08a8bbf 100644
--- a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
+++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
@@ -49,6 +49,14 @@
<inject-code file="shibokenmodule.cpp" snippet="getallvalidwrappers"/>
</add-function>
+ <add-function signature="dumpTypeGraph(const char *@fileName@)" return-type="bool">
+ <inject-code file="shibokenmodule.cpp" snippet="dumptypegraph"/>
+ </add-function>
+
+ <add-function signature="dumpWrapperMap()">
+ <inject-code file="shibokenmodule.cpp" snippet="dumpwrappermap"/>
+ </add-function>
+
<extra-includes>
<include file-name="sbkversion.h" location="local"/>
<include file-name="voidptr.h" location="local"/>