aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cppgenerator.cpp53
-rw-r--r--libshiboken/basewrapper.cpp30
-rw-r--r--libshiboken/basewrapper.h15
-rw-r--r--libshiboken/bindingmanager.cpp69
-rw-r--r--libshiboken/bindingmanager.h3
-rw-r--r--libshiboken/conversions.h6
-rw-r--r--tests/libother/CMakeLists.txt1
-rw-r--r--tests/libother/othermultiplederived.cpp56
-rw-r--r--tests/libother/othermultiplederived.h6
-rw-r--r--tests/libsample/multiple_derived.h5
-rw-r--r--tests/samplebinding/typediscovery_test.py13
11 files changed, 194 insertions, 63 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index 7aca126f2..49e5d5555 100644
--- a/cppgenerator.cpp
+++ b/cppgenerator.cpp
@@ -369,7 +369,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl
writeClassDefinition(s, metaClass);
s << endl;
- if (metaClass->isPolymorphic())
+ if (metaClass->isPolymorphic() && metaClass->baseClass())
writeTypeDiscoveryFunction(s, metaClass);
@@ -2217,7 +2217,6 @@ void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaCl
s << "static void* " << cpythonSpecialCastFunctionName(metaClass) << "(void* obj, SbkBaseWrapperType* desiredType)\n";
s << "{\n";
s << INDENT << className << "* me = reinterpret_cast<" << className << "*>(obj);\n";
- AbstractMetaClassList bases = getBaseClasses(metaClass);
bool firstClass = true;
foreach (const AbstractMetaClass* baseClass, getAllAncestors(metaClass)) {
s << INDENT << (!firstClass ? "else " : "") << "if (desiredType == reinterpret_cast<SbkBaseWrapperType*>(" << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n";
@@ -3277,8 +3276,8 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
if (metaClass->baseClass())
s << INDENT << pyTypeName << ".super.ht_type.tp_base = " << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ';' << endl;
// Multiple inheritance
+ const AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
if (metaClass->baseClassNames().size() > 1) {
- AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
s << INDENT << pyTypeName << ".super.ht_type.tp_bases = PyTuple_Pack(";
s << baseClasses.size();
s << ',' << endl;
@@ -3299,21 +3298,11 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
// Set typediscovery struct or fill the struct of another one
if (metaClass->isPolymorphic()) {
s << INDENT << "// Fill type discovery information" << endl;
- if (!metaClass->baseClass()) {
- s << INDENT << cpythonTypeName(metaClass) << ".type_discovery = new Shiboken::TypeDiscovery;" << endl;
- s << INDENT << cpythonTypeName(metaClass) << ".type_discovery->addTypeDiscoveryFunction(&";
- s << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl;
- } else {
- // FIXME: What about mi classes?
- AbstractMetaClass* baseClass = metaClass->baseClass();
- while (baseClass->baseClass())
- baseClass = baseClass->baseClass();
- s << INDENT << cpythonTypeName(metaClass) << ".type_discovery = " ;
- s << "reinterpret_cast<SbkBaseWrapperType*>(" << cpythonTypeNameExt(baseClass->typeEntry()) << ")->type_discovery;" << endl;
-
- if (!metaClass->typeEntry()->polymorphicIdValue().isEmpty()) {
- s << INDENT << cpythonTypeName(metaClass) << ".type_discovery->addTypeDiscoveryFunction(&";
- s << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl;
+ if (metaClass->baseClass()) {
+ s << INDENT << cpythonTypeName(metaClass) << ".type_discovery = &" << cpythonBaseName(metaClass) << "_typeDiscovery;" << endl;
+ s << INDENT << "Shiboken::BindingManager& bm = Shiboken::BindingManager::instance();" << endl;
+ foreach (const AbstractMetaClass* base, baseClasses) {
+ s << INDENT << "bm.addClassInheritance(reinterpret_cast<SbkBaseWrapperType*>(" << cpythonTypeNameExt(base->typeEntry()) << "), &" << cpythonTypeName(metaClass) << ");" << endl;
}
}
s << endl;
@@ -3389,16 +3378,8 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass)
{
QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
- bool shouldGenerateIt = !polymorphicExpr.isEmpty() || !metaClass->baseClass();
- if (!shouldGenerateIt)
- return;
s << "static SbkBaseWrapperType* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkBaseWrapperType* instanceType)\n{" << endl;
- s << INDENT << "if (instanceType->mi_specialcast)" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "cptr = instanceType->mi_specialcast(cptr, &" << cpythonTypeName(metaClass) << ");" << endl;
- }
if (!metaClass->baseClass()) {
s << INDENT << "TypeResolver* typeResolver = TypeResolver::get(typeid(*reinterpret_cast<"
@@ -3408,13 +3389,31 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta
Indentation indent(INDENT);
s << INDENT << "return reinterpret_cast<SbkBaseWrapperType*>(typeResolver->pythonType());" << endl;
}
- } else {
+ } else if (!polymorphicExpr.isEmpty()) {
polymorphicExpr = polymorphicExpr.replace("%1", " reinterpret_cast<"+metaClass->qualifiedCppName()+"*>(cptr)");
s << INDENT << " if (" << polymorphicExpr << ")" << endl;
{
Indentation indent(INDENT);
s << INDENT << "return &" << cpythonTypeName(metaClass) << ';' << endl;
}
+ } else if (metaClass->isPolymorphic()) {
+ AbstractMetaClassList ancestors = getAllAncestors(metaClass);
+ foreach (AbstractMetaClass* ancestor, ancestors) {
+ if (ancestor->baseClass())
+ continue;
+ if (ancestor->isPolymorphic()) {
+ s << INDENT << "if (instanceType == reinterpret_cast<Shiboken::SbkBaseWrapperType*>(Shiboken::SbkType<"
+ << ancestor->qualifiedCppName() << " >()) && dynamic_cast<" << metaClass->qualifiedCppName()
+ << "*>(reinterpret_cast<"<< ancestor->qualifiedCppName() << "*>(cptr)))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return &" << cpythonTypeName(metaClass) << ';' << endl;
+ } else {
+ ReportHandler::warning(metaClass->qualifiedCppName() + " inherits from a non polymorphic type ("
+ + ancestor->qualifiedCppName() + "), type discovery based on RTTI is "
+ "impossible, write a polymorphic-id-expresison for this type.");
+ }
+
+ }
}
s << INDENT << "return 0;" << endl;
s << "}\n\n";
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
index e5e6d3dc4..304080c91 100644
--- a/libshiboken/basewrapper.cpp
+++ b/libshiboken/basewrapper.cpp
@@ -264,11 +264,19 @@ void destroyParentInfo(SbkBaseWrapper* obj, bool removeFromParent)
PyObject* SbkBaseWrapper_New(SbkBaseWrapperType* instanceType,
void* cptr,
bool hasOwnership,
- bool isExactType)
+ bool isExactType, const char* typeName)
{
// Try to find the exact type of cptr.
- if (!isExactType && instanceType->type_discovery)
- instanceType = instanceType->type_discovery->getType(cptr, instanceType);
+ if (!isExactType) {
+ TypeResolver* tr = 0;
+ if (typeName) {
+ tr = TypeResolver::get(typeName);
+ if (tr)
+ instanceType = reinterpret_cast<SbkBaseWrapperType*>(tr->pythonType());
+ }
+ if (!tr)
+ instanceType = BindingManager::instance().resolveType(cptr, instanceType);
+ }
SbkBaseWrapper* self = reinterpret_cast<SbkBaseWrapper*>(SbkBaseWrapper_TpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0));
self->cptr[0] = cptr;
@@ -613,22 +621,6 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha
}
-SbkBaseWrapperType* TypeDiscovery::getType(const void* cptr, SbkBaseWrapperType* instanceType) const
-{
- TypeDiscoveryFuncList::const_reverse_iterator it = m_discoveryFunctions.rbegin();
- for (; it != m_discoveryFunctions.rend(); ++it) {
- SbkBaseWrapperType* type = (*it)(const_cast<void*>(cptr), instanceType);
- if (type)
- return type;
- }
- return instanceType;
-}
-
-void TypeDiscovery::addTypeDiscoveryFunction(Shiboken::TypeDiscoveryFunc func)
-{
- m_discoveryFunctions.push_back(func);
-}
-
class FindBaseTypeVisitor : public HierarchyVisitor
{
public:
diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
index 703c46532..e65a5b3fa 100644
--- a/libshiboken/basewrapper.h
+++ b/libshiboken/basewrapper.h
@@ -56,6 +56,7 @@ extern "C"
/// Function signature for the multiple inheritance information initializers that should be provided by classes with multiple inheritance.
typedef int* (*MultipleInheritanceInitFunction)(const void*);
struct SbkBaseWrapperType;
+
/**
* Special cast function is used to correctly cast an object when it's
* part of a multiple inheritance hierarchy.
@@ -64,7 +65,6 @@ struct SbkBaseWrapperType;
typedef void* (*SpecialCastFunction)(void*, SbkBaseWrapperType*);
typedef void* (*ObjectCopierFunction)(const void*);
typedef SbkBaseWrapperType* (*TypeDiscoveryFunc)(void*, SbkBaseWrapperType*);
-typedef std::list<TypeDiscoveryFunc> TypeDiscoveryFuncList;
typedef void* (*ExtendedToCppFunc)(PyObject*);
typedef bool (*ExtendedIsConvertibleFunc)(PyObject*);
@@ -75,14 +75,6 @@ typedef void (*DeleteUserDataFunc)(void*);
extern LIBSHIBOKEN_API PyTypeObject SbkBaseWrapperType_Type;
extern LIBSHIBOKEN_API SbkBaseWrapperType SbkBaseWrapper_Type;
-class LIBSHIBOKEN_API TypeDiscovery {
-public:
- SbkBaseWrapperType* getType(const void* cptr, SbkBaseWrapperType* instanceType) const;
- void addTypeDiscoveryFunction(TypeDiscoveryFunc func);
-private:
- TypeDiscoveryFuncList m_discoveryFunctions;
-};
-
/// PyTypeObject extended with C++ multiple inheritance information.
struct LIBSHIBOKEN_API SbkBaseWrapperType
{
@@ -91,7 +83,7 @@ struct LIBSHIBOKEN_API SbkBaseWrapperType
MultipleInheritanceInitFunction mi_init;
/// Special cast function, null if this class doesn't have multiple inheritance.
SpecialCastFunction mi_specialcast;
- TypeDiscovery* type_discovery;
+ TypeDiscoveryFunc type_discovery;
ObjectCopierFunction obj_copier;
/// Extended "isConvertible" function to be used when a conversion operator is defined in another module.
ExtendedIsConvertibleFunc ext_isconvertible;
@@ -221,7 +213,8 @@ LIBSHIBOKEN_API PyObject*
SbkBaseWrapper_New(SbkBaseWrapperType* instanceType,
void* cptr,
bool hasOwnership = true,
- bool isExactType = false);
+ bool isExactType = false,
+ const char* typeName = 0);
LIBSHIBOKEN_API PyObject*
SbkBaseWrapper_TpNew(PyTypeObject* subtype, PyObject*, PyObject*);
diff --git a/libshiboken/bindingmanager.cpp b/libshiboken/bindingmanager.cpp
index 7bd402725..33e9f3ad6 100644
--- a/libshiboken/bindingmanager.cpp
+++ b/libshiboken/bindingmanager.cpp
@@ -33,16 +33,71 @@
*/
#include "basewrapper.h"
+#include <cstddef>
+#include <fstream>
#include "basewrapper_p.h"
#include "bindingmanager.h"
#include "google/dense_hash_map"
-#include <cstddef>
+#include "sbkdbg.h"
namespace Shiboken
{
typedef google::dense_hash_map<const void*, PyObject*> WrapperMap;
+class Graph
+{
+public:
+ typedef std::list<SbkBaseWrapperType*> NodeList;
+ typedef google::dense_hash_map<SbkBaseWrapperType*, NodeList> Edges;
+
+ Edges m_edges;
+
+ Graph()
+ {
+ m_edges.set_empty_key(0);
+ }
+
+ void addEdge(SbkBaseWrapperType* from, SbkBaseWrapperType* to)
+ {
+ m_edges[from].push_back(to);
+ }
+
+#ifndef NDEBUG
+ void dumpDotGraph()
+ {
+ std::ofstream file("/tmp/shiboken_graph.dot");
+
+ file << "digraph D {\n";
+
+ Edges::const_iterator i = m_edges.begin();
+ for (; i != m_edges.end(); ++i) {
+ SbkBaseWrapperType* node1 = i->first;
+ const NodeList& nodeList = i->second;
+ NodeList::const_iterator j = nodeList.begin();
+ for (; j != nodeList.end(); ++j)
+ file << '"' << (*j)->super.ht_type.tp_name << "\" -> \"" << node1->super.ht_type.tp_name << "\"\n";
+ }
+ file << "}\n";
+ }
+#endif
+
+ SbkBaseWrapperType* identifyType(void* cptr, SbkBaseWrapperType* type, SbkBaseWrapperType* baseType) const
+ {
+ Edges::const_iterator edgesIt = m_edges.find(type);
+ if (edgesIt != m_edges.end()) {
+ const NodeList& adjNodes = m_edges.find(type)->second;
+ NodeList::const_iterator i = adjNodes.begin();
+ for (; i != adjNodes.end(); ++i) {
+ SbkBaseWrapperType* newType = identifyType(cptr, *i, baseType);
+ if (newType)
+ return newType;
+ }
+ }
+ return type->type_discovery ? type->type_discovery(cptr, baseType) : 0;
+ }
+};
+
#ifndef NDEBUG
static void showWrapperMap(const WrapperMap& wrapperMap)
@@ -58,6 +113,7 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
struct BindingManager::BindingManagerPrivate {
WrapperMap wrapperMapper;
+ Graph classHierarchy;
void releaseWrapper(void* cptr);
void assignWrapper(PyObject* wrapper, const void* cptr);
};
@@ -230,5 +286,16 @@ void BindingManager::transferOwnershipToCpp(SbkBaseWrapper* wrapper)
invalidateWrapper(wrapper);
}
+void BindingManager::addClassInheritance(Shiboken::SbkBaseWrapperType* parent, Shiboken::SbkBaseWrapperType* child)
+{
+ m_d->classHierarchy.addEdge(parent, child);
+}
+
+SbkBaseWrapperType* BindingManager::resolveType(void* cptr, Shiboken::SbkBaseWrapperType* type)
+{
+ SbkBaseWrapperType* identifiedType = m_d->classHierarchy.identifyType(cptr, type, type);
+ return identifiedType ? identifiedType : type;
+}
+
} // namespace Shiboken
diff --git a/libshiboken/bindingmanager.h b/libshiboken/bindingmanager.h
index 150baa90a..dd18dcdc1 100644
--- a/libshiboken/bindingmanager.h
+++ b/libshiboken/bindingmanager.h
@@ -42,6 +42,7 @@ namespace Shiboken
{
struct SbkBaseWrapper;
+struct SbkBaseWrapperType;
class LIBSHIBOKEN_API BindingManager
{
@@ -73,6 +74,8 @@ public:
transferOwnershipToCpp(reinterpret_cast<SbkBaseWrapper*>(wrapper));
}
+ void addClassInheritance(SbkBaseWrapperType* parent, SbkBaseWrapperType* child);
+ SbkBaseWrapperType* resolveType(void* cptr, SbkBaseWrapperType* type);
private:
~BindingManager();
// disable copy
diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h
index 6247c55d8..8caa56c84 100644
--- a/libshiboken/conversions.h
+++ b/libshiboken/conversions.h
@@ -38,6 +38,7 @@
#include <Python.h>
#include <limits>
#include <memory>
+#include <typeinfo>
#include "pyenum.h"
#include "basewrapper.h"
@@ -119,8 +120,11 @@ struct CppObjectCopier<T, true>
template<typename T>
inline PyObject* createWrapper(const T* cppobj, bool hasOwnership = false, bool isExactType = false)
{
+ const char* typeName = 0;
+ if (!isExactType)
+ typeName = typeid(*const_cast<T*>(cppobj)).name();
return SbkBaseWrapper_New(reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()),
- const_cast<T*>(cppobj), hasOwnership, isExactType);
+ const_cast<T*>(cppobj), hasOwnership, isExactType, typeName);
}
// Base Conversions ----------------------------------------------------------
diff --git a/tests/libother/CMakeLists.txt b/tests/libother/CMakeLists.txt
index 96ab6cab5..9b3cf5552 100644
--- a/tests/libother/CMakeLists.txt
+++ b/tests/libother/CMakeLists.txt
@@ -4,6 +4,7 @@ set(libother_SRC
number.cpp
otherderived.cpp
otherobjecttype.cpp
+othermultiplederived.cpp
)
add_definitions("-DLIBOTHER_BUILD")
diff --git a/tests/libother/othermultiplederived.cpp b/tests/libother/othermultiplederived.cpp
new file mode 100644
index 000000000..fadaa02b8
--- /dev/null
+++ b/tests/libother/othermultiplederived.cpp
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Shiboken Python Binding Generator project.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation. Please
+ * review the following information to ensure the GNU Lesser General
+ * Public License version 2.1 requirements will be met:
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * As a special exception to the GNU Lesser General Public License
+ * version 2.1, the object code form of a "work that uses the Library"
+ * may incorporate material from a header file that is part of the
+ * Library. You may distribute such object code under terms of your
+ * choice, provided that the incorporated material (i) does not exceed
+ * more than 5% of the total size of the Library; and (ii) is limited to
+ * numerical parameters, data structure layouts, accessors, macros,
+ * inline functions and templates.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "othermultiplederived.h"
+
+VirtualMethods OtherMultipleDerived::returnUselessClass()
+{
+ return VirtualMethods();
+}
+
+Base1* OtherMultipleDerived::createObject(const std::string& objName)
+{
+ if (objName == "Base1")
+ return new Base1;
+ else if (objName == "MDerived1")
+ return new MDerived1;
+ else if (objName == "SonOfMDerived1")
+ return new SonOfMDerived1;
+ else if (objName == "MDerived3")
+ return new MDerived3;
+ else if (objName == "OtherMultipleDerived")
+ return new OtherMultipleDerived;
+ return 0;
+}
+
diff --git a/tests/libother/othermultiplederived.h b/tests/libother/othermultiplederived.h
index cefc72561..33260b6ec 100644
--- a/tests/libother/othermultiplederived.h
+++ b/tests/libother/othermultiplederived.h
@@ -37,14 +37,16 @@
#include "libothermacros.h"
#include "multiple_derived.h"
+#include "virtualmethods.h"
class ObjectType;
-class OtherMultipleDerived : public MDerived1
+class LIBOTHER_API OtherMultipleDerived : public MDerived1
{
public:
// this will use CppCopier from other module (bug#142)
- inline VirtualMethods returnUselessClass() { return VirtualMethods(); }
+ VirtualMethods returnUselessClass();
+ static Base1* createObject(const std::string& objName);
};
#endif
diff --git a/tests/libsample/multiple_derived.h b/tests/libsample/multiple_derived.h
index ffbe5feb4..98ccb4de8 100644
--- a/tests/libsample/multiple_derived.h
+++ b/tests/libsample/multiple_derived.h
@@ -36,6 +36,7 @@
#define MDERIVED_H
#include "libsamplemacros.h"
+#include <string>
class Base1
{
@@ -97,7 +98,7 @@ class Base3
{
public:
explicit Base3(int val = 3) : m_value(val) {}
- ~Base3() {}
+ virtual ~Base3() {}
int base3Method() { return m_value; }
private:
int m_value;
@@ -107,7 +108,7 @@ class Base4
{
public:
Base4() : m_value(4) {}
- ~Base4() {}
+ virtual ~Base4() {}
int base4Method() { return m_value; }
private:
int m_value;
diff --git a/tests/samplebinding/typediscovery_test.py b/tests/samplebinding/typediscovery_test.py
index 3c1bfdb98..f7d5433ce 100644
--- a/tests/samplebinding/typediscovery_test.py
+++ b/tests/samplebinding/typediscovery_test.py
@@ -29,6 +29,7 @@
import unittest
from sample import *
+from other import *
class TypeDiscoveryTest(unittest.TestCase):
@@ -42,6 +43,18 @@ class TypeDiscoveryTest(unittest.TestCase):
a = Derived.triggerAnotherImpossibleTypeDiscovery()
self.assertEqual(type(a), Derived)
+ def testMultipleInheritance(self):
+ obj = OtherMultipleDerived.createObject("Base1");
+ self.assertEqual(type(obj), Base1)
+ obj = OtherMultipleDerived.createObject("MDerived1");
+ self.assertEqual(type(obj), MDerived1)
+ obj = OtherMultipleDerived.createObject("SonOfMDerived1");
+ self.assertEqual(type(obj), SonOfMDerived1)
+ obj = OtherMultipleDerived.createObject("MDerived3");
+ self.assertEqual(type(obj), MDerived3)
+ obj = OtherMultipleDerived.createObject("OtherMultipleDerived");
+ self.assertEqual(type(obj), OtherMultipleDerived)
+
if __name__ == '__main__':
unittest.main()