diff options
-rw-r--r-- | cppgenerator.cpp | 53 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 30 | ||||
-rw-r--r-- | libshiboken/basewrapper.h | 15 | ||||
-rw-r--r-- | libshiboken/bindingmanager.cpp | 69 | ||||
-rw-r--r-- | libshiboken/bindingmanager.h | 3 | ||||
-rw-r--r-- | libshiboken/conversions.h | 6 | ||||
-rw-r--r-- | tests/libother/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/libother/othermultiplederived.cpp | 56 | ||||
-rw-r--r-- | tests/libother/othermultiplederived.h | 6 | ||||
-rw-r--r-- | tests/libsample/multiple_derived.h | 5 | ||||
-rw-r--r-- | tests/samplebinding/typediscovery_test.py | 13 |
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() |