diff options
-rw-r--r-- | cppgenerator.cpp | 113 | ||||
-rw-r--r-- | cppgenerator.h | 14 | ||||
-rw-r--r-- | headergenerator.cpp | 11 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 22 | ||||
-rw-r--r-- | libshiboken/basewrapper.h | 18 | ||||
-rw-r--r-- | libshiboken/bindingmanager.cpp | 13 | ||||
-rw-r--r-- | shibokengenerator.cpp | 46 | ||||
-rw-r--r-- | shibokengenerator.h | 9 | ||||
-rw-r--r-- | tests/libsample/multiple_derived.cpp | 37 | ||||
-rw-r--r-- | tests/libsample/multiple_derived.h | 157 | ||||
-rw-r--r-- | tests/samplebinding/CMakeLists.txt | 15 | ||||
-rwxr-xr-x | tests/samplebinding/multiple_derived_test.py | 161 | ||||
-rw-r--r-- | tests/samplebinding/typesystem_sample.xml | 15 |
13 files changed, 493 insertions, 138 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index e07dd2ada..06051dbb4 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -89,6 +89,12 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl // headers s << "// default includes" << endl; s << "#include <shiboken.h>" << endl; + + // The multiple inheritance initialization function + // needs the 'set' class from C++ STL. + if (hasMultipleInheritanceInAncestry(metaClass)) + s << "#include <set>" << endl; + s << "#include \"" << moduleName().toLower() << "_python.h\"" << endl << endl; QString converterImpl; @@ -429,7 +435,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << "* cptr;" << endl << endl; if (rfunc->ownerClass()->isAbstract()) { - s << INDENT << "if (type == &" << className << ") {" << endl; + s << INDENT << "if (type == (PyTypeObject*)&" << className << ") {" << endl; { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl; @@ -440,7 +446,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << INDENT << '}' << endl << endl; } - s << INDENT << "if (!PyType_IsSubtype(type, &" << className << "))" << endl; + s << INDENT << "if (!PyType_IsSubtype(type, (PyTypeObject*)&" << className << "))" << endl; s << INDENT << INDENT << "return 0;" << endl << endl; if (overloadData.maxArgs() > 0) { @@ -1142,6 +1148,67 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f } } +QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass* metaClass) +{ + QStringList result; + if (!metaClass->baseClassNames().isEmpty()) { + foreach (QString base, metaClass->baseClassNames()) { + result.append(QString("((size_t) static_cast<const %1*>(class_ptr)) - base").arg(base)); + result.append(QString("((size_t) static_cast<const %1*>((%2*)((void*)class_ptr))) - base").arg(base).arg(metaClass->name())); + } + foreach (const AbstractMetaClass* pClass, getBaseClasses(metaClass)) + result.append(getAncestorMultipleInheritance(pClass)); + } + return result; +} + +void CppGenerator::writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + QString className = metaClass->qualifiedCppName(); + QStringList ancestors = getAncestorMultipleInheritance(metaClass); + s << "static int mi_offsets[] = { "; + for (int i = 0; i < ancestors.size(); i++) + s << "-1, "; + s << "-1 };" << endl; + s << "int*" << endl; + s << multipleInheritanceInitializerFunctionName(metaClass) << "(const void* cptr)" << endl; + s << '{' << endl; + s << INDENT << "if (mi_offsets[0] == -1) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "std::set<int> offsets;" << endl; + s << INDENT << "std::set<int>::iterator it;" << endl; + s << INDENT << "const " << className << "* class_ptr = reinterpret_cast<const " << className << "*>(cptr);" << endl; + s << INDENT << "size_t base = (size_t) class_ptr;" << endl; + + foreach (QString ancestor, ancestors) + s << INDENT << "offsets.insert(" << ancestor << ");" << endl; + + s << endl; + s << INDENT << "offsets.erase(0);" << endl; + s << endl; + + s << INDENT << "int i = 0;" << endl; + s << INDENT << "for (it = offsets.begin(); it != offsets.end(); it++) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "mi_offsets[i] = *it;" << endl; + s << INDENT << "i++;" << endl; + } + s << INDENT << '}' << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "return mi_offsets;" << endl; + s << '}' << endl; +} + +QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass) +{ + if (!hasMultipleInheritanceInAncestry(metaClass)) + return QString(); + return QString("%1_mi_init").arg(cpythonBaseName(metaClass->typeEntry())); +} + bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass) { foreach(QString funcName, m_sequenceProtocol.keys()) { @@ -1158,6 +1225,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* QString tp_dealloc; QString tp_as_number('0'); QString tp_as_sequence('0'); + QString mi_init('0'); QString cppClassName = metaClass->qualifiedCppName(); QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), ""); QString baseClassName; @@ -1173,7 +1241,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* tp_as_sequence = QString("&Py%1_as_sequence").arg(cppClassName); if (metaClass->baseClass()) - baseClassName = QString("&") + cpythonTypeName(metaClass->baseClass()->typeEntry()); + baseClassName = QString("(PyTypeObject*)&%1").arg(cpythonTypeName(metaClass->baseClass()->typeEntry())); else baseClassName = QString("0"); @@ -1207,9 +1275,23 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* m_tpFuncs[func->name()] = cpythonFunctionName(func); } + // class or some ancestor has multiple inheritance + const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass); + if (miClass) { + mi_init = QString("(Shiboken::MultipleInheritanceInitFunction)%1") + .arg(multipleInheritanceInitializerFunctionName(miClass)); + if (metaClass == miClass) { + writeMultipleInheritanceInitializerFunction(s, metaClass); + } else { + s << "extern int* " << multipleInheritanceInitializerFunctionName(miClass); + s << "(const void* cptr);" << endl; + } + s << endl; + } + s << "// Class Definition -----------------------------------------------" << endl; - s << "PyTypeObject " << className + "_Type" << " = {" << endl; + s << "Shiboken::ShiboTypeObject " << className + "_Type" << " = { {" << endl; s << INDENT << "PyObject_HEAD_INIT(&PyType_Type)" << endl; s << INDENT << "/*ob_size*/ 0," << endl; s << INDENT << "/*tp_name*/ \"" << cppClassName << "\"," << endl; @@ -1256,7 +1338,10 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* s << INDENT << "/*tp_cache*/ 0," << endl; s << INDENT << "/*tp_subclasses*/ 0," << endl; s << INDENT << "/*tp_weaklist*/ 0" << endl; - s << "};" << endl << endl; + s << "}," << endl; + s << INDENT << "/*mi_offsets*/ 0," << endl; + s << INDENT << "/*mi_init*/ " << mi_init << endl; + s << "};" << endl; } @@ -1556,14 +1641,14 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu if (cppEnum->enclosingClass()) { addFunction = QString("PyDict_SetItemString(Py") + cppEnum->enclosingClass()->name() - + "_Type.tp_dict,"; + + "_Type.pytype.tp_dict,"; } else { addFunction = "PyModule_AddObject(module,"; } s << INDENT << "// init enum class: " << cppEnum->name() << endl; - s << INDENT << "if (PyType_Ready(&" << cpythonName << "_Type) < 0)" << endl; + s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << cpythonName << "_Type) < 0)" << endl; s << INDENT << INDENT << "return;" << endl; s << INDENT << "Py_INCREF(&" << cpythonName << "_Type);" << endl; @@ -1577,7 +1662,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu QString flagsName = cpythonFlagsName(flags); s << INDENT << "// init flags class: " << flags->name() << endl; - s << INDENT << "if (PyType_Ready(&" << flagsName << "_Type) < 0)" << endl; + s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << flagsName << "_Type) < 0)" << endl; s << INDENT << INDENT << "return;" << endl; s << INDENT << "Py_INCREF(&" << flagsName << "_Type);" << endl; @@ -1893,19 +1978,17 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // Multiple inheritance if (metaClass->baseClassNames().size() > 1) { - s << INDENT << pyTypeName << ".tp_bases = PyTuple_Pack("; + s << INDENT << pyTypeName << ".pytype.tp_bases = PyTuple_Pack("; s << metaClass->baseClassNames().size(); s << ',' << endl; QStringList bases; - foreach (QString baseName, metaClass->baseClassNames()) { - const AbstractMetaClass* base = classes().findClass(baseName); - bases << QString("&%1").arg(cpythonTypeName(base->typeEntry())); - } + foreach (const AbstractMetaClass* base, getBaseClasses(metaClass)) + bases << QString("(PyTypeObject*)&%1").arg(cpythonTypeName(base->typeEntry())); Indentation indent(INDENT); s << INDENT << bases.join(", ") << ");" << endl << endl; } - s << INDENT << "if (PyType_Ready(&" << pyTypeName << ") < 0)" << endl; + s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << pyTypeName << ") < 0)" << endl; s << INDENT << INDENT << "return;" << endl << endl; s << INDENT << "Py_INCREF(&" << pyTypeName << ");" << endl; s << INDENT << "PyModule_AddObject(module, \"" << metaClass->name() << "\"," << endl; @@ -1950,7 +2033,7 @@ void CppGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* type) s << '{' << endl; s << INDENT << "return " << "Shiboken::"; if (type->isObject() || type->isValue()) { - s << "PyBaseWrapper_New(&" << pyTypeName << ", &" << pyTypeName << ','; + s << "PyBaseWrapper_New((PyTypeObject*)&" << pyTypeName << ", &" << pyTypeName << ','; } else { // Type is enum or flag s << "PyEnumObject_New(&" << pyTypeName << ", (long)"; diff --git a/cppgenerator.h b/cppgenerator.h index 237dc68b7..a0e001f2f 100644 --- a/cppgenerator.h +++ b/cppgenerator.h @@ -127,6 +127,20 @@ private: void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, QString pyOpName, QString cppOpName, bool boolResult = false); + /// Writes the function that registers the multiple inheritance information for the classes that need it. + void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass); + + /** + * Returns the multiple inheritance initializer function for the given class. + * \param metaClass the class for whom the function name must be generated. + * \return name of the multiple inheritance information initializer function or + * an empty string if there is no multiple inheritance in its ancestry. + */ + QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass); + + /// Returns a list of all classes to which the given class could be casted. + QStringList getAncestorMultipleInheritance(const AbstractMetaClass* metaClass); + /// Returns true if the given class supports the python sequence protocol bool supportsSequenceProtocol(const AbstractMetaClass* metaClass); // Maps special function names to function parameters and return types diff --git a/headergenerator.cpp b/headergenerator.cpp index 9074726fd..a776e0c73 100644 --- a/headergenerator.cpp +++ b/headergenerator.cpp @@ -132,10 +132,15 @@ void HeaderGenerator::writeTypeCheckMacro(QTextStream& s, const TypeEntry* type) { QString pyTypeName = cpythonTypeName(type); QString checkFunction = cpythonCheckFunction(type); - s << "PyAPI_DATA(PyTypeObject) " << pyTypeName << ';' << endl; - s << "#define " << checkFunction << "(op) PyObject_TypeCheck(op, &"; + s << "PyAPI_DATA("; + if (type->isObject() || type->isValue()) + s << "Shiboken::ShiboTypeObject"; + else + s << "PyTypeObject"; + s << ") " << pyTypeName << ';' << endl; + s << "#define " << checkFunction << "(op) PyObject_TypeCheck(op, (PyTypeObject*)&"; s << pyTypeName << ')' << endl; - s << "#define " << checkFunction << "Exact(op) ((op)->ob_type == &"; + s << "#define " << checkFunction << "Exact(op) ((op)->ob_type == (PyTypeObject*)&"; s << pyTypeName << ')' << endl; } diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp index 1f58ae588..b0bb3d735 100644 --- a/libshiboken/basewrapper.cpp +++ b/libshiboken/basewrapper.cpp @@ -38,17 +38,27 @@ namespace Shiboken { PyObject* -PyBaseWrapper_New(PyTypeObject* instanceType, PyTypeObject* baseWrapperType, const void* cptr, unsigned int hasOwnership) +PyBaseWrapper_New(PyTypeObject* instanceType, ShiboTypeObject* baseWrapperType, const void* cptr, unsigned int hasOwnership) { if (!cptr) return 0; - PyObject *self = instanceType->tp_alloc(instanceType, 0); - ((Shiboken::PyBaseWrapper*)self)->baseWrapperType = baseWrapperType; - ((Shiboken::PyBaseWrapper*)self)->cptr = const_cast<void*>(cptr); - ((Shiboken::PyBaseWrapper*)self)->hasOwnership = hasOwnership; - ((Shiboken::PyBaseWrapper*)self)->validCppObject = 1; + PyObject* self = ((ShiboTypeObject*) instanceType)->pytype.tp_alloc((PyTypeObject*) instanceType, 0); + ((PyBaseWrapper*)self)->baseWrapperType = baseWrapperType; + ((PyBaseWrapper*)self)->cptr = const_cast<void*>(cptr); + ((PyBaseWrapper*)self)->hasOwnership = hasOwnership; + ((PyBaseWrapper*)self)->validCppObject = 1; + if (((ShiboTypeObject*) instanceType)->mi_init && !((ShiboTypeObject*) instanceType)->mi_offsets) + ((ShiboTypeObject*) instanceType)->mi_offsets = ((ShiboTypeObject*) instanceType)->mi_init(cptr); BindingManager::instance().assignWrapper(self, cptr); + if (((ShiboTypeObject*) instanceType)->mi_offsets) { + int* offset = ((ShiboTypeObject*) instanceType)->mi_offsets; + while (*offset != -1) { + if (*offset > 0) + BindingManager::instance().assignWrapper(self, (void*) ((size_t) cptr + (*offset))); + offset++; + } + } return self; } diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h index 67f13c11d..a98b77e39 100644 --- a/libshiboken/basewrapper.h +++ b/libshiboken/basewrapper.h @@ -44,10 +44,20 @@ namespace Shiboken extern "C" { +typedef int* (*MultipleInheritanceInitFunction)(const void*); + +// TODO: explain +struct ShiboTypeObject +{ + PyTypeObject pytype; + int* mi_offsets; + MultipleInheritanceInitFunction mi_init; +}; + struct PyBaseWrapper { PyObject_HEAD - PyTypeObject* baseWrapperType; + ShiboTypeObject* baseWrapperType; void* cptr; unsigned int hasOwnership : 1; unsigned int validCppObject : 1; @@ -55,8 +65,8 @@ struct PyBaseWrapper } // extern "C" -#define PyBaseWrapper_Check(op) PyObject_TypeCheck(op, &PyBaseWrapper_Type) -#define PyBaseWrapper_CheckExact(op) ((op)->ob_type == &PyBaseWrapper_Type) +#define PyBaseWrapper_Check(op) PyObject_TypeCheck(op, &Shiboken::PyBaseWrapper_Type) +#define PyBaseWrapper_CheckExact(op) ((op)->ob_type == &Shiboken::PyBaseWrapper_Type) #define PyBaseWrapper_cptr(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->cptr) #define PyBaseWrapper_setCptr(pyobj,c) (((Shiboken::PyBaseWrapper*)pyobj)->cptr = c) @@ -115,7 +125,7 @@ typedef struct { LIBSHIBOKEN_API PyAPI_FUNC(PyObject*) -PyBaseWrapper_New(PyTypeObject *instanceType, PyTypeObject *baseWrapperType, +PyBaseWrapper_New(PyTypeObject* instanceType, ShiboTypeObject* baseWrapperType, const void *cptr, unsigned int hasOwnership = 1); inline bool diff --git a/libshiboken/bindingmanager.cpp b/libshiboken/bindingmanager.cpp index a848e5e47..fc48348fc 100644 --- a/libshiboken/bindingmanager.cpp +++ b/libshiboken/bindingmanager.cpp @@ -85,7 +85,16 @@ void BindingManager::releaseWrapper(void *cptr) void BindingManager::releaseWrapper(PyObject* wrapper) { - releaseWrapper(PyBaseWrapper_cptr(wrapper)); + void* cptr = PyBaseWrapper_cptr(wrapper); + releaseWrapper(cptr); + if (((ShiboTypeObject*) wrapper->ob_type)->mi_offsets) { + int* offset = ((ShiboTypeObject*) wrapper->ob_type)->mi_offsets; + while (*offset != -1) { + if (*offset > 0) + BindingManager::instance().releaseWrapper((void*) ((size_t) cptr + (*offset))); + offset++; + } + } } PyObject* BindingManager::retrieveWrapper(const void* cptr) @@ -101,7 +110,7 @@ PyObject* BindingManager::getOverride(const void* cptr, const char* methodName) PyObject* wrapper = retrieveWrapper(cptr); if (wrapper) { - PyTypeObject* baseWrapperType = ((Shiboken::PyBaseWrapper*)wrapper)->baseWrapperType; + PyTypeObject* baseWrapperType = (PyTypeObject*) ((Shiboken::PyBaseWrapper*)wrapper)->baseWrapperType; PyObject* method = PyObject_GetAttrString(wrapper, const_cast<char*>(methodName)); if (method) { PyObject* defaultMethod = 0; diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp index f5d5b5046..5b6734cbf 100644 --- a/shibokengenerator.cpp +++ b/shibokengenerator.cpp @@ -850,8 +850,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, if (context) { // replace template variable for the Python Type object for the // class context in which the variable is used - QString pytype = cpythonTypeName(context); - code.replace("%PYTHONTYPEOBJECT", pytype); + code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(context) + ".pytype"); } if (func) { @@ -919,7 +918,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, // replace template variable for the Python Type object for the // class implementing the method in which the code snip is written if (func->isStatic()) { - code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(func->implementingClass())); + code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(func->implementingClass()) + ".pytype"); } else { code.replace("%PYTHONTYPEOBJECT.", QString("%1->ob_type->").arg(pySelf)); code.replace("%PYTHONTYPEOBJECT", QString("%1->ob_type").arg(pySelf)); @@ -1078,30 +1077,31 @@ bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMeta return false; } -QStringList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass) +bool ShibokenGenerator::hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass) { - QStringList baseClass; - - if (!metaClass->baseClassName().isEmpty() && - (metaClass->name() != metaClass->baseClassName())) - baseClass.append(metaClass->baseClassName()); - - foreach (AbstractMetaClass* interface, metaClass->interfaces()) { - AbstractMetaClass* aux = interface->primaryInterfaceImplementor(); - if (!aux) - continue; - - //skip templates - if (!aux->templateArguments().isEmpty()) - continue; - - if (!aux->name().isEmpty() && (metaClass->name() != aux->name())) - baseClass.append(aux->name()); - } + if (!metaClass || metaClass->baseClassNames().isEmpty()) + return false; + if (metaClass->baseClassNames().size() > 1) + return true; + return hasMultipleInheritanceInAncestry(metaClass->baseClass()); +} - return baseClass; +AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass) +{ + AbstractMetaClassList baseClasses; + foreach (QString parent, metaClass->baseClassNames()) + baseClasses << classes().findClass(parent); + return baseClasses; } +const AbstractMetaClass* ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass* metaClass) +{ + if (!metaClass || metaClass->baseClassNames().isEmpty()) + return 0; + if (metaClass->baseClassNames().size() > 1) + return metaClass; + return getMultipleInheritingClass(metaClass->baseClass()); +} QString ShibokenGenerator::getApiExportMacro() const { diff --git a/shibokengenerator.h b/shibokengenerator.h index 78a5498c2..af0b80a95 100644 --- a/shibokengenerator.h +++ b/shibokengenerator.h @@ -175,7 +175,14 @@ public: int arg_count = -1) const; bool hasInjectedCodeOrSignatureModification(const AbstractMetaFunction* func); - QStringList getBaseClasses(const AbstractMetaClass* metaClass); + + /// Returns true if there are cases of multiple inheritance in any of its ancestors. + bool hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass); + + /// Returns a list of parent classes for a method. + AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass); + + const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass); void writeBaseConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context); diff --git a/tests/libsample/multiple_derived.cpp b/tests/libsample/multiple_derived.cpp index c6ce9f8a8..e8e4c4c3d 100644 --- a/tests/libsample/multiple_derived.cpp +++ b/tests/libsample/multiple_derived.cpp @@ -34,52 +34,37 @@ #include "multiple_derived.h" -MDerived::MDerived() +MDerived1::MDerived1() : m_value(100) { } -MDerived::~MDerived() +MDerived2::MDerived2() : m_value(200) { } -const char* -MDerived::name() +MDerived3::MDerived3() : m_value(3000) { - return "MDerived"; } -// Base2 methods -const char* -MDerived::funcName() +MDerived4::MDerived4() { - return "MDerived.funcName"; } -MBase1* -MDerived::castToMBase1() +MDerived5::MDerived5() { - MBase1* ptr = (MBase1*) this; - return ptr; -} - -MBase2* -MDerived::castToMBase2() -{ - MBase2* ptr = (MBase2*) this; - return ptr; } -MDerived* -MDerived::transformFromBase1(MBase1* self) +MDerived1* +MDerived1::transformFromBase1(Base1* self) { - MDerived* ptr = dynamic_cast<MDerived*>(self); + MDerived1* ptr = dynamic_cast<MDerived1*>(self); return ptr; } -MDerived* -MDerived::transformFromBase2(MBase2* self) +MDerived1* +MDerived1::transformFromBase2(Base2* self) { - MDerived* ptr = dynamic_cast<MDerived*>(self); + MDerived1* ptr = dynamic_cast<MDerived1*>(self); return ptr; } diff --git a/tests/libsample/multiple_derived.h b/tests/libsample/multiple_derived.h index 5ddfd112d..6fd35a5da 100644 --- a/tests/libsample/multiple_derived.h +++ b/tests/libsample/multiple_derived.h @@ -37,37 +37,160 @@ #include "libsamplemacros.h" -class LIBSAMPLE_API MBase1 +class LIBSAMPLE_API Base1 { public: - ~MBase1() {} - virtual const char* name() { return "MBase"; } + Base1() : m_value(1) {} + ~Base1() {} + virtual int base1Method() { return m_value; } +private: + int m_value; }; -class LIBSAMPLE_API MBase2 +class LIBSAMPLE_API Base2 { public: - ~MBase2() {} - virtual const char* funcName() { return "MBase2.funcName"; } + Base2() : m_value(2) {} + ~Base2() {} + virtual int base2Method() { return m_value; } +private: + int m_value; }; -class LIBSAMPLE_API MDerived : public MBase1, public MBase2 +class LIBSAMPLE_API MDerived1 : public Base1, public Base2 { public: - MDerived(); - virtual ~MDerived(); + MDerived1(); + virtual ~MDerived1() {} - // MBase1 methods - const char* name(); + virtual int mderived1Method() { return m_value; } + virtual int base1Method() { return Base1::base1Method() * 10; } + virtual int base2Method() { return Base2::base2Method() * 10; } - // MBase2 methods - const char* funcName(); + Base1* castToBase1() { return (Base1*) this; } + Base2* castToBase2() { return (Base2*) this; } - MBase1* castToMBase1(); - MBase2* castToMBase2(); + static MDerived1* transformFromBase1(Base1 *self); + static MDerived1* transformFromBase2(Base2 *self); - static MDerived* transformFromBase1(MBase1 *self); - static MDerived* transformFromBase2(MBase2 *self); +private: + int m_value; }; + +class SonOfMDerived1 : public MDerived1 +{ +public: + SonOfMDerived1() : m_value(0) {} + ~SonOfMDerived1() {} + + MDerived1* castToMDerived1() { return (MDerived1*) this; } + + int sonOfMDerived1Method() { return m_value; } +private: + int m_value; +}; + +class Base3 +{ +public: + explicit Base3(int val = 3) : m_value(val) {} + ~Base3() {} + int base3Method() { return m_value; } +private: + int m_value; +}; + +class Base4 +{ +public: + Base4() : m_value(4) {} + ~Base4() {} + int base4Method() { return m_value; } +private: + int m_value; +}; + +class Base5 +{ +public: + Base5() : m_value(5) {} + ~Base5() {} + virtual int base5Method() { return m_value; } +private: + int m_value; +}; + +class Base6 +{ +public: + Base6() : m_value(6) {} + ~Base6() {} + virtual int base6Method() { return m_value; } +private: + int m_value; +}; + + +class MDerived2 : public Base3, public Base4, public Base5, public Base6 +{ +public: + MDerived2(); + virtual ~MDerived2() {} + + int base4Method() { return Base3::base3Method() * 10; } + int mderived2Method() { return m_value; } + + Base3* castToBase3() { return (Base3*) this; } + Base4* castToBase4() { return (Base4*) this; } + Base5* castToBase5() { return (Base5*) this; } + Base6* castToBase6() { return (Base6*) this; } + +private: + int m_value; +}; + +class MDerived3 : public MDerived1, public MDerived2 +{ +public: + MDerived3(); + virtual ~MDerived3() {} + + virtual int mderived3Method() { return m_value; } + + MDerived1* castToMDerived1() { return (MDerived1*) this; } + MDerived2* castToMDerived2() { return (MDerived2*) this; } + + Base3* castToBase3() { return (Base3*) this; } + +private: + int m_value; +}; + +class MDerived4 : public Base3, public Base4 +{ +public: + MDerived4(); + ~MDerived4() {} + + int mderived4Method() { return 0; } + + Base3* castToBase3() { return (Base3*) this; } + Base4* castToBase4() { return (Base4*) this; } +private: + int m_value; +}; + +class MDerived5 : public Base3, public Base4 +{ +public: + MDerived5(); + ~MDerived5() {} + + virtual int mderived5Method() { return 0; } + + Base3* castToBase3() { return (Base3*) this; } + Base4* castToBase4() { return (Base4*) this; } +}; + #endif // MDERIVED_H diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 5f1f87348..7d37950e5 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -7,6 +7,12 @@ ${CMAKE_CURRENT_SOURCE_DIR}/typesystem_sample.xml set(sample_SRC ${CMAKE_CURRENT_BINARY_DIR}/sample/abstractmodifications_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/abstract_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base5_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base6_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp @@ -20,9 +26,11 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/injectcode_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/kindergarten_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/listuser_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/mapuser_wrapper.cpp -${CMAKE_CURRENT_BINARY_DIR}/sample/mbase1_wrapper.cpp -${CMAKE_CURRENT_BINARY_DIR}/sample/mbase2_wrapper.cpp -${CMAKE_CURRENT_BINARY_DIR}/sample/mderived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived5_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/modifications_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/nondefaultctor_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/objecttype_wrapper.cpp @@ -40,6 +48,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/str_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/time_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdtor_wrapper.cpp diff --git a/tests/samplebinding/multiple_derived_test.py b/tests/samplebinding/multiple_derived_test.py index 473cf8da0..56f1fe00d 100755 --- a/tests/samplebinding/multiple_derived_test.py +++ b/tests/samplebinding/multiple_derived_test.py @@ -29,55 +29,146 @@ import sys import unittest -from sample import MBase1, MBase2, MDerived +from sample import Base1, Base2, Base3, Base4, Base5, Base6 +from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1 class MultipleDerivedTest(unittest.TestCase): '''Test cases for multiple inheritance''' def testIsInstance(self): - '''MDerived is instance of its parents MBase1 and MBase2.''' - a = MDerived() - self.assert_(isinstance(a, MDerived)) - self.assert_(isinstance(a, MBase1)) - self.assert_(isinstance(a, MBase2)) + '''MDerived1 is instance of its parents Base1 and Base2.''' + a = MDerived1() + self.assert_(isinstance(a, MDerived1)) + self.assert_(isinstance(a, Base1)) + self.assert_(isinstance(a, Base2)) def testIsSubclass(self): - '''MDerived is subclass of its parents MBase1 and MBase2.''' - self.assert_(issubclass(MDerived, MBase1)) - self.assert_(issubclass(MDerived, MBase2)) - - def testCallToFunctionWithMBase1ArgumentThatCastsBackToMDerived(self): - '''MDerived is passed as an MBase1 argument to method that returns it casted back to MDerived.''' - a = MDerived() - b = MDerived.transformFromBase1(a) + '''MDerived1 is subclass of its parents Base1 and Base2.''' + self.assert_(issubclass(MDerived1, Base1)) + self.assert_(issubclass(MDerived1, Base2)) + + def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base1 argument to a method that returns it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase1(a) self.assertEqual(a, b) - def testCallToFunctionWithMBase2ArgumentThatCastsBackToMDerived(self): - '''MDerived is passed as an MBase2 argument to method that returns it casted back to MDerived.''' - a = MDerived() - b = MDerived.transformFromBase2(a) + def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base2 argument to a method that returns it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase2(a) self.assertEqual(a, b) - def testCastFromMDerivedToMBase1(self): - '''MDerived is casted by C++ to its first parent MBase2 and the binding must return the MDerived wrapper.''' - a = MDerived() + def testCastFromMDerived1ToBases(self): + '''MDerived1 is casted by C++ to its parents and the binding must return the MDerived1 wrapper.''' + a = MDerived1() refcnt = sys.getrefcount(a) - b = a.castToMBase1() - self.assert_(isinstance(b, MDerived)) - self.assertEqual(a, b) - self.assertEqual(sys.getrefcount(a), refcnt + 1) + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assert_(isinstance(b1, MDerived1)) + self.assert_(isinstance(b2, MDerived1)) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 2) - """ - # This method must be commented since it will break the test flow until the problem is fixed. - def testCastFromMDerivedToMBase2(self): - '''MDerived is casted by C++ to its second parent MBase2 and the binding must return the MDerived wrapper.''' - a = MDerived() + def testCastFromSonOfMDerived1ToBases(self): + '''SonOfMDerived1 is casted by C++ to its parents and the binding must return the SonOfMDerived1 wrapper.''' + a = SonOfMDerived1() refcnt = sys.getrefcount(a) - b = a.castToMBase2() - self.assert_(isinstance(b, MDerived)) - self.assertEqual(a, b) - self.assertEqual(sys.getrefcount(a), refcnt + 1) - """ + md1 = a.castToMDerived1() + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assert_(isinstance(md1, SonOfMDerived1)) + self.assert_(isinstance(b2, SonOfMDerived1)) + self.assert_(isinstance(b2, SonOfMDerived1)) + self.assertEqual(a, md1) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 3) + + def testCastFromMDerived2ToBases(self): + '''MDerived2 is casted by C++ to its parents and the binding must return the MDerived2 wrapper.''' + a = MDerived2() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assert_(isinstance(b3, MDerived2)) + self.assert_(isinstance(b4, MDerived2)) + self.assert_(isinstance(b5, MDerived2)) + self.assert_(isinstance(b6, MDerived2)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 4) + + def testCastFromMDerived3ToBases(self): + '''MDerived3 is casted by C++ to its parents and the binding must return the MDerived3 wrapper.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + md1 = a.castToMDerived1() + md2 = a.castToMDerived2() + b1 = a.castToBase1() + b2 = a.castToBase2() + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assert_(isinstance(md1, MDerived3)) + self.assert_(isinstance(md2, MDerived3)) + self.assert_(isinstance(b1, MDerived3)) + self.assert_(isinstance(b2, MDerived3)) + self.assert_(isinstance(b3, MDerived3)) + self.assert_(isinstance(b4, MDerived3)) + self.assert_(isinstance(b5, MDerived3)) + self.assert_(isinstance(b6, MDerived3)) + self.assertEqual(a, md1) + self.assertEqual(a, md2) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 8) + + def testCastFromMDerived4ToBases(self): + '''MDerived4 is casted by C++ to its parents and the binding must return the MDerived4 wrapper.''' + a = MDerived4() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assert_(isinstance(b3, MDerived4)) + self.assert_(isinstance(b4, MDerived4)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromMDerived5ToBases(self): + '''MDerived5 is casted by C++ to its parents and the binding must return the MDerived5 wrapper.''' + a = MDerived5() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assert_(isinstance(b3, MDerived5)) + self.assert_(isinstance(b4, MDerived5)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + def testCastFromMDerived3ToBase3(self): + '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited and reimplement castToBase3 methods.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + b3_reimplemented = a.castToBase3() + b3_inherited = MDerived2.castToBase3(a) + self.assert_(isinstance(b3_reimplemented, MDerived3)) + self.assert_(isinstance(b3_inherited, MDerived3)) + self.assertEqual(a, b3_reimplemented) + self.assertEqual(a, b3_inherited) + self.assertEqual(sys.getrefcount(a), refcnt + 2) if __name__ == '__main__': unittest.main() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index b6ce70c5c..cfa87c23f 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -663,9 +663,18 @@ <object-type name="PrivateDtor" /> - <interface-type name="MBase1"/> - <object-type name="MBase2"/> - <object-type name="MDerived"/> + <object-type name="Base1"/> + <interface-type name="Base2"/> + <object-type name="Base3"/> + <interface-type name="Base4"/> + <interface-type name="Base5"/> + <interface-type name="Base6"/> + <object-type name="MDerived1"/> + <object-type name="MDerived2"/> + <object-type name="MDerived3"/> + <object-type name="MDerived4"/> + <object-type name="MDerived5"/> + <object-type name="SonOfMDerived1"/> <value-type name="Echo"> <add-function signature="echo(const char *)" return-type="PyObject*"> |