From 47d4a1f545eb7f348e46d39230a73a1b465e57a4 Mon Sep 17 00:00:00 2001 From: Marcelo Lira Date: Mon, 31 May 2010 15:25:12 -0300 Subject: Generator improved to handle protected enums without the protected hack. --- cppgenerator.cpp | 93 +++++++++++++++++++++++++------ headergenerator.cpp | 43 +++++++++++--- shibokengenerator.cpp | 27 ++++++++- shibokengenerator.h | 2 + tests/libsample/protected.h | 6 ++ tests/samplebinding/protected_test.py | 36 ++++++++++-- tests/samplebinding/typesystem_sample.xml | 2 +- 7 files changed, 177 insertions(+), 32 deletions(-) diff --git a/cppgenerator.cpp b/cppgenerator.cpp index 2d30be2c6..e2351094d 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -477,15 +477,22 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu Indentation indentation(INDENT); ac << INDENT; - if (convert && !hasConversionRule) { + if (convert && !hasConversionRule) writeToPythonConversion(ac, arg->type(), func->ownerClass()); - ac << '('; - } - if (hasConversionRule) + if (hasConversionRule) { ac << arg->argumentName() << "_out"; - else - ac << arg->argumentName() << (convert ? ")" : ""); + } else { + QString argName = arg->argumentName(); +#ifdef AVOID_PROTECTED_HACK + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type()); + if (metaEnum && metaEnum->isProtected()) { + argName.prepend(protectedEnumSurrogateName(metaEnum) + '('); + argName.append(')'); + } +#endif + ac << (convert ? "(" : "") << argName << (convert ? ")" : ""); + } argConversions << argConv; } @@ -530,10 +537,17 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu if (func->typeReplaced(0).isEmpty()) { s << cpythonCheckFunction(func->type()); // SbkType would return null when the type is a container. - if (func->type()->typeEntry()->isContainer()) + if (func->type()->typeEntry()->isContainer()) { desiredType = '"' + reinterpret_cast(func->type()->typeEntry())->typeName() + '"'; - else - desiredType = "SbkType<" + func->type()->cppSignature() + " >()->tp_name"; + } else { + QString typeName = func->type()->cppSignature(); +#ifdef AVOID_PROTECTED_HACK + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum && metaEnum->isProtected()) + typeName = protectedEnumSurrogateName(metaEnum); +#endif + desiredType = "SbkType<" + typeName + " >()->tp_name"; + } } else { s << guessCPythonCheckFunction(func->typeReplaced(0)); desiredType = '"' + func->typeReplaced(0) + '"'; @@ -561,8 +575,28 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu writeCodeSnips(s, convRule, CodeSnip::Any, TypeSystem::NativeCode, func); } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) { s << INDENT; - s << translateTypeForWrapperMethod(func->type(), func->implementingClass()) << " " CPP_RETURN_VAR "("; +#ifdef AVOID_PROTECTED_HACK + QString enumName; + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + bool isProtectedEnum = metaEnum && metaEnum->isProtected(); + if (isProtectedEnum) { + enumName = metaEnum->name(); + if (metaEnum->enclosingClass()) + enumName = metaEnum->enclosingClass()->qualifiedCppName() + "::" + enumName; + s << enumName; + } else +#endif + s << translateTypeForWrapperMethod(func->type(), func->implementingClass()); + s << " " CPP_RETURN_VAR "("; +#ifdef AVOID_PROTECTED_HACK + if (isProtectedEnum) + s << enumName << '('; +#endif writeToCppConversion(s, func->type(), func->implementingClass(), PYTHON_RETURN_VAR); +#ifdef AVOID_PROTECTED_HACK + if (isProtectedEnum) + s << ')'; +#endif s << ')'; s << ';' << endl; } @@ -1601,10 +1635,25 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f if (func->allowThread()) s << INDENT << THREAD_STATE_SAVER_VAR ".save();" << endl; s << INDENT; - if (isCtor) + if (isCtor) { s << "cptr = "; - else if (func->type() && !func->isInplaceOperator()) - s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = "; + } else if (func->type() && !func->isInplaceOperator()) { +#ifdef AVOID_PROTECTED_HACK + QString enumName; + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum) { + if (metaEnum->isProtected()) + enumName = protectedEnumSurrogateName(metaEnum); + else + enumName = func->type()->cppSignature(); + methodCall.prepend(enumName + '('); + methodCall.append(')'); + s << enumName; + } else +#endif + s << func->type()->cppSignature(); + s << " " CPP_RETURN_VAR " = "; + } s << methodCall << ';' << endl; if (func->allowThread()) s << INDENT << THREAD_STATE_SAVER_VAR ".restore();" << endl; @@ -2394,10 +2443,20 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu s << cpythonName << "_Type," << endl; { Indentation indent(INDENT); - s << INDENT << "(long) "; - if (cppEnum->enclosingClass()) - s << cppEnum->enclosingClass()->qualifiedCppName() << "::"; - s << enumValue->name() << ", \"" << enumValue->name() << "\");" << endl; + s << INDENT; +#ifdef AVOID_PROTECTED_HACK + if (!cppEnum->isProtected()) { +#endif + s << "(long) "; + if (cppEnum->enclosingClass()) + s << cppEnum->enclosingClass()->qualifiedCppName() << "::"; + s << enumValue->name(); +#ifdef AVOID_PROTECTED_HACK + } else { + s << enumValue->value(); + } +#endif + s << ", \"" << enumValue->name() << "\");" << endl; } s << INDENT << addFunction << endl; diff --git a/headergenerator.cpp b/headergenerator.cpp index 3310227f3..ca6b5dafe 100644 --- a/headergenerator.cpp +++ b/headergenerator.cpp @@ -120,9 +120,22 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* #ifdef AVOID_PROTECTED_HACK if (func->isProtected() && !func->isConstructor()) { s << INDENT << "inline " << (func->isStatic() ? "static " : ""); - s << functionSignature(func, "", "_protected") << " { "; + s << functionSignature(func, "", "_protected", Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { "; s << (func->type() ? "return " : "") << func->ownerClass()->qualifiedCppName() << "::"; - writeFunctionCall(s, func); + s << func->originalName() << '('; + QStringList args; + foreach (const AbstractMetaArgument* arg, func->arguments()) { + QString argName = arg->argumentName(); + const TypeEntry* enumTypeEntry = 0; + if (arg->type()->isFlags()) + enumTypeEntry = reinterpret_cast(arg->type()->typeEntry())->originator(); + else if (arg->type()->isEnum()) + enumTypeEntry = arg->type()->typeEntry(); + if (enumTypeEntry) + argName = QString("%1(%2)").arg(arg->type()->cppSignature()).arg(argName); + args << argName; + } + s << args.join(", ") << ')'; s << "; }" << endl; } #endif @@ -169,6 +182,15 @@ void HeaderGenerator::writeTypeConverterDecl(QTextStream& s, const TypeEntry* ty bool isValueTypeWithImplConversions = type->isValue() && !implicitConvs.isEmpty(); bool hasCustomConversion = type->hasConversionRule(); QString typeT = type->name() + (isAbstractOrObjectType ? "*" : ""); + QString typeName = type->name(); + +#ifdef AVOID_PROTECTED_HACK + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); + if (metaEnum && metaEnum->isProtected()) { + typeT = protectedEnumSurrogateName(metaEnum); + typeName = typeT; + } +#endif s << "struct Converter<" << typeT << " >"; if (!hasCustomConversion) { @@ -178,7 +200,7 @@ void HeaderGenerator::writeTypeConverterDecl(QTextStream& s, const TypeEntry* ty s << " : ObjectTypeConverter"; else s << " : ValueTypeConverter"; - s << '<' << type->name() << " >"; + s << '<' << typeName << " >"; } s << endl << '{' << endl; if (isValueTypeWithImplConversions || hasCustomConversion) { @@ -398,11 +420,18 @@ void HeaderGenerator::writeExportMacros(QTextStream& s) void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum) { - QString enumPrefix; + QString enumName = cppEnum->name(); if (cppEnum->enclosingClass()) - enumPrefix = cppEnum->enclosingClass()->qualifiedCppName() + "::"; - s << "template<> inline PyTypeObject* SbkType<" << enumPrefix << cppEnum->name() << " >() " - << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n"; + enumName = cppEnum->enclosingClass()->qualifiedCppName() + "::" + enumName; +#ifdef AVOID_PROTECTED_HACK + if (cppEnum->isProtected()) { + enumName = protectedEnumSurrogateName(cppEnum); + s << "enum " << enumName << " {};" << endl; + } +#endif + + s << "template<> inline PyTypeObject* SbkType<" << enumName << " >() "; + s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n"; FlagsTypeEntry* flag = cppEnum->typeEntry()->flags(); if (flag) { diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp index 64976d3dd..5b85ef43a 100644 --- a/shibokengenerator.cpp +++ b/shibokengenerator.cpp @@ -157,10 +157,19 @@ QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* { QString result; - if (cType->isArray()) + if (cType->isArray()) { result = translateTypeForWrapperMethod(cType->arrayElementType(), context) + "[]"; - else - result = translateType(cType, context); + } else { +#ifdef AVOID_PROTECTED_HACK + if (cType->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(cType); + if (metaEnum && metaEnum->isProtected()) + result = protectedEnumSurrogateName(metaEnum); + } + if (result.isEmpty()) +#endif + result = translateType(cType, context); + } return result; } @@ -188,6 +197,11 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) } } +QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum) +{ + return metaEnum->fullName().replace(".", "_") + "_Surrogate"; +} + QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func) { QString result; @@ -299,6 +313,13 @@ void ShibokenGenerator::writeBaseConversion(QTextStream& s, const TypeEntry* typ QString typeName = type->name(); if (type->isObject()) typeName.append('*'); +#ifdef AVOID_PROTECTED_HACK + if (type->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); + if (metaEnum && metaEnum->isProtected()) + typeName = protectedEnumSurrogateName(metaEnum); + } +#endif s << baseConversionString(typeName); } diff --git a/shibokengenerator.h b/shibokengenerator.h index e1dadc867..bb1dcae50 100644 --- a/shibokengenerator.h +++ b/shibokengenerator.h @@ -213,6 +213,8 @@ public: static QString wrapperName(const AbstractMetaClass* metaClass); + static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum); + static QString pythonPrimitiveTypeName(const QString& cppTypeName); static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type); diff --git a/tests/libsample/protected.h b/tests/libsample/protected.h index abbbf2930..d8d55a40f 100644 --- a/tests/libsample/protected.h +++ b/tests/libsample/protected.h @@ -111,6 +111,10 @@ class LIBSAMPLE_API ProtectedEnumClass public: ProtectedEnumClass() {} virtual ~ProtectedEnumClass() {} + enum PublicEnum { + PublicItem0, + PublicItem1 + }; protected: enum ProtectedEnum { ProtectedItem0, @@ -118,6 +122,8 @@ protected: }; ProtectedEnum callProtectedEnumMethod(ProtectedEnum in) { return protectedEnumMethod(in); } virtual ProtectedEnum protectedEnumMethod(ProtectedEnum in) { return in; } + PublicEnum callPublicEnumMethod(PublicEnum in) { return publicEnumMethod(in); } + virtual PublicEnum publicEnumMethod(PublicEnum in) { return in; } }; #endif // PROTECTED_H diff --git a/tests/samplebinding/protected_test.py b/tests/samplebinding/protected_test.py index 6a5f732c9..efb0bedbf 100755 --- a/tests/samplebinding/protected_test.py +++ b/tests/samplebinding/protected_test.py @@ -185,12 +185,16 @@ class ExtendedProtectedEnumClass(ProtectedEnumClass): if value == ProtectedEnumClass.ProtectedItem0: return ProtectedEnumClass.ProtectedItem1 return ProtectedEnumClass.ProtectedItem0 + def publicEnumMethod(self, value): + if value == ProtectedEnumClass.PublicItem0: + return ProtectedEnumClass.PublicItem1 + return ProtectedEnumClass.PublicItem0 class ProtectedEnumTest(unittest.TestCase): '''Test cases for protected enum.''' - def testProtectedEnum(self): - '''Original protected method is being called.''' + def testProtectedMethodWithProtectedEnumArgument(self): + '''Calls protected method with protected enum argument.''' obj = ProtectedEnumClass() self.assertEqual(type(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedEnum) @@ -201,8 +205,18 @@ class ProtectedEnumTest(unittest.TestCase): self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0) self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1) - def testProtectedEnumWithMethodOverride(self): - '''Overridden protected method is being called.''' + def testProtectedMethodWithPublicEnumArgument(self): + '''Calls protected method with public enum argument.''' + obj = ProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + def testOverriddenProtectedMethodWithProtectedEnumArgument(self): + '''Calls overridden protected method with protected enum argument.''' obj = ExtendedProtectedEnumClass() self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1) @@ -214,6 +228,20 @@ class ProtectedEnumTest(unittest.TestCase): self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1) self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem0) + def testOverriddenProtectedMethodWithPublicEnumArgument(self): + '''Calls overridden protected method with public enum argument.''' + obj = ExtendedProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0) + + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0) + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0) + + if __name__ == '__main__': unittest.main() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 2a905f234..e53486fcc 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -280,9 +280,9 @@ - // Receives and returns the same protected enum item. +